Google は、黒人コミュニティに対する人種平等の促進に取り組んでいます。取り組みを見る

Play Feature Delivery の概要

Google Play のアプリ配信モデルでは、Android App Bundle を使用して、個々のユーザーのデバイス設定に合わせて最適化した APK を生成、配信します。それにより、各ユーザーは、アプリの実行に必要なコードとリソースのみダウンロードできます。

Play Feature Delivery では、App Bundle の高度な機能を使用して、アプリの特定の機能を条件付きで配信、またはオンデマンドでダウンロードできます。

機能モジュールをカスタム配信に使用する

機能モジュールに固有のメリットをもたらすのは、Android 5.0(API レベル 21)以降を搭載するデバイスに、アプリのさまざまな機能をダウンロードする方法とタイミングをカスタマイズできる機能です。たとえば、アプリの初回ダウンロード サイズを削減するために、一部の機能を必要に応じてオンデマンドでダウンロードするか、特定の機能(写真の撮影機能、拡張現実のサポート機能など)を持つデバイスにのみダウンロードするように構成できます。

アプリを App Bundle としてアップロードすると、デフォルトで高度に最適化されたダウンロードが可能になりますが、さらに高度かつカスタマイズ可能な機能の配信方法では、「機能モジュール」を使用するアプリの機能について追加の構成とモジュール化が必要になります。つまり、機能モジュールは、必要に応じたダウンロードの構成が可能なモジュール式機能を作成するための構成要素を提供するものです。

オンライン ショップでユーザーが商品を売買できるようにするアプリについて考えます。アプリの以下の機能は、それぞれ個別の機能モジュールに合理的にモジュール化できます。

  • アカウントのログインと作成
  • ショップのブラウジング
  • 販売する商品の配置
  • 支払いの処理

機能モジュールがサポートするさまざまな配信方法と、その方法を使用して、ショップのサンプルアプリの初回ダウンロード サイズの最適化を行う方法を、以下の表に示します。

配信方法 動作 使用事例 スタートガイド
インストール時の配信 上記の配信方法のいずれも構成しない機能モジュールが、デフォルトでアプリのインストール時にダウンロードされます。これは、高度な配信方法を徐々に採用できることを意味するため重要な動作です。たとえば、Play のコアライブラリを使用したオンデマンド ダウンロードを完全に実装した後でのみ、アプリ機能のモジュール化を活用して、オンデマンド配信を有効にできます。

さらに、アプリは後で機能のアンインストールをリクエストできます。 それにより、アプリのインストール時に必要な特定の機能がその後で不要になった場合に、デバイスからその機能を削除するようリクエストできるようにすることで、インストール サイズを削減できます。

ショップでの商品の売買方法に関するインタラクティブ ガイドのような特定のトレーニング アクティビティがアプリにある場合は、アプリのインストール時にデフォルトでその機能を含めることができます。

一方、アプリのインストール サイズを削減するために、ユーザーがトレーニングを完了した後で、アプリは機能の削除をリクエストできます。

高度な配信方法を構成しない機能モジュールを使用して、アプリをモジュール化します。

ユーザーにとって不要になった特定の機能モジュールを削除することで、アプリのインストール サイズを削減する方法については、インストールしたモジュールを管理するをご覧ください。

オンデマンド配信 必要に応じて機能モジュールをリクエスト、ダウンロードすることをアプリに許可します。 ショップアプリを使用するユーザーのうち、販売する商品を投稿するのが 20% のみである場合、大多数のユーザーにおける初回ダウンロード サイズを削減するおすすめの戦略は、写真の撮影、商品の説明の指定、および販売する商品の配置の各機能をオンデマンド ダウンロードとして利用可能にすることです。つまり、アプリの販売機能の機能モジュールは、ユーザーが販売する商品をショップに配置することに関心を示したときにのみ、ダウンロードされるように構成できます。

