Verwendung des Play Feature Delivery
Was ist die Bereitstellung von Funktionen?
In der Entwicklerdokumentation von Google wird diese Funktion ausführlich beschrieben. Sie ermöglicht es Entwicklern, ihre Projekte so zu strukturieren, dass der Google Play Store den Inhalt ihrer App in mehrere herunterladbare Pakete aufteilen kann. Außerdem haben die Entwickler so die Kontrolle darüber, wie der Inhalt an die Nutzer ausgeliefert wird. Diese aufgeteilten Software- und Inhaltspakete werden über Android App Bundles (AAB) an den Google Play Store geliefert.
Beispielprojekt: FDMapLoader
Diese App nutzt die Play-Feature-Bereitstellung, um einem Benutzer auf Anforderung Bilder zu liefern. Die App kann leicht modifiziert werden, um eine App zu erstellen, die über 200 MB groß ist, um die Größenbeschränkungen der App und den Download mit einem großen Feature Delivery-Modul zu testen.
Build-Setup
- fdwintermapmodule: Feature-Modul-Projekt für Qt Creator
- fdmaploader: Hauptanwendungsprojekt für Qt Creator
- fdmaploader-android-project: Android-Projekt zum Kompilieren des Android-App-Bundles.
FDWintermapModule kompilieren - Funktionsmodul
Laden Sie das fdwintermapmodule-Projekt auf Qt Creator, konfigurieren Sie es für Ihre Zielplattform und erstellen Sie es.
FDMapLoader kompilieren - Hauptanwendung
Laden Sie den fdmaploader nach Qt Creator, konfigurieren Sie ihn für Ihre Zielplattform und erstellen Sie ihn.
Android Projekt modifizieren
- Kopieren Sie die erstellten Binärdateien (.so) aus den Verzeichnissen für die Funktionsmodule und die Hauptanwendung in die entsprechenden Bibliotheksverzeichnisse in einem Android-Projekt. (
app/src/main/jniLibs/[target ABI]/
bzw.fdwintermapmodule/src/main/jniLibs/[target ABI]/
) - Kopieren Sie andere geänderte Dateien, z. B. Ressourcendateien und Java-Klassen. (
.../res/...
und.../src/main/java/...
Verzeichnisse) - Erstellen Sie das Android-Projekt entweder mit Android Studio oder über die Befehlszeile mit dem Gradle-Wrapper (
./gradlew
bundle) - Zum Testen können Sie APKs aus einem Bundle erstellen und eine lokale Testversion mit
bundletool
auf einem Gerät installieren. Bundletool ist ein von Google bereitgestelltes Tool, auf dessen Verwendung wir später in dieser Dokumentation eingehen werden. Zum Testen und Freigeben können Sie das Bundle in die Google Play Console hochladen.
Eigene Inhalte hinzufügen
Dieses Beispiel ist so konzipiert, dass Entwickler problemlos eigene Inhalte hinzufügen können, um die Funktionsbereitstellung zu testen. Um die maximale Paketgröße im Play Store zu überschreiten, können Kartenbilder (es müssen nicht unbedingt Kartenbilder sein, aber es passt zum Thema des Beispiels) zum Ordner images in FDMapLoader und FDWintermapModule hinzugefügt werden, die Bildnamen müssen ebenfalls zur Datei images.qrc
hinzugefügt werden.
Erstellen Sie Ihre eigenen
In den folgenden Abschnitten wird beschrieben, wie Sie Ihr eigenes Projekt erstellen können, das die Play Feature Delivery verwendet. Es wird empfohlen, das Beispiel als Grundlage zu verwenden. In dem Projekt wurde Qt 6.7.2 verwendet.
Feature-Modul
Feature Delivery behandelt C++-Bibliotheken wie normale Shared Libraries, die zur Laufzeit verfügbar sein können oder auch nicht. Vor dem Aufruf einer Bibliothek muss die Verfügbarkeit einer solchen geprüft werden.
- Verwenden Sie Qt Creator, um eine C++ Shared Library zu erstellen.
- Implementieren Sie Funktionen und fügen Sie Ressourcen hinzu.
- Erstellen Sie .so-Binärdateien.
Hauptanwendung (Qt)
- Verwenden Sie Qt Creator, um eine App zu erstellen (Qt Quick Projektvorlage wurde hier verwendet).
- Implementieren Sie den Zugriff auf die Feature Delivery Bibliothek. Die zentrale Klasse in der Google Play Feature Delivery Java Bibliothek ist
SplitInstallManager
. - Android-Vorlagendateien können über die Schaltfläche "Create Templates" im QtCreator Projects -> Build&Run -> [target ABI] -> Build Steps -> Build Android APK erstellt werden. Vorlagen werden im Ordner "android" im Projekt erstellt.
- Fügen Sie Java-Dateien in den Ordner
.../android/src/java/[package...]
und Dateipfade inCMakeLists.txt
ein:qt_add_executable... ...[path]/[java-filename.java] ...
- In diesem Beispiel wurde eine Java-Klasse erstellt, um die Aufrufe und Rückrufe zu verwalten. Auf die Java-Klasse würde dann von Qt aus mit JNI zugegriffen werden. Die Android-Dokumentation enthält eine einfache Beschreibung, wie man ein Modul anfordert.
- Beim Hinzufügen von Java-Dateien unter dem android-Ordner im Projekt muss die Eigenschaft QT_ANDROID_PACKAGE_SOURCE_DIR zur
CMakeLists.txt
hinzugefügt werden:... set_property(TARGET appFDMainApp APPEND PROPERTY QT_ANDROID_PACKAGE_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/android) ...
- Außerdem muss die Hauptanwendung
build.gradle
über Abhängigkeiten für die Feature-API verfügen: Ersetzen Sie im Block dependenciesimplementation 'androidx.core:core:1.13.1'
durch
implementation("com.google.android.play:feature-delivery:2.1.0")
- Implementieren Sie den Zugriff auf die vom Feature-Modul bereitgestellte Bibliothek. Da das Feature-Modul für die Hauptanwendung verfügbar sein kann oder auch nicht, werden die Module nicht zur Erstellungszeit verknüpft und die Aufrufe an das Modul müssen zur Laufzeit aufgelöst werden. Beispiel:
typedef void* (*LoadModuleRulesFunc)(); LoadModuleRulesFunc loadModuleRules = (LoadModuleRulesFunc) mFDModuleLibrary.resolve("loadModuleRules"); if (loadModuleRules) { void* result = loadModuleRules(); QScopedPointer<QString> resultStr{static_cast<QString*>(result)}; }
- Implementieren Sie die Benutzeroberfläche und andere erforderliche Teile der Hauptanwendung.
Funktionsmodul (Qt)
- Verwenden Sie Qt Creator, um eine Anwendung zu erstellen (die Projektvorlage Qt C++ Library wurde verwendet).
- Implementieren Sie die Funktionen, die das Modul bietet.
Android-Projekt (Android)
Die Erstellung eines Projekts zur Erstellung eines Android-App-Bundles für die Bereitstellung von Funktionen basiert hauptsächlich auf der Dokumentation von Android:
Erstellen Sie ein Android-Projekt manuell oder mit Android Studio (unter Verwendung der Vorlage "No Activity"). Das Projekt wird so modifiziert, dass es ein Top-Level-Projekt und zwei Unterprojekte enthält, app
und feature-module
. Die Android Studio-Vorlage erstellt das Unterprojekt app
und feature-module
kann mit der Vorlage File -> New -> New Module hinzugefügt werden.
Das Vorlagenprojekt erfordert mehrere Änderungen:
- Fügen Sie das Feature Delivery Plugin auf der Hauptebene
build.gradle
hinzu:plugins { id 'com.android.application' version '8.5.2' apply false id 'com.android.dynamic-feature' version '8.5.2' apply false id 'com.android.library' version '8.5.2' apply false }
- Fügen Sie das Feature-Modul zur
settings.gradle
hinzu, ändern SierootProject.name
falls erforderlich:... rootProject.name = "name-of-the-root-project" include(:app) include(:name-of-the-feature-module)
app - Unterprojekt
- Das Android-Projekt benötigt Qt-Binärdateien aus dem App-Hauptprojekt:
- Kopieren Sie native Bibliotheken in Qt build:
[build directory]/android-build/libs/[target ABI]
nachapp/src/main/jniLibs/[target ABI]
- Kopieren Sie die Jars in
[build directory]/android-build/libs/
nachapp/libs/
- Kopieren Sie native Bibliotheken in Qt build:
- Aus dem Qt-Build werden auch die Inhalte der Ordner
res
,AndroidManifest.xml
undlocal.properties
an die entsprechenden Stellen im Android-Projekt kopiert. - Fügen Sie die Datei
feature_names.xml
in den Ordnerapp/src/main/res/values
ein, die einen String für das Feature-Modul enthält:<?xml version="1.0" encoding="utf-8"?> <resources> <string name="feature_module_name">name-of-the-feature-module-here</string> </resources>
- Fügen Sie die Datei
keep.xml
zum Ordnerapp/src/main/res/raw
hinzu, die Folgendes enthält:<?xml version="1.0" encoding="utf-8"?> <resources xmlns:tools="http://schemas.android.com/tools" tools:keep="@string/feature_module_winter_map" tools:discard="" />
Änderungen an den Build-Dateien des App-Unterprojekts
Die in das Android-Projekt kopierten Build-Dateien benötigen einige Änderungen.
app - Unterprojekt
build.gradle
- Entfernen Sie die Blöcke
buildScript
undrepositories
. - Der Android-Block im
build.gradle
der Hauptanwendung erfordert einige Änderungen:defaultConfig
packagingOptions
dynamicFeatures
sourceSets
aaptOptions
dependencies
android { ... defaultConfig { ... applicationId "your-project-name-here" ... } packagingOptions.jniLibs.useLegacyPackaging true dynamicFeatures = [":your-dynamic-feature-name-here"] sourceSets { main { manifest.srcFile 'src/main/AndroidManifest.xml' java.srcDirs = [qtAndroidDir + '/src', 'src', 'java'] aidl.srcDirs = [qtAndroidDir + '/src', 'src', 'aidl'] res.srcDirs = [qtAndroidDir + '/res', 'res'] resources.srcDirs = ['resources'] renderscript.srcDirs = ['src'] assets.srcDirs = ['assets'] jniLibs.srcDirs = ['src/main/jniLibs/'] } } // Do not compress Qt binary resources file aaptOptions { noCompress 'rcc' } ... } dependencies { ... implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar']) implementation 'com.google.android.play:feature-delivery:2.1.0' implementation libs.material ... }
Fügen Sie dem Android-Block auch eine Signierkonfiguration hinzu:
android { ... signingConfigs { release { store \code android { ... signingConfigs { release { storeFile file("/absolute/path/to/the/keystore.jks") storePassword "myStorePassword" keyAlias "myKeyAlias" keyPassword "myKeyPassword" } } buildTypes { release { signingConfig signingConfigs.release ... } } ... }
gradle.properties
Qt hat Projektvariablen zu gradle.properties
hinzugefügt. Ändern Sie bei Bedarf den Wert von androidPackageName
.
AndroidManifest.xml
- Entfernen Sie
package
:... <manifest ... android:package... <--remove ... > ...
- Ändern Sie
label
undandroid.app.lib_name
, falls erforderlich:... <application ... android:label=" ... <activity ... > <meta-data android:name="android.app.lib_name" android:value=" ... /> ...
feature-module - Unterprojekt
App- und Feature-Module werden als Unterprojekte für das übergeordnete Android-Projekt erstellt. Die Ordner- und Dateistruktur ist ähnlich wie die des App-Unterprojekts.
- Feature-Modul-Binärdateien aus dem Qt-Build werden in den Ordner
[name-of-feature-module]/src/main/jniLibs/
- Wie in der Haupt-App sollte der Ordner
src/main/res/
die Ordnerxml
undvalues
haben, dieqtprovider_paths.xml
bzw.libs.xml
enthalten. Beide Dateien können aus dem App-Projekt kopiert werden. - Wenn der Ordner
src/main/res/
Drawable- oder Mipmap-Ordner enthält und das Feature diese nicht benötigt, können sie entfernt werden. - Im Feature-Modul sollte
src/main/res/values
nicht das Feldapp_name
enthalten. In einfachen Projekten, in denen strings.xml nicht für andere Zwecke benötigt wird, kann es entfernt werden. libs.xml
enthält nur den Namen des Merkmalsmoduls:... <array name="load_local_libs"> <item>name-of-the-feature-module-here</item> </array> <string name="static_init_classes"></string> <string name="use_local_qt_libs">0</string> <string name="bundle_local_qt_libs">0</string> ...
AndroidManifest.xml
wird dem Verzeichnissrc/main/
hinzugefügt:<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:dist="http://schemas.android.com/apk/distribution"> <dist:module dist:instant="false" dist:title="@string/feature_module_title_string"> <dist:delivery> <dist:on-demand /> </dist:delivery> <dist:fusing dist:include="false" /> </dist:module> <!-- This feature module does contain code. --> <application android:hasCode="true"/> </manifest>
- Das Feature-Modul
build.gradle
ist dem des App-Projekts recht ähnlich, mit einigen Änderungen. Hier ist ein Beispiel aus dem Beispielprojekt:plugins { id 'com.android.dynamic-feature' } dependencies { implementation project(':app') implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar']) implementation 'com.google.android.play:feature-delivery:2.1.0' } android { namespace = androidPackageName compileSdk = androidCompileSdkVersion ndkVersion androidNdkVersion // Extract native libraries from the APK packagingOptions.jniLibs.useLegacyPackaging true defaultConfig { resConfig "en" minSdkVersion qtMinSdkVersion targetSdkVersion qtTargetSdkVersion } sourceSets { main { manifest.srcFile 'src/main/AndroidManifest.xml' resources.srcDirs = ['resources'] renderscript.srcDirs = ['src'] assets.srcDirs = ['assets'] jniLibs.srcDirs = ['src/main/jniLibs/'] } } tasks.withType(JavaCompile) { options.incremental = true } compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } lintOptions { abortOnError false } // Do not compress Qt binary resources file aaptOptions { noCompress 'rcc' } }
gradle.properties
Die Datei kann aus dem app-Unterprojekt kopiert werden, wobei dasandroidPackageName
in das Feature-Modul-Paket geändert wird.
Bauen und Bereitstellen
Das AAB-Bündel kann über die Befehlszeile mit dem gradle-Wrapper erstellt werden: ./gradlew
bundle Das erstellte AAB befindet sich im Ordner build/outputs/bundle/release
(oder debug
). Das AAB kann dann in den Google Play Store kopiert und zum Testen freigegeben werden. Das Testen kann auch lokal durchgeführt werden, indem bundletool
mit dem Parameter --local-testing
verwendet wird. Bundletool-Dokumentation
Verwendete Bundletool-Befehle
- APK:s aus einem Bundle generieren:
bundletool build-apks --bundle=/path/to/bundle.aab --output=/path/to/apk/package.apks --local-testing
- App auf dem Gerät installieren:
bundletool install-apks --apks=/path/to/apk/package.apks
© 2025 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.