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 407a10c8920..d899e4675f0 100644 --- a/src/android/templates/doc/src/android-manifest-file-configuration.qdoc +++ b/src/android/templates/doc/src/android-manifest-file-configuration.qdoc @@ -246,6 +246,17 @@ the actual values: able to include the correct permissions. So some functionalities might not work properly. +\section3 Customizing Permissions + +Since Qt 6.8.1, it is possible to override the default permissions set +by Qt modules. This is useful if you need to define the same permissions +as used by a Qt module, but with additional or different attributes. + +To achieve this, you can manually define these permissions in the Android +manifest file, along with the \c {} placeholder. +Manually defined permissions take precedence over the same permissions added +by Qt modules, avoiding duplication. + \section2 Style Extraction Qt uses different methods to determine how Qt Widgets and Qt Quick Controls diff --git a/src/corelib/kernel/qpermissions.cpp b/src/corelib/kernel/qpermissions.cpp index 6d295970550..bfe8087d969 100644 --- a/src/corelib/kernel/qpermissions.cpp +++ b/src/corelib/kernel/qpermissions.cpp @@ -382,6 +382,8 @@ QT_PERMISSION_IMPL_COMMON(QMicrophonePermission) \l {QLocationPermission::Precise}{precise location}) and ensure that \c {BLUETOOTH_SCAN} permission doesn't have the \c {android:usesPermissionFlags="neverForLocation"} attribute set. + For setting and customizing permissions in the application manifest, + \l {Qt Permissions and Features}{see this guide}. \include permissions.qdocinc permission-metadata */ diff --git a/src/tools/androiddeployqt/main.cpp b/src/tools/androiddeployqt/main.cpp index 6567b0dac0d..08bd4ccdf3f 100644 --- a/src/tools/androiddeployqt/main.cpp +++ b/src/tools/androiddeployqt/main.cpp @@ -1855,6 +1855,21 @@ bool updateAndroidManifest(Options &options) replacements[QStringLiteral("-- %%INSERT_VERSION_CODE%% --")] = options.versionCode; replacements[QStringLiteral("package=\"org.qtproject.example\"")] = "package=\"%1\""_L1.arg(options.packageName); + const QString androidManifestPath = options.outputDirectory + "/AndroidManifest.xml"_L1; + QFile androidManifestXml(androidManifestPath); + // User may have manually defined permissions in the AndroidManifest.xml + // Read these permissions in order to remove any duplicates, as otherwise the + // application build would fail. + if (androidManifestXml.exists() && androidManifestXml.open(QIODevice::ReadOnly)) { + QXmlStreamReader reader(&androidManifestXml); + while (!reader.atEnd()) { + reader.readNext(); + if (reader.isStartElement() && reader.name() == "uses-permission"_L1) + options.permissions.remove(QString(reader.attributes().value("android:name"_L1))); + } + androidManifestXml.close(); + } + QString permissions; for (auto [name, extras] : options.permissions.asKeyValueRange()) permissions += " \n"_L1.arg(name).arg(extras); @@ -1868,13 +1883,11 @@ bool updateAndroidManifest(Options &options) replacements[QStringLiteral("")] = features.trimmed(); - QString androidManifestPath = options.outputDirectory + "/AndroidManifest.xml"_L1; if (!updateFile(androidManifestPath, replacements)) return false; // read the package, min & target sdk API levels from manifest file. bool checkOldAndroidLabelString = false; - QFile androidManifestXml(androidManifestPath); if (androidManifestXml.exists()) { if (!androidManifestXml.open(QIODevice::ReadOnly)) { fprintf(stderr, "Cannot open %s for reading.\n", qPrintable(androidManifestPath));