プレイ・フィーチャー・デリバリーの使用

フィーチャー・デリバリーとは?

Googleの開発者向けドキュメントには、この機能の詳細が記載されています。基本的に、開発者はGoogle Playストアがアプリのコンテンツを複数のダウンロード可能なパッケージに分割できるように、プロジェクトを構成することができます。また、コンテンツをユーザーに配信する方法を開発者がコントロールできるようになります。これらの分割されたソフトウェアとコンテンツのパッケージは、Android App Bundles(AAB)を使用してGoogle Playストアに配信されます。

プロジェクトの例FDMapLoader

このアプリは、要求されたときにユーザーに画像を提供するために再生機能配信を使用します。このアプリは、アプリのサイズ制限をテストするために200MBを超えるアプリを作成したり、大きなフィーチャーデリバリーモジュールを使用してダウンロードするように簡単に変更できます。

ビルドセットアップ

  • fdwintermapmodule:のFeature Moduleプロジェクト。Qt Creator
  • fdmaploader:のメインアプリプロジェクトQt Creator
  • fdmaploader-android-project:Android App BundleをコンパイルするためのAndroidプロジェクト。

FDWintermapModuleのコンパイル - 機能モジュール

fdwintermapmoduleプロジェクトをQt Creator にロードし、ターゲットプラットフォーム用に設定し、ビルドします。

FDMapLoaderのコンパイル - メインアプリ

fdmaploaderQt Creator にロードし、ターゲット・プラットフォーム用に設定し、ビルドします。

Androidプロジェクトの修正

  • ビルドしたバイナリ(.so)ファイルを、機能モジュールとメインアプリのビルドディレクトリから、Androidプロジェクトの対応するライブラリディレクトリにコピーします。(それぞれapp/src/main/jniLibs/[target ABI]/fdwintermapmodule/src/main/jniLibs/[target ABI]/
  • リソース・ファイルやJavaクラスなど、その他の変更ファイルをコピーする。(.../res/....../src/main/java/... フォルダー)
  • Android Studioを使用するか、Gradleラッパーを使用してコマンドラインからAndroidプロジェクトをビルドする (./gradlew バンドル)
  • テストのために、バンドルからAPKを作成し、bundletool を使用してデバイスにローカルのテストバージョンをインストールすることができます。BundletoolはGoogleが提供するツールで、このドキュメントの後半でその使い方を説明します。テストとリリースのために、Google Play Console にバンドルをアップロードできます。

独自のコンテンツを追加する

この例は、開発者が独自のコンテンツを簡単に追加して Feature Delivery をテストできるように設計されています。Play ストアの最大パッケージサイズを超えるために、マップ画像 (マップ画像である必要はありませんが、この例のテーマに合っています。) を FDMapLoader と FDWintermapModule の images フォルダに追加できます。images.qrc ファイルに画像名を追加する必要があります。

自分で作る

以下のセクションでは、プレイ機能配信を使用する独自のプロジェクトを作成する方法について説明します。例題をベースにすることをお勧めします。このプロジェクトでは、Qt 6.7.2 を使用しています。

機能モジュール

フィーチャーデリバリーは、通常の共有ライブラリーのようにC++ライブラリーを扱います。ライブラリを呼び出す前に、利用可能かどうかをチェックする必要があります。

  • Qt Creator 、C++共有ライブラリを作成する。
  • 機能を実装し、リソースを追加する。
  • ビルドして.soバイナリを作成する。

メインアプリ (Qt)

  • Qt Creator を使ってアプリを作成する(Qt Quick プロジェクトテンプレートを使用)。
  • Feature Deliveryライブラリへのアクセスを実装する。Google Play Feature Delivery Javaライブラリの中心的なクラスは次のとおりです。 SplitInstallManager.
  • Androidのテンプレートファイルは、QtCreatorProjects -> Build&Run -> [target ABI] -> Build Steps -> Build Android APK の「Create Templates」ボタンを使って作成できます。テンプレートは、プロジェクトの 'android' フォルダに作成されます。
  • フォルダ.../android/src/java/[package...] に Java ファイルを追加し、ファイルパスをCMakeLists.txt に追加します:
    qt_add_executable...
    ...[path]/[java-filename.java]
    ...
  • この例では、呼び出しとコールバックを処理するJavaクラスが作成されています。Javaクラスは、JNIを使用してQtからアクセスされます。Androidのドキュメントには、モジュールを要求する方法についての簡単な説明があります。
  • プロジェクトのandroidフォルダの下にJavaファイルを追加する場合、QT_ANDROID_PACKAGE_SOURCE_DIRプロパティをCMakeLists.txt
    ...
    set_property(TARGET appFDMainApp APPEND PROPERTY QT_ANDROID_PACKAGE_SOURCE_DIR
                 ${CMAKE_CURRENT_SOURCE_DIR}/android)
    ...
  • また、メインアプリbuild.gradle 、機能APIの依存関係を持つ必要があります。
    implementation 'androidx.core:core:1.13.1'

    implementation("com.google.android.play:feature-delivery:2.1.0")
  • 機能モジュールが提供するライブラリへのアクセスを実装する。フィーチャー・モジュールはメイン・アプリで利用可能な場合もそうでない場合もあるため、モジュールはビルド時にリンクされず、モジュールへの呼び出しは実行時に解決されなければなりません。例
    typedef void* (*LoadModuleRulesFunc)();
    LoadModuleRulesFunc loadModuleRules =
        (LoadModuleRulesFunc) mFDModuleLibrary.resolve("loadModuleRules");
    if (loadModuleRules) {
        void* result = loadModuleRules();
        QScopedPointer<QString> resultStr{static_cast<QString*>(result)};
    }
  • メインアプリのユーザーインターフェースやその他の必要な部分を実装する。

機能モジュール(Qt)

  • Qt Creator を使用してアプリを作成する(Qt C++ Library プロジェクトのテンプレートを使用)。
  • モジュールが提供する機能を実装する。

Androidプロジェクト(Android)

機能提供のためのAndroidアプリバンドル構築のためのプロジェクト作成は、主にAndroidのドキュメントに基づいています:

手動またはAndroid Studioを使用してAndroidプロジェクトを作成します(「No Activity」テンプレートを使用)。プロジェクトは、トップレベルのプロジェクトと2つのサブプロジェクト、appfeature-module を含むように変更されます。Android Studioテンプレートでは、app サブプロジェクトが作成され、File -> New -> New Module テンプレートを使用してfeature-module を追加できます。

テンプレート・プロジェクトにはいくつかの修正が必要です:

  • メインレベルbuild.gradle に機能配信プラグインを追加します:
    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
    }
  • settings.gradle に機能モジュールを追加し、必要に応じてrootProject.name を変更する:
    ...
    rootProject.name = "name-of-the-root-project"
    include(:app)
    include(:name-of-the-feature-module)

