summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAssam Boudjelthia <assam.boudjelthia@qt.io>2024-05-07 15:57:00 +0300
committerQt Cherry-pick Bot <cherrypick_bot@qt-project.org>2024-05-15 11:54:02 +0000
commitd32f7dc0165489e96dd5e2834b513b289b46d185 (patch)
tree77d8be639ab0422ce74cbacd616f51fe209949e2
parentQDir: replace a QScopedArrayPointer with a QVLA (diff)
downloadqtbase-d32f7dc0165489e96dd5e2834b513b289b46d185.tar.xz
qtbase-d32f7dc0165489e96dd5e2834b513b289b46d185.zip
Android: account for namespace in build.gradle instead of manifest
AGP version 7.4 deprecated the use of "package" attribute in the manifest to specify the unique package name, it's instead been moved to build.gradle file and set using "namespace" property. This patch adds support of that to androiddeployqt. Removing the "package" attribute from the default manifest would break Qt Creator 13 and below because Qt Creator would fail to deploy apps without such attribute in the manifest. For that reason we'll defer removing it until a later version, for example Qt 6.10, to allow some buffer for a Qt Creator that can handle that to be adopted by users to reduce breakage. [ChangeLog][Android] Add support for namespace in build.gradle instead of the package attribute in the manifest. Task-number: QTBUG-106907 Change-Id: Ib0f0d6a6fbb3b38f605aadfdcc497067daf90297 Reviewed-by: Tinja Paavoseppä <tinja.paavoseppa@qt.io> (cherry picked from commit b740cd1f38e8fa08e61cee1d7a19badaff2dd282) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
-rw-r--r--src/android/templates/build.gradle1
-rw-r--r--src/android/templates/doc/src/android-manifest-file-configuration.qdoc2
-rw-r--r--src/tools/androiddeployqt/main.cpp116
3 files changed, 70 insertions, 49 deletions
diff --git a/src/android/templates/build.gradle b/src/android/templates/build.gradle
index f94ffbde54..de37b5ea6b 100644
--- a/src/android/templates/build.gradle
+++ b/src/android/templates/build.gradle
@@ -35,6 +35,7 @@ android {
* Changing them manually might break the compilation!
*******************************************************/
+ namespace androidPackageName
compileSdkVersion androidCompileSdkVersion
buildToolsVersion androidBuildToolsVersion
ndkVersion androidNdkVersion
diff --git a/src/android/templates/doc/src/android-manifest-file-configuration.qdoc b/src/android/templates/doc/src/android-manifest-file-configuration.qdoc
index db0d3c7277..79268f7576 100644
--- a/src/android/templates/doc/src/android-manifest-file-configuration.qdoc
+++ b/src/android/templates/doc/src/android-manifest-file-configuration.qdoc
@@ -50,6 +50,8 @@ Qt sets the following manifest configuration by default:
\li {1, 5} \l {Android: App Manifest <manifest>}{<manifest>}
\li package
\li Sets the package name. The default value is \c {org.qtproject.example.app_name}.
+ \warning This field is deprecated and moved to \c build.gradle. It will be removed
+ in an upcoming release.
\row
\li \c {android:installLocation}
\li Sets the app's installation location, whether internal or external storage.
diff --git a/src/tools/androiddeployqt/main.cpp b/src/tools/androiddeployqt/main.cpp
index e0143f5e4b..d858bce1ce 100644
--- a/src/tools/androiddeployqt/main.cpp
+++ b/src/tools/androiddeployqt/main.cpp
@@ -731,6 +731,53 @@ bool copyFileIfNewer(const QString &sourceFileName,
return true;
}
+struct GradleBuildConfigs {
+ QString appNamespace;
+ bool setsLegacyPackaging = false;
+ bool usesIntegerCompileSdkVersion = false;
+};
+
+GradleBuildConfigs gradleBuildConfigs(const QString &path)
+{
+ GradleBuildConfigs configs;
+
+ QFile file(path);
+ if (!file.open(QIODevice::ReadOnly))
+ return configs;
+
+ auto isComment = [](const QByteArray &trimmed) {
+ return trimmed.startsWith("//") || trimmed.startsWith('*') || trimmed.startsWith("/*");
+ };
+
+ auto extractValue = [](const QByteArray &trimmed) {
+ int idx = trimmed.indexOf('=');
+
+ if (idx == -1)
+ idx = trimmed.indexOf(' ');
+
+ if (idx > -1)
+ return trimmed.mid(idx + 1).trimmed();
+
+ return QByteArray();
+ };
+
+ const auto lines = file.readAll().split('\n');
+ for (const auto &line : lines) {
+ const QByteArray trimmedLine = line.trimmed();
+ if (isComment(trimmedLine))
+ continue;
+ if (trimmedLine.contains("useLegacyPackaging")) {
+ configs.setsLegacyPackaging = true;
+ } else if (trimmedLine.contains("compileSdkVersion androidCompileSdkVersion.toInteger()")) {
+ configs.usesIntegerCompileSdkVersion = true;
+ } else if (trimmedLine.contains("namespace")) {
+ configs.appNamespace = QString::fromUtf8(extractValue(trimmedLine));
+ }
+ }
+
+ return configs;
+}
+
QString cleanPackageName(QString packageName)
{
auto isLegalChar = [] (QChar c) -> bool {
@@ -812,18 +859,28 @@ QString detectLatestAndroidPlatform(const QString &sdkPath)
return latestPlatform.baseName();
}
-QString packageNameFromAndroidManifest(const QString &androidManifestPath)
+QString extractPackageName(Options *options)
{
- QFile androidManifestXml(androidManifestPath);
+ QString packageName;
+ QFile androidManifestXml(options->androidSourceDirectory + "/AndroidManifest.xml"_L1);
if (androidManifestXml.open(QIODevice::ReadOnly)) {
QXmlStreamReader reader(&androidManifestXml);
while (!reader.atEnd()) {
reader.readNext();
if (reader.isStartElement() && reader.name() == "manifest"_L1)
- return cleanPackageName(reader.attributes().value("package"_L1).toString());
+ packageName = reader.attributes().value("package"_L1).toString();
}
}
- return {};
+
+ if (packageName.isEmpty()) {
+ const QString gradleBuildFile = options->androidSourceDirectory + "/build.gradle"_L1;
+ packageName = gradleBuildConfigs(gradleBuildFile).appNamespace;
+ }
+
+ if (packageName.isEmpty() || packageName == "androidPackageName"_L1)
+ packageName = "org.qtproject.example.%1"_L1.arg(options->applicationBinary);
+
+ return cleanPackageName(packageName);
}
bool parseCmakeBoolean(const QJsonValue &value)
@@ -1278,9 +1335,7 @@ bool readInputFile(Options *options)
options->isZstdCompressionEnabled = zstdCompressionFlag.toBool();
}
}
- options->packageName = packageNameFromAndroidManifest(options->androidSourceDirectory + "/AndroidManifest.xml"_L1);
- if (options->packageName.isEmpty())
- options->packageName = cleanPackageName("org.qtproject.example.%1"_L1.arg(options->applicationBinary));
+ options->packageName = extractPackageName(options);
return true;
}
@@ -1735,13 +1790,7 @@ bool updateAndroidManifest(Options &options)
reader.readNext();
if (reader.isStartElement()) {
- if (reader.name() == "manifest"_L1) {
- if (!reader.attributes().hasAttribute("package"_L1)) {
- fprintf(stderr, "Invalid android manifest file: %s\n", qPrintable(androidManifestPath));
- return false;
- }
- options.packageName = reader.attributes().value("package"_L1).toString();
- } else if (reader.name() == "uses-sdk"_L1) {
+ if (reader.name() == "uses-sdk"_L1) {
if (reader.attributes().hasAttribute("android:minSdkVersion"_L1))
if (reader.attributes().value("android:minSdkVersion"_L1).toInt() < 23) {
fprintf(stderr, "Invalid minSdkVersion version, minSdkVersion must be >= 23\n");
@@ -2740,38 +2789,6 @@ void checkAndWarnGradleLongPaths(const QString &outputDirectory)
}
#endif
-struct GradleFlags {
- bool setsLegacyPackaging = false;
- bool usesIntegerCompileSdkVersion = false;
-};
-
-GradleFlags gradleBuildFlags(const QString &path)
-{
- GradleFlags flags;
-
- QFile file(path);
- if (!file.open(QIODevice::ReadOnly))
- return flags;
-
- auto isComment = [](const QByteArray &line) {
- const auto trimmed = line.trimmed();
- return trimmed.startsWith("//") || trimmed.startsWith('*') || trimmed.startsWith("/*");
- };
-
- const auto lines = file.readAll().split('\n');
- for (const auto &line : lines) {
- if (isComment(line))
- continue;
- if (line.contains("useLegacyPackaging")) {
- flags.setsLegacyPackaging = true;
- } else if (line.contains("compileSdkVersion androidCompileSdkVersion.toInteger()")) {
- flags.usesIntegerCompileSdkVersion = true;
- }
- }
-
- return flags;
-}
-
bool buildAndroidProject(const Options &options)
{
GradleProperties localProperties;
@@ -2784,8 +2801,8 @@ bool buildAndroidProject(const Options &options)
GradleProperties gradleProperties = readGradleProperties(gradlePropertiesPath);
const QString gradleBuildFilePath = options.outputDirectory + "build.gradle"_L1;
- GradleFlags gradleFlags = gradleBuildFlags(gradleBuildFilePath);
- if (!gradleFlags.setsLegacyPackaging)
+ GradleBuildConfigs gradleConfigs = gradleBuildConfigs(gradleBuildFilePath);
+ if (!gradleConfigs.setsLegacyPackaging)
gradleProperties["android.bundle.enableUncompressedNativeLibs"] = "false";
gradleProperties["buildDir"] = "build";
@@ -2804,7 +2821,7 @@ bool buildAndroidProject(const Options &options)
QByteArray sdkPlatformVersion;
// Provide the integer version only if build.gradle explicitly converts to Integer,
// to avoid regression to existing projects that build for sdk platform of form android-xx.
- if (gradleFlags.usesIntegerCompileSdkVersion) {
+ if (gradleConfigs.usesIntegerCompileSdkVersion) {
const QByteArray tmp = options.androidPlatform.split(u'-').last().toLocal8Bit();
bool ok;
tmp.toInt(&ok);
@@ -2819,6 +2836,7 @@ bool buildAndroidProject(const Options &options)
if (sdkPlatformVersion.isEmpty())
sdkPlatformVersion = options.androidPlatform.toLocal8Bit();
+ gradleProperties["androidPackageName"] = options.packageName.toLocal8Bit();
gradleProperties["androidCompileSdkVersion"] = sdkPlatformVersion;
gradleProperties["qtMinSdkVersion"] = options.minSdkVersion;
gradleProperties["qtTargetSdkVersion"] = options.targetSdkVersion;