summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAssam Boudjelthia <assam.boudjelthia@qt.io>2024-05-07 15:57:00 +0300
committerAssam Boudjelthia <assam.boudjelthia@qt.io>2024-05-15 12:34:08 +0300
commitb740cd1f38e8fa08e61cee1d7a19badaff2dd282 (patch)
tree954d3a950159a41d84a3d70e0b69c4a73ac66baf
parent0a48730d0821cf0d2f8ad25934d2498293c3648b (diff)
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. Pick-to: 6.7 Task-number: QTBUG-106907 Change-Id: Ib0f0d6a6fbb3b38f605aadfdcc497067daf90297 Reviewed-by: Tinja Paavoseppä <tinja.paavoseppa@qt.io>
-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 920815fbd8..831b1361ce 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)
@@ -1277,9 +1334,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;
}
@@ -1734,13 +1789,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");
@@ -2738,38 +2787,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;
@@ -2782,8 +2799,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";
@@ -2802,7 +2819,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);
@@ -2817,6 +2834,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;