app - サブプロジェクト

  • Android プロジェクトでは、メイン App プロジェクトの Qt バイナリが必要です:
    • Qt build:[build directory]/android-build/libs/[target ABI] にネイティブ・ライブラリをコピーします。app/src/main/jniLibs/[target ABI]
    • [build directory]/android-build/libs/ にある jar を以下にコピーします。app/libs/
  • Qt ビルドから、res フォルダ、AndroidManifest.xmllocal.properties の内容も Android プロジェクトのそれぞれの場所にコピーします。
  • 機能モジュール用の文字列を含むファイルfeature_names.xmlapp/src/main/res/values フォルダーに追加します:
    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <string name="feature_module_name">name-of-the-feature-module-here</string>
    </resources>
  • ファイルkeep.xmlapp/src/main/res/raw フォルダーに追加します:
    <?xml version="1.0" encoding="utf-8"?>
    <resources xmlns:tools="http://schemas.android.com/tools"
        tools:keep="@string/feature_module_winter_map"
        tools:discard="" />

アプリのサブプロジェクトのビルドファイルの修正

Androidプロジェクトにコピーされたビルドファイルには、いくつかの修正が必要です。

app - サブプロジェクト

build.gradle
  • buildScriptrepositories ブロックを削除。
  • メインアプリのbuild.gradle にある Android ブロックは、若干の修正が必要です:
    • 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
...
}

また、アンドロイド・ブロックに署名設定を追加する:

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 はgradle.properties にプロジェクト変数を追加しました。必要に応じてandroidPackageName の値を変更してください。

AndroidManifest.xml
  • package を削除します:
    ...
    <manifest
    ...
      android:package... <--remove
    ...
    >
    ...
  • 必要に応じてlabelandroid.app.lib_name を変更する:
    ...
    <application ...
      android:label=" ...
      <activity ... >
        <meta-data android:name="android.app.lib_name" android:value=" ...
        />
    ...

feature-module - サブプロジェクト

アプリと機能モジュールは、トップレベルのAndroidプロジェクトのサブプロジェクトとして作成されます。フォルダとファイルの構造は、アプリのサブプロジェクトと似ています。

  • Qtビルドの機能モジュール・バイナリは、Qtサブプロジェクトにコピーされます。[name-of-feature-module]/src/main/jniLibs/
  • メイン・アプリと同様に、src/main/res/ フォルダーには、qtprovider_paths.xmllibs.xml をそれぞれ含むxmlvalues フォルダーがあるはずです。どちらのファイルも、アプリ・プロジェクトからコピーできます。
  • src/main/res/ フォルダーに drawable や mipmap のフォルダーがあり、その機能がそれらを必要としない場合は、それらを削除することができます。
  • フィーチャーモジュールのsrc/main/res/values には、app_name フィールドを含めないでください。strings.xmlが他の用途で必要とされない単純なプロジェクトでは、削除することができます。
  • libs.xml には、機能モジュールの名前だけが含まれます:
    ...
        <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 は、 ディレクトリに追加されます:src/main/
    <?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>
  • 機能モジュールbuild.gradle は、appプロジェクトのものとよく似ていますが、若干の変更が加えられています。以下はサンプル・プロジェクトの例です:
    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 ファイルをappサブプロジェクトからコピーし、 をフィーチャー・モジュール・パッケージに変更します。androidPackageName

ビルドとデプロイ

AAB バンドルは、gradle wrapper を使ってコマンドラインからビルドできます:./gradlew bundle 作成された AAB はbuild/outputs/bundle/release (またはdebug) フォルダに入ります。このAABをGoogle Play Storeにコピーし、テスト用にリリースすることができます。--local-testing パラメータを指定してbundletool を使えば、ローカルでテストすることもできます。Bundletool ドキュメント

使用するBundletoolコマンド

  • バンドルから APK:s を生成する:
    bundletool build-apks --bundle=/path/to/bundle.aab --output=/path/to/apk/package.apks --local-testing
  • 端末にアプリをインストールする:
    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.