さらに、一定期間ユーザーが商品を販売しなかった場合、アプリは販売機能のアンインストールをリクエストすることで、インストール済みのサイズを削減できます。

機能モジュールを作成して、オンデマンド配信を構成します。その後、アプリは Play のコアライブラリを使用して、オンデマンドでモジュールをダウンロードするようリクエストできます。
条件付き配信 ハードウェアの機能、言語、地域、最小 API レベルなど、特定のユーザー デバイス要件を指定することで、モジュール化した機能をダウンロードするかどうかを、アプリのインストール時に判断可能にすることができます。 ショップアプリがグローバル ユーザーを対象とする場合、一部の地域や言語でのみ頻繁に使用される支払い方法のサポートが必要になることがあります。アプリの初回ダウンロード サイズを削減するために、特定のタイプの支払い方法を処理する機能モジュールを個別に作成して、ユーザーのデバイスに、登録されている言語や地域に基づく条件付きでインストールされるようにできます。 機能モジュールを作成して、条件付き配信を構成します。
Instant 配信 Google Play Instant を使用すると、デバイスに APK をインストールしなくても、ユーザーがアプリを利用できるようになります。インストールする代わりに、ユーザーは Google Play ストアの [今すぐ試す] ボタン、またはデベロッパーが作成した URL を使用してアプリを利用できます。このコンテンツ配信形式を使用すると、Android アプリのユーザー エンゲージメントを高めるのが容易になります。

Instant 配信により Google Play Instant を活用すると、インストールしなくてもアプリの一部の機能をユーザーがすぐに試せるようになります。

ゲームの最初の数レベルを軽量の機能モジュールに含めることを検討します。そのモジュールで Instant に対応すると、ユーザーはアプリをインストールしなくても、URL リンクまたは [今すぐ試す] ボタンからすぐにゲームを体験できます。 機能モジュールを作成し、Instant 配信を構成します。その後、アプリは Play のコアライブラリを使用して、オンデマンドでモジュールをダウンロードするようリクエストできます。

機能モジュールを使用したアプリ機能のモジュール化は最初のステップにすぎません。Google Play Instant をサポートするには、アプリのベース モジュールと Instant 対応にした特定の機能のダウンロード サイズが厳しいサイズ要件を満たす必要があります。詳しくは、アプリまたはゲームのサイズを削減して Instant 機能を有効にするをご覧ください。

アプリをモジュール化する

アプリのモジュール化とは、アプリ プロジェクトの論理コンポーネントを個別のモジュールに分割するプロセスのことです。

アプリの各機能を個別のコンポーネントに再編成するには、綿密な検討を行い時間を確保する必要があります。それでもモジュール化によって、プロジェクトには以下の利点がもたらされます。

  • 並行して開発: アプリの論理コンポーネントをモジュールに分割することで、各モジュールを組織内の異なるチームまたは個人に所有、担当させ、他のチームとの統合時における競合や障害を減らすことができます。さらに、アプリのさまざまな部分で使用されるロジックがある場合は、ライブラリ モジュールを使用して、コードの再利用とカプセル化を促すことができます。
  • ビルド時間に関する改善: Gradle を使用する Android Studio などのビルドシステムは、モジュールとして編成されているプロジェクトを対象として最適化されています。たとえば、Gradle のプロジェクトの並列実行による最適化を、マルチコア プロセッサが搭載されたワークステーションで有効にする場合、ビルドシステムは複数のモジュールを並行してビルドし、ビルドの所要時間を大幅に削減できます。プロジェクトのモジュール化が進むほど、ビルドのパフォーマンスが大幅に向上します。
  • 機能の配信のカスタマイズ: アプリの機能を機能モジュールとしてモジュール化することは、Play Feature Delivery のカスタム配信方法(オンデマンド配信、条件付き配信、Instant 配信など)を活用するための要件です。オンデマンドの機能を作成するには、さらに労力をかけ、アプリで可能なリファクタリングを進める必要があります。そのため、どのアプリの機能を機能モジュールにモジュール化すればカスタム配信方法のメリットが最大になるかを、慎重に検討してください。

