Verwendung von „Play Feature Delivery“
Beispiele für die Verwendung von Google Play Feature Delivery unter Qt.

Dieses Dokument beschreibt die Funktionalität des „Feature Delivery“-Beispiels. Das Beispiel nutzt Funktionen, die seit Qt 6.11 unterstützt werden.
„Play Feature Delivery“ kann auch mit älteren Qt-Versionen verwendet werden, jedoch erfordert die Erstellung der Anwendung das manuelle Hinzufügen eines Android-Projekts und das Kopieren der Qt-Binärdateien. Eine Anleitung dazu finden Sie im Kapitel „Feature Delivery 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 erhalten Entwickler dadurch die Kontrolle darüber, wie der Inhalt an die Nutzer bereitgestellt wird. Diese aufgeteilten Software- und Inhaltspakete werden mithilfe von Android App Bundles (AAB) an den Google Play Store übermittelt. In der Entwicklerdokumentation von Google wird diese Funktion ausführlich beschrieben.
Beispielprojekt: Feature Delivery Map Loader
Diese einfache App nutzt „Play Feature Delivery“, um einem Nutzer auf Anfrage Bilder bereitzustellen. Die App lässt sich leicht so anpassen, dass eine App mit einer Größe von über 200 MB entsteht, um die Größenbeschränkungen der App zu testen und den Download mithilfe eines großen „Feature Delivery“-Moduls durchzuführen.
Die App
Die Anwendung besteht aus einer verschiebbaren Ansicht und vier Schaltflächen.
- Beim Start sind die Schaltflächen „ Load Map “ und „ Show Map Info “ aktiviert.
- Ein Klick auf die Schaltfläche „ Show Map Info “ zeigt lediglich an, dass keine Informationen verfügbar sind.
- Load Map Löst das Laden des Funktionsmoduls aus:
- Ein Download-Popup wird angezeigt; über dieses Popup kann der Download abgebrochen werden.
- Nach Abschluss des Downloads wird das Popup-Fenster geschlossen und
- Change Map werden die Schaltflächen „ Remove Map “ aktiviert.
- Remove Map Die Schaltfläche fordert die Deinstallation des Feature-Moduls an und deaktiviert dabei die aktivierten Schaltflächen.
- Wenn auf „ Change Map “ geklickt wird, öffnet sich eine Ansicht, in der die angezeigte Karte geändert werden kann. In diesem Beispiel besteht das Feature-Modul aus nur einem Kartenbild mit Wintermotiven.
Einrichtung des Quellordners
- fdwintermapmodule: Feature-Modul
- fdmaploader: Die Hauptanwendung
- fdmaploader/storeloader: JNI-Schnittstelle für die Bereitstellung von Features
Schnittstelle für die Bereitstellung von Features
Der Ordner „ fdmaploader/storeloader “ enthält die Schnittstellenklasse „ PlayStoreLoader “ für die Feature-Delivery-API. Die API ist noch nicht vollständig, enthält jedoch relevante Funktionen zum Laden und Entfernen von Feature-Modulen. Das Laden eines Moduls wird durch einen Aufruf von „ PlayStoreLoader::loadModule “ initiiert. Der Status des Vorgangs kann mithilfe der von „ PlayStoreLoaderHandler “ bereitgestellten Signale überwacht werden. Ein Handle für die Callbacks kann mit der Funktion „ PlayStoreLoader::getHandler “ abgerufen werden. Die Beispiel-API bietet außerdem die Möglichkeit, bereits installierte Module mit der Funktion ` PlayStoreLoader::getInstalledModules ` zu überprüfen, sowie eine Option zum Entfernen installierter Module mit ` PlayStoreLoader::uninstallModules`.
Dieses Beispiel ist so konzipiert, dass Entwickler problemlos eigene Inhalte hinzufügen können, um die Feature-Bereitstellung zu testen. Um die maximale Paketgröße des Play Stores zu überschreiten, können Kartenbilder (es müssen keine Kartenbilder sein, aber sie passen zum Thema des Beispiels) zu den Ordnern „images“ unter fdmaploader und fdwintermapmodule hinzugefügt werden; die Bildnamen müssen zudem in die Datei „ images.qrc “ eingetragen werden.
Hinter den Kulissen
Das API-Modul besteht aus zwei Teilen: der Qt-Schnittstelle (PlayStoreLoader und PlayStoreLoaderHandler) und Java-Klassen, die den Aufruf der Android: Google Split Install-Schnittstellen übernehmen. Die Qt-Schnittstelle fungiert größtenteils als Durchgang für die Java-Klassen. Die Qt-Schnittstelle vereinfacht die API derart, dass beim Laden des Funktionsmoduls die Google-Klassen „ SplitCompat “ und „ SplitInstall “ sowie die entsprechenden Listener automatisch erstellt und freigegeben werden. In diesem Beispiel wurden Teile der APIs weggelassen, wie beispielsweise „ deferredInstall “ und die 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 jeweilige dynamische Bibliothek als dynamisches Feature für das Android-Anwendungsziel hinzu. Dazu muss „QT_ANDROID_GRADLE_MULTI_MODULE“ aktiviert sein. Dies kann entweder als Kompilierungsflag erfolgen oder in der Datei „CMakeLists“ festgelegt werden. Der Ordner, in dem sich der Java-Teil der Schnittstelle befindet, wird mit „ qt_add_android_dynamic_feature_java_source_dir “ zum Build hinzugefügt.
In der Beispiel-App werden Module über die Schnittstelle „ storeloader “ geladen. Die Qt-Funktionen „ 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 der 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 Befehlszeile lässt sich ein lokal testbares AAB-Paket erstellen.
Erstellen Sie ein Build-Verzeichnis auf derselben Ebene wie das Quellverzeichnis und wechseln Sie dorthin:
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=DebugErstellen:
ninja aabTesten
Das erstellte AAB kann lokal getestet werden, indem man den Befehl „ bundletool “ mit dem Parameter „ --local-testing “ verwendet. Android: Bundletool-Dokumentation Der Befehl „bundletool build-apks “ erstellt APK-Dateien, die anschließend mit dem Befehl „ install-apks “ auf einem Gerät oder Emulator installiert werden können.
Verwendete Bundletool-Befehle
APKs aus einem Bundle generieren:
bundletool build-apks --bundle=/path/to/bundle.aab --output=/path/to/apk/package.apks --local-testingApp auf dem Gerät installieren:
bundletool install-apks --apks=/path/to/apk/package.apksVeröffentlichung im Play Store
Um das erstellte AAB-Paket in den Google Play Store hochladen zu können, muss das Paket signiert werden. Dazu kann „ jarsigner “ verwendet werden. Nachfolgend finden Sie 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]Bereitstellung von Funktionen in Versionen vor Qt 6.11
Versionen vor Qt 6.11 unterstützen keine Erstellung von Paketen, die mit dem Google Play Store kompatibel sind. Wenn Sie keine Qt-Version 6.11 oder höher verwenden können, gibt es eine Möglichkeit, Google Play Feature Delivery zu nutzen; dies erfordert jedoch die manuelle Erstellung des Android-Projekts und das Kopieren der Qt-Binärdateien in dieses Projekt. Im weiteren Verlauf dieses Dokuments finden Sie Anweisungen, wie Sie dies bewerkstelligen können. Die Anweisungen sind möglicherweise nicht für alle Umgebungen eins zu eins übertragbar, sollten Ihnen jedoch gute Hinweise für eine erfolgreiche Implementierung von „Feature Delivery“ 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 C++-Shared-Library zu erstellen.
- Implementieren Sie Funktionen und fügen Sie Ressourcen hinzu.
- Führen Sie den Build durch, um .so-Binärdateien zu erstellen.
Feature Delivery behandelt C++-Bibliotheken wie normale gemeinsam genutzte Bibliotheken, die zur Laufzeit verfügbar sein können oder auch nicht. Vor dem Aufruf einer Bibliothek muss deren Verfügbarkeit überprüft werden.
Hauptanwendung (Qt)
- Verwenden Sie „ Qt Creator “, um eine App zu erstellen (hier wurde die Projektvorlage „Qt Quick “ verwendet).
- Implementieren Sie den Zugriff auf die Feature-Delivery-Bibliothek. Die zentrale Klasse in der Java-Bibliothek von Google Play Feature Delivery ist „Android: SplitInstallManager“.
- Android-Vorlagendateien können über die Schaltfläche „Create Templates“ in QtCreator erstellt werden: Projects -> Build&Run -> [target ABI] -> Build Steps -> Build Android APK. Die Vorlagen werden im Ordner „android“ des Projekts erstellt.
- Fügen Sie Java-Dateien zum Ordner „
.../android/src/java/[package...]“ hinzu und geben Sie die Dateipfade unter „CMakeLists.txt“ an:qt_add_executable... ...[path]/[java-filename.java] ... - Im Beispiel wurde eine Java-Klasse erstellt, um die Aufrufe und Rückrufe zu verarbeiten. Auf diese Java-Klasse wird dann von Qt aus über JNI zugegriffen. Der Abschnitt „Android: Anfordern eines On-Demand-Moduls“ in der Android-Dokumentation enthält eine einfache Beschreibung, wie ein Modul angefordert wird.
- Beim Hinzufügen von Java-Dateien im Ordner „android“ des Projekts muss die Eigenschaft „QT_ANDROID_PACKAGE_SOURCE_DIR“ in die Datei „
CMakeLists.txt“ aufgenommen werden:... set_property(TARGET appFDMainApp APPEND PROPERTY QT_ANDROID_PACKAGE_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/android) ... - Außerdem muss die Haupt-App „
build.gradle“ Abhängigkeiten für die Feature-API enthalten: Ersetzen Sie im Abhängigkeitsblock „“implementation '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 der Haupt-App möglicherweise zur Verfügung steht oder auch nicht, werden Module nicht zur Erstellungszeit verknüpft, und Aufrufe an das Modul müssen zur Laufzeit aufgelöst werden. Beispiel:
- Implementieren Sie die Benutzeroberfläche und andere erforderliche Teile der Hauptanwendung.
QString MapLoader::loadMapInfo()
{
QScopedPointer<QString> resultStr;
typedef void* (*LoadMapInfoFunc)();
// Prüfen, ob die Wintermap-Bibliothek vorhanden ist
mWintermapLibrary.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();
}Funktionsmodul (Qt)
- Verwenden Sie „ Qt Creator “, um eine App zu erstellen (es wurde die Projektvorlage „Qt C++ Library“ verwendet).
- Implementieren Sie die Funktionen, die das Modul bietet.
Android-Projekt (Android)
Die Erstellung eines Projekts zum Erstellen eines Android-App-Bundles für Feature Delivery basiert auf der Android-Dokumentation, insbesondere auf folgenden Dokumenten:
Erstellen Sie ein Android-Projekt manuell oder mithilfe von Android Studio (unter Verwendung der Vorlage „No Activity“). Das Projekt wird so angepasst, dass es ein Projekt auf oberster Ebene und zwei Unterprojekte enthält: „ app “ und „ feature-module “. Die Android Studio-Vorlage erstellt das Unterprojekt „ app “, und das Unterprojekt „ feature-module “ kann mithilfe der Vorlage „ File -> New -> New Module “ hinzugefügt werden.
Das Vorlagenprojekt erfordert einige Anpassungen:
- Fügen Sie das „Feature Delivery“-Plugin auf der Hauptebene unter „
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 und ändern Sie gegebenenfalls „rootProject.name“:... 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 Haupt-App-Projekt:
- Kopiere die nativen Bibliotheken aus dem Qt-Build:
[build directory]/android-build/libs/[target ABI]nachapp/src/main/jniLibs/[target ABI] - Kopieren Sie die JAR-Dateien aus „
[build directory]/android-build/libs/“ nachapp/libs/
- Kopiere die nativen Bibliotheken aus dem Qt-Build:
- Aus dem Qt-Build werden außerdem die Inhalte des Ordners „
res“, „AndroidManifest.xml“ sowie „local.properties“ an die entsprechenden Speicherorte im Android-Projekt kopiert. - Fügen Sie die Datei „
feature_names.xml“ zum Ordner „app/src/main/res/values“ hinzu, die eine Zeichenfolge 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 Ordner „app/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-Teilprojekts
Die in das Android-Projekt kopierten Build-Dateien müssen leicht angepasst werden.
app – Unterprojekt
- Entfernen Sie die Blöcke „
buildScript“ und „repositories“. - Der Android-Block im „
build.gradle“-Block der Haupt-App erfordert einige Anpassungen: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 außerdem die Signaturkonfiguration zum Android-Block 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 unter „ gradle.properties “ hinzugefügt. Ändern Sie bei Bedarf den Wert von „ androidPackageName “.
- Entfernen Sie „
package“:... <manifest ... android:package... <--remove ... > ... - Ändern Sie bei Bedarf „
label“ und „android.app.lib_name“:... <application ... android:label=" ... <activity ... > <meta-data android:name="android.app.lib_name" android:value=" ... /> ...
Feature-Modul – Unterprojekt
App- und Feature-Module werden als Unterprojekte des obersten Android-Projekts angelegt. Die Ordner- und Dateistruktur ähnelt der des App-Unterprojekts.
- Die Binärdateien des Feature-Moduls 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 Ordner „xml“ und „values“ enthalten, die wiederum die Dateien „qtprovider_paths.xml“ bzw. „libs.xml“ enthalten. Beide Dateien können aus dem App-Projekt kopiert werden. - Wenn der Ordner „
src/main/res/“ Ordner „drawable“ oder „mipmap“ enthält, die für die Funktion nicht benötigt werden, können diese entfernt werden. - Im Feature-Modul sollte „
src/main/res/values“ kein Feld „app_name“ enthalten. In einfachen Projekten, in denen „strings.xml“ für keine anderen Zwecke benötigt wird, kann es entfernt werden. libs.xmlenthält nur den Namen des Feature-Moduls:... <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 Verzeichnis „src/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“ ähnelt stark dem des App-Projekts, weist jedoch einige Änderungen auf. Hier 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 { 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/'] } } compileOptions { sourceCompatibility JavaVersion.VERSION_17 targetCompatibility JavaVersion.VERSION_17 } // Do not compress Qt binary resources file aaptOptions { noCompress 'rcc' } } gradle.propertiesDie Datei kann aus dem App-Unterprojekt kopiert werden; ändern Sie dabei „androidPackageName“ in das Paket des Feature-Moduls.
Erstellung und Bereitstellung
Das AAB-Bundle 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 anschließend in den Google Play Store kopiert und zum Testen veröffentlicht werden. Das Testen kann auch lokal erfolgen, 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.