Verwendung des Play Feature Delivery
Zeigt die Verwendung von Google Play Feature Delivery auf Qt.

Dieses Dokument beschreibt die Funktionalität des Feature Delivery Beispiels. Das Beispiel verwendet Funktionen, die seit Qt 6.11 unterstützt werden.
Play Feature Delivery kann auch auf älteren Qt-Versionen verwendet werden, aber die Erstellung der Anwendung erfordert das manuelle Hinzufügen des Android-Projekts und das Kopieren der Qt-Binärdateien. Eine Anleitung dazu finden Sie im Kapitel Feature Delivery auf Vor-Qt 6.11.
Was ist Feature Delivery?
Play Feature Delivery ist eine von Google angebotene Funktion, die es Entwicklern im Wesentlichen ermöglicht, 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 die Inhalte an die Nutzer geliefert werden. Diese aufgeteilten Software- und Inhaltspakete werden über Android App Bundles (AAB) an den Google Play Store geliefert. In der Entwicklerdokumentation von Google wird diese Funktion ausführlich beschrieben.
Beispielprojekt: Feature Delivery Map Loader
Diese einfache App verwendet Play Feature Delivery, um einem Nutzer auf Anfrage Bilder zu liefern. Die App kann leicht modifiziert werden, um eine App zu erstellen, die mehr als 200 MB groß ist, um die Größenbeschränkungen der App und den Download mit einem großen Feature Delivery-Modul zu testen.
Die App
Die Anwendung besteht aus einer verschiebbaren Ansicht und vier Schaltflächen.
- Beim Starten sind die Schaltflächen Load Map und Show Map Info aktiviert.
- Beim Anklicken der Schaltfläche Show Map Info wird lediglich angezeigt, dass keine Informationen verfügbar sind.
- Load Map initiiert das Laden des Funktionsmoduls:
- Es wird ein Download-Pop-up angezeigt, in dem der Download abgebrochen werden kann.
- Wenn der Download abgeschlossen ist, wird das Popup-Fenster entfernt und die Schaltflächen
- Change Map und die Schaltflächen Remove Map sind aktiviert.
- Remove Map Schaltfläche fordert die Deinstallation des Funktionsmoduls an, wodurch die aktivierten Schaltflächen deaktiviert werden.
- Wenn Change Map angeklickt wird, öffnet sich eine Ansicht, in der eine angezeigte Karte geändert werden kann. In diesem Beispiel besteht das Funktionsmodul nur aus einem Kartenbild mit Wintermotiven.
Einrichtung des Quellordners
- fdwintermapmodule: Feature-Modul
- fdmaploader: Die Hauptanwendung
- fdmaploader/storeloader: Feature Delivery JNI-Schnittstelle
Feature Delivery-Schnittstelle
Der Ordner fdmaploader/storeloader enthält die Schnittstellenklasse PlayStoreLoader für die Feature Delivery API. Die API ist nicht vollständig, enthält aber relevante Funktionen zum Laden und Entfernen von Feature-Modulen. Das Laden von Modulen wird mit einem Aufruf an PlayStoreLoader::loadModule eingeleitet. Der Status des Prozesses kann mit Signalen überwacht werden, die von PlayStoreLoaderHandler bereitgestellt werden. Ein Handle auf die Callbacks kann mit der Funktion PlayStoreLoader::getHandler erhalten werden. Die Beispiel-API bietet auch eine Möglichkeit zur Überprüfung bereits installierter Module mit der Funktion PlayStoreLoader::getInstalledModules und eine Option zum Entfernen installierter Module mit PlayStoreLoader::uninstallModules.
Dieses Beispiel ist so konzipiert, dass ein Entwickler leicht eigene Inhalte hinzufügen kann, 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) zu den Bilderordnern in fdmaploader und fdwintermapmodule hinzugefügt werden, die Bildnamen müssen auch zur Datei images.qrc hinzugefügt werden.
Unter der Haube
Das API-Modul besteht aus zwei Teilen. Qt-Schnittstelle (PlayStoreLoader und PlayStoreLoaderHandler) und Java-Klassen, die für den Aufruf von Android zuständig sind: Google Split Install Interfaces. Die Qt-Schnittstelle dient hauptsächlich als Durchleitung für die Java-Klassen. Die Qt-Schnittstelle vereinfacht die API, so dass beim Laden des Feature-Moduls die Google SplitCompat und SplitInstall Klassen und Listener automatisch erstellt und freigegeben werden. In diesem Beispiel werden Teile der APIs weggelassen, wie deferredInstall und Sprachunterstützung.
Qt creates and builds package suitable for Google Play deployment using qt6_add_android_dynamic_features when it is defined CMakeLists.
qt6_add_android_dynamic_features(${target_name}
FEATURE_TARGETS fdwintermapmodule)Die CMake-Funktion qt6_add_android_dynamic_features fügt die spezifische dynamische Bibliothek als dynamisches Merkmal für das Android-Anwendungsziel hinzu. Dazu muss das Merkmal QT_USE_ANDROID_MODERN_BUNDLE aktiviert sein. Dies kann entweder als Flag zur Kompilierzeit oder in CMakeLists gesetzt werden. Der Ordner, in dem sich der Java-Teil der Schnittstelle befindet, wird dem Build mit qt_add_android_dynamic_feature_java_source_dir hinzugefügt.
In der Beispielanwendung werden die Module über die Schnittstelle storeloader geladen. Die Funktionen von Qt PlayStoreLoader und die Klasse PlayStoreLoaderHandler fungieren als Vermittler zwischen dem Beispielcode und Java.
void PlayStoreLoader::loadModule(const QString & callId, const QString &moduleName) { if (callId.isEmpty() || moduleName.isEmpty()) return; if (!loaderInstance->registerNatives()) return; if (!loaderInstance->loader().isValid()) { qCritical("StoreLoader not constructed"); return; } loaderInstance->loader().callMethod<void>("installModuleFromStore", moduleName, callId); }
Java-Klassen verarbeiten Aufrufe an die Split Install API.
m_splitInstallManager.startInstall(request)
.addOnSuccessListener(sessionId -> {
PlayStoreLoaderListener listener = m_listeners.get(callId);
if (listener != null)
listener.setSessionId(sessionId);
})Erstellen von Binärdateien
Über die Kommandozeile kann ein lokal testbares AAB-Paket erstellt werden.
Erstellen Sie ein Build-Verzeichnis auf der gleichen Ebene wie das Quellverzeichnis und geben Sie es ein:
mkdir build-feature-delivery/ ; cd build-feature-delivery/
Konfigurieren:
path-to-qt-version/path-to-abi/bin/qt-cmake -GNinja -B . -S ../feature-delivery/ -DQT_USE_TARGET_ANDROID_BUILD_DIR=ON -DCMAKE_BUILD_TYPE=Debug
Bauen:
ninja aab
Prüfung
Das erstellte AAB kann lokal getestet werden, indem bundletool mit dem Parameter --local-testing verwendet wird. Android: Bundletool Dokumentation Der Befehl bundletool build-apks erstellt eine apks-Datei, die dann mit dem Befehl install-apks auf einem Gerät oder Emulator installiert werden kann.
Verwendete Bundletool-Befehle
Erzeugen von APK:s aus einem Bundle:
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
Übergabe an den Play Store
Um das erstellte AAB-Paket in den Google Play Store hochladen zu können, muss das Paket signiert werden. Hierfür kann jarsigner verwendet werden. Unten ist ein Beispiel für einen jarsigner-Befehl zum Signieren des AAB-Pakets. Siehe Android: Jarsigner-Dokumentation
jarsigner -verbose -sigalg SHA256withRSA -digestalg SHA-256 -keystore [path-to-keystore-file].keystore [path-to-aab-file].aab [alias]
Feature-Auslieferung vor Qt 6.11
Versionen vor Qt 6.11 unterstützen keine Google Play Store kompatible Paketerstellung. Wenn Sie nicht in der Lage sind, eine Qt-Version 6.11 oder höher zu verwenden, gibt es eine Möglichkeit, Google Play Feature Delivery zu nutzen, aber es erfordert die manuelle Erstellung des Android-Projekts und das Kopieren der Qt-Binärdateien in dieses Projekt. Der Rest des Dokuments enthält Anweisungen, wie man das erreicht. Die Anweisungen sind möglicherweise nicht 1 zu 1 kompatibel für alle Umgebungen, sollten aber gute Hinweise für eine erfolgreiche Feature Delivery-Implementierung geben. Es wird empfohlen, das Beispiel als Grundlage zu verwenden.
Feature-Modul
Feature-Module werden wie normale Bibliotheken erstellt.
- Verwenden Sie Qt Creator, um eine gemeinsame C++-Bibliothek zu erstellen.
- Implementieren Sie Features und fügen Sie Ressourcen hinzu.
- Bauen Sie, um .so-Binärdateien zu erstellen.
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 Bibliothek geprüft werden.
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 Android: 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 zum Ordner
.../android/src/java/[package...]und Dateipfade zuCMakeLists.txt:hinzuqt_add_executable... ...[path]/[java-filename.java] ...
- . Im Beispiel wurde eine Java-Klasse erstellt, um die Aufrufe und Rückrufe zu behandeln. Auf die Java-Klasse würde dann von Qt aus mit JNI zugegriffen werden. Android: Request an on demand module section in the Android documentation has a simple description of how to request a module.
- When adding Java files under the android folder in the project, QT_ANDROID_PACKAGE_SOURCE_DIR property must be added to the
CMakeLists.txt: ... set_property(TARGET appFDMainApp APPEND PROPERTY QT_ANDROID_PACKAGE_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/android) ...
- Außerdem muss die Hauptanwendung
build.gradleAbhängigkeiten für die Feature-API haben: in the dependencies block, replaceimplementation 'androidx.core:core:1.13.1'with
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 verlinkt und die Aufrufe an das Modul müssen zur Laufzeit aufgelöst werden. Beispiel:
QString MapLoader::loadMapInfo() { QScopedPointer<QString> resultStr; typedef void*(*LoadMapInfoFunc)(); //Finden, ob Wintermap-Bibliothek existiertmWintermapLibrary.setFileName("fdwintermapmodule"); if (!mWintermapLibrary.load()) { qWarning() << Q_FUNC_INFO << "Failed to load library"; return QString(); } LoadMapInfoFunc loadMapInfo = (LoadMapInfoFunc) mWintermapLibrary.resolve("loadMapInfo"); if (loadMapInfo) { void* result = loadMapInfo(); resultStr.reset(static_cast<QString*>(result)); } else qWarning() << Q_FUNC_INFO << "Function loadMapInfo not loaded"; return *resultStr.data(); }
- 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 Feature Delivery 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.gradlehinzu: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.gradlehinzu, ändern SierootProject.namefalls 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 die nativen 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 die nativen Bibliotheken in Qt build:
- Aus dem Qt-Build werden auch die Inhalte der Ordner
res,AndroidManifest.xmlundlocal.propertiesan die entsprechenden Stellen im Android-Projekt kopiert. - Fügen Sie die Datei
feature_names.xmlzum Ordnerapp/src/main/res/valueshinzu, 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.xmlzum Ordnerapp/src/main/res/rawhinzu, 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
- Entfernen Sie die Blöcke
buildScriptundrepositories. - Der Android-Block in der Haupt-App
build.gradleerfordert einige Änderungen:defaultConfigpackagingOptionsdynamicFeaturessourceSetsaaptOptionsdependencies
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 {
storeFile file("/absolute/path/to/the/keystore.jks")
storePassword "myStorePassword"
keyAlias "myKeyAlias"
keyPassword "myKeyPassword"
}
}
buildTypes {
release {
signingConfig signingConfigs.release
...
}
}
...
}Qt hat Projektvariablen zu gradle.properties hinzugefügt. Ändern Sie bei Bedarf den Wert von androidPackageName.
- Entfernen Sie
package:... <manifest ... android:package... <--remove ... > ...
- Ändern Sie
labelundandroid.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 Ordnerxmlundvalueshaben, dieqtprovider_paths.xmlbzw.libs.xmlenthalten. 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/valuesnicht das Feldapp_nameenthalten. In einfachen Projekten, in denen strings.xml nicht für andere Zwecke benötigt wird, kann es entfernt werden. libs.xmlenthä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.xmlwird 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.gradleist dem des App-Projekts recht ähnlich, mit einigen Änderungen. Hier ist ein Beispiel: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.propertiesDie Datei kann aus dem app-Unterprojekt kopiert werden, wobei dasandroidPackageNamein 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.
© 2026 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.