アプリの機能ごとにプロジェクトをモジュール化するには、時間をかけて、適切な方法を検討する必要があります。アプリのモジュール化を始めることを決断したら、まず、モジュール式機能をサポートするのに必要なプロパティを指定して、ベース モジュールを構成する必要があります。その後で、インストール時配信用に機能モジュールを構成することで、アプリの現在の動作を変えずにアプリの機能を徐々にモジュール化できます。

機能モジュールのマニフェスト

Android Studio を使用して新しい機能モジュールを作成する際、機能モジュールとして動作するモジュールに必要なほとんどのマニフェスト属性は IDE に含まれています。また、一部の属性はコンパイル時にビルドシステムによって挿入されるため、ご自分で指定または変更する必要はありません。次の表に、機能モジュールの重要なマニフェスト属性を示します。

属性 説明
<manifest
...
これは典型的な <manifest> ブロックです。
xmlns:dist="http://schemas.android.com/apk/distribution" 新しい dist: XML 名前空間を指定します。これについては以下で詳細に説明します。
split="split_name" Android Studio が App Bundle をビルドする際、この属性が自動的に含まれます。そのため、この属性をご自分で指定または変更する必要はありません

モジュールの名前を定義します。これは、Play のコアライブラリを使用してオンデマンド モジュールをリクエストする際に、アプリで指定するものです。

Gradle がこの属性の値を判断する方法:

デフォルトでは、Android Studio を使用して機能モジュールを作成する際、IDE はモジュール名として指定された名前を、Gradle 設定ファイル内の Gradle サブプロジェクトとしてのモジュールを識別する名前として使用します。

App Bundle をビルドする際に、Gradle はサブプロジェクト パスの最後の要素を使用して、このマニフェスト属性をモジュールのマニフェストに挿入します。たとえば、新しい機能モジュールを MyAppProject/features/ ディレクトリに作成し、「dynamic_feature1」をモジュール名として指定した場合、IDE は ':features:dynamic_feature1' をサブプロジェクトとして settings.gradle ファイルに追加します。App Bundle をビルドすると、Gradle はモジュールのマニフェストに <manifest split="dynamic_feature1"> を挿入します。

android:isFeatureSplit="true | false"> Android Studio が App Bundle をビルドする際、この属性が自動的に含まれます。そのため、この属性を手動で指定または変更する必要はありません

このモジュールが機能モジュールであることを指定します。 ベース モジュールと構成 APK のマニフェストでは、この属性は省略されるか、false に設定されます。

<dist:module この新しい XML 要素は、モジュールを APK としてパッケージ化して配信する方法を決定する属性を定義します。
dist:instant="true | false" モジュールを Google Play Instant を介して Instant 機能として利用できるようにするかどうかを指定します。

アプリに Instant 対応の機能モジュールが含まれる場合は、ベース モジュールも Instant 対応にする必要があります。Android Studio 3.5 以降を使用して、Instant 対応機能モジュールを作成すると、IDE が Instant 対応を自動的に有効にします。

<dist:on-demand/> を設定している場合は、この XML 要素を true に設定することはできません。その場合でも、Play のコアライブラリを使用して Instant 対応にした機能モジュールを「Instant 機能」としてオンデマンドでダウンロードすることをリクエストできます。ユーザーがアプリをダウンロードしてインストールする際、デフォルトではデバイスはアプリの Instant 対応機能モジュールをベース APK とともに、ダウンロードしてインストールします。

dist:title="@string/feature_name" モジュールのユーザー向けのタイトルを指定します。たとえば、デバイスがダウンロードの確認を求める際にこのタイトルが表示される場合があります。

このタイトルの文字列リソースをベース モジュールの module_root/src/source_set/res/values/strings.xml ファイルに追加する必要があります。

<dist:fusing dist:include="true | false" />
</dist:module>
Android 4.4(API レベル 20)以前を搭載したデバイスを対象とするマルチ APK 内に、対象のモジュールを含めるかどうかを指定します。

さらに、bundletool を使用して App Bundle から APK を生成する際、このプロパティを true に設定する機能モジュールのみがユニバーサル APK に含まれます。ユニバーサル APK は、アプリがサポートするすべてのデバイス構成用のコードとリソースが含まれるモノリシック APK です。

<dist:delivery> 以下に示すように、モジュール配信をカスタマイズするオプションをカプセル化します。 各機能モジュールでは、以下のカスタム配信オプションのうち必ず 1 種類のみを構成します。
<dist:install-time> モジュールをインストール時に利用できるようにすることを指定します。これは、別のタイプのカスタム配信オプションを指定しない機能モジュールのデフォルトの動作です。

インストール時ダウンロードについて詳しくは、インストール時の配信を設定するをご覧ください。

このノードでは、デバイスの機能、ユーザーの居住国、最小 API レベルなど、特定の要件を満たすデバイスにモジュールを制限する条件も指定できます。詳細については、条件付き配信の構成をご覧ください。

<dist:removable value="true | false" />

未設定にするか、false に設定すると、バンドルから分割 APK を生成する際に、bundletool によってインストール時モジュールがベース モジュールに融合されます。融合の結果、分割 APK の数が減るため、この設定によってアプリのパフォーマンスが向上する可能性があります。

removabletrue に設定されている場合、インストール時モジュールはベース モジュールに融合されません。将来、モジュールをアンインストールする場合は、true に設定します。ただし、削除可能に設定したモジュールが多すぎると、アプリのインストール時間が長くなる可能性があります。

デフォルトは false です。機能モジュールの融合を無効にする場合にのみ、この値をマニフェストで設定する必要があります。

注: この機能は、Android Gradle プラグイン 4.2 を使用している場合と、コマンドラインから bundletool v1.0 を使用している場合にのみ使用できます。

</dist:install-time>  
<dist:on-demand/> モジュールをオンデマンドでダウンロード可能とすることを指定します。つまり、モジュールはインストール時には利用できませんが、後でアプリがダウンロードをリクエストできます。

オンデマンド ダウンロードの詳細については、オンデマンド配信を構成するをご覧ください。

</dist:delivery>
<application
android:hasCode="true | false">
...
</application>
DEX ファイルが生成されない機能モジュールの場合は、後で DEX ファイル形式にコンパイルされるコードが含まれていないため、以下のように設定する必要があります(設定しない場合は、ランタイム エラーが発生することがあります)。
  1. 機能モジュールのマニフェストで android:hasCode"false" に設定します。
  2. 以下の対象をベース モジュールのマニフェストに追加します。
    
    <application
      android:hasCode="true"
      tools:replace="android:hasCode">
      ...
    </application>
    

Play Feature Delivery をテストする

Play Feature Delivery のテストは Google Play ストアから行うことをおすすめします。Play Feature Delivery のメリットの多くが、APK の生成、署名、Play ストアへの配信の最適化の保留に依存しているためです。そのため、単純に App Bundle をアップロードする、または高度な配信方法を構成する場合のいずれであっても、以下の方法でアプリをテストするようにしてください。

リソースの URI の作成

URI を使用して機能モジュールに保存されているリソースにアクセスする場合は、以下に示すとおり、Uri.Builder() を使用して機能モジュールのリソース URI を生成します。

Kotlin

val uri = Uri.Builder()
                .scheme(ContentResolver.SCHEME_ANDROID_RESOURCE)
                .authority(context.getPackageName()) // Look up the resources in the application with its splits loaded
                .appendPath(resources.getResourceTypeName(resId))
                .appendPath(String.format("%s:%s",
                  resources.getResourcePackageName(resId), // Look up the dynamic resource in the split namespace.
                  resources.getResourceEntryName(resId)
                  ))
                .build()

Java

String uri = Uri.Builder()
                .scheme(ContentResolver.SCHEME_ANDROID_RESOURCE)
                .authority(context.getPackageName()) // Look up the resources in the application with its splits loaded
                .appendPath(resources.getResourceTypeName(resId))
                .appendPath(String.format("%s:%s",
                  resources.getResourcePackageName(resId), // Look up the dynamic resource in the split namespace.
                  resources.getResourceEntryName(resId)
                  ))
                .build().toString();

分割 APK が読み込まれた後に正しい名前空間が生成されるように、リソースへのパスの各部分は実行時に作成されます。

URI の生成方法の例として、次の名前のアプリと機能モジュールがあるとします。

  • アプリのパッケージ名: com.example.my_app_package
  • 機能のリソース パッケージ名: com.example.my_app_package.my_dynamic_feature

前述のコード スニペットの resId が、機能モジュールの「my_video」という名前の未加工のファイル リソースを参照した場合、上記の Uri.Builder() コードの出力内容は次のようになります。

android.resource://com.example.my_app_package/raw/com.example.my_app_package.my_dynamic_feature:my_video

アプリでこの URI を使用して、機能モジュールのリソースにアクセスできます。

URI のパスを検証するには、APK Analyzer を使用して機能モジュール APK を検査し、パッケージ名を特定します。

コンパイル済みリソース ファイルの内容を検査する APK Analyzer のスクリーンショット。

図 2. APK Analyzer を使用して、コンパイル済みリソース ファイルのパッケージ名を調べます。

機能モジュールについての検討事項

機能モジュールが含まれるアプリを製品版トラックに公開する場合は、以下の検討事項について考慮してください。

  • 1 台のデバイスに 50 個以上の機能モジュールをインストールすると、パフォーマンスの問題が発生する可能性があります。これを回避するには、Play のコアライブラリを使用して、ユーザーにとって不要になったモジュールをアンインストールすることを検討します。
  • インストール時の配信用に削除可能として構成するモジュールの数を 10 個以下に制限します。そうしないと、アプリのダウンロードとインストールに要する時間が増大する可能性があります。
  • 機能のオンデマンドによるダウンロードとインストールに対応しているのは、Android 5.0(API レベル 21)以降を搭載するデバイスのみです。Android のそれより前のバージョンで機能を利用できるようにするには、機能モジュールの作成時に、融合を有効にしてください。
  • ダウンロードされた機能モジュールにアプリがアクセスできるように、SplitCompat を必ず有効にします
  • 機能のダウンロード サイズが大きい場合は、デバイスに機能モジュールをダウンロードする前に、アプリがユーザーの確認をとる必要があります。
  • 機能モジュールのマニフェストで android:exportedtrue に設定したアクティビティを指定しないでください。別のアプリがそのアクティビティを開始しようとした際に、デバイスが機能モジュールをダウンロード済みであるという保証はないためです。さらに、アプリは機能のコードとリソースにアクセスしようとする前に、その機能がダウンロードされていることを確認する必要があります。詳細については、インストールしたモジュールの管理をご覧ください。
  • Play Feature Delivery では App Bundle を使用してアプリを公開する必要があるため、App Bundle の既知の問題について必ずご確認ください。

参考情報

Play Feature Delivery のサポートについて詳しくは、以下のリソースをご覧ください。

サンプル

Codelab

  • 初めての Android App Bundle: Android App Bundle の基本原則を探り、Android Studio を使用して独自のビルドをすぐに始める方法を示すコードラボです。このコードラボでは、bundletool を使用して App Bundle をテストする方法についても紹介します。
  • オンデマンド モジュール: オンデマンドで機能モジュールをダウンロードしてインストールするアプリの作成方法を紹介します。

ブログ投稿

動画