複数 APK のサポート

アプリを Google Play に公開する場合は、Android App Bundle を作成してアップロードしてください。そうすることで、各ユーザーのデバイス構成に合わせて最適化された APK が Google Play によって自動的に生成、配信されるため、ユーザーはアプリの実行に必要なコードとリソースをダウンロードするだけで済みます。複数の APK を公開するという方法は、Google Play に公開しない場合は便利ですが、各 APK のビルド、署名、管理を自分で行う必要があります。

複数 APK サポートとは、1 つのアプリでデバイス構成ごとに別々の APK を公開するための Google Play の機能です。各 APK は、それぞれがアプリの完全で独立したバージョンですが、Google Play では同じアプリ掲載情報を共有します。また、パッケージ名を同じにして、同じリリースキーで署名する必要があります。この機能は、1 つの APK では、アプリで対象とするデバイスをすべてカバーしきれない場合に役立ちます。

同じ Android を搭載したデバイスでも、デバイスによって構成が異なるため、アプリを広く普及させるには、できるだけ多くのデバイスで利用できるようにすることが重要です。通常、Android アプリは 1 つの APK でもほとんどの互換デバイスで動作させることができます。これは、異なる構成ごとに代替リソースを用意しておけば(さまざまな画面サイズ用のレイアウトなど)、実行時に Android システムによって適切なリソースが選択されるためです。ただし、少ないながらも、1 つの APK ではすべてのデバイス構成に対応できない場合があります。代替リソースで APK ファイルが大きくなりすぎるなどの技術的な問題により、1 つの APK のみではすべてのデバイスをカバーしきれないことがあるためです。

できるだけ多くのデバイスに向けてアプリを公開できるよう、Google Play では同じアプリ掲載情報の下に複数の APK を公開できるようにしています。各 APK は、それぞれのマニフェスト ファイルで宣言した構成サポートに基づいて、適切なデバイスに提供されます。

複数 APK でアプリを公開することにより、以下が可能になります。

  • APK ごとに異なる OpenGL テクスチャ圧縮形式をサポートすること。
  • APK ごとに異なる画面サイズと画面密度をサポートすること。
  • APK ごとに異なるデバイス機能セットをサポートすること。
  • APK ごとに異なるプラットフォーム バージョンをサポートすること。
  • APK ごとに異なる CPU アーキテクチャをサポートすること(アプリで Android NDK を使用する場合、ARM や x86 など)。
  • エントリレベルのデバイス(Android Go バージョンを搭載したデバイスなど)向けに最適化すること。

現時点では、Google Play で複数 APK を同一アプリとして公開する際にサポートされるデバイス特性は上記のみです。

注: Google Play での APK のリリース準備と公開の詳細については、リリースの準備と公開のサポート記事をご覧ください。

複数 APK の仕組み

Google Play で複数 APK を使用するということは、Google Play でのアプリのエントリは 1 つしかなくても、デバイスによって異なる APK がダウンロードされるということです。それによる効果は以下のとおりです。

  • 商品の詳細(アプリの説明、アイコン、スクリーンショットなど)は 1 セットのみ保守すれば済みます。 これはまた、APK ごとに異なる価格を設定できないということでもあります。
  • Google Play ですべてのユーザーに表示されるアプリのバージョンは 1 つのみのため、「タブレット用」や「スマートフォン用」など、公開したバージョンの違いにより混乱を招くことがありません。
  • デバイスによってユーザーの APK が異なる場合でも、すべてのユーザーのレビューは同じアプリ掲載情報に反映されます。
  • Android のバージョン(API レベル)に応じて異なる APK を公開している場合、ユーザーのデバイスが、公開済みの別の APK に適したシステム アップデートを受信すると、ユーザーのアプリは、Google Play によって新しい Android バージョン用に設計された APK に更新されます。その場合、アプリに関連付けられたシステムデータは保持されます(単一の APK を使用する場合の通常のアプリ更新と同様です)。

サポート対象フィルタ

各 APK を受信するデバイスは、各 APK のマニフェスト ファイルの要素で指定される Google Play フィルタによって決まります。ただし、Google Play で複数 APK を公開できるのは、各 APK がフィルタによって以下のデバイス特性のバリエーションをサポートする場合のみです。

  • OpenGL テクスチャ圧縮形式

    これは、マニフェスト ファイルの <supports-gl-texture> 要素に基づきます。

    たとえば、OpenGL ES を使用するゲームを開発する場合、ATI テクスチャ圧縮をサポートするデバイス用の APK と、PowerVR 圧縮をサポートするデバイス用の APK を、その他とは別個に提供できます。

  • 画面サイズ(画面密度も指定可能)

    これは、マニフェスト ファイルの <supports-screens> 要素または <compatible-screens> 要素に基づきます。両方の要素を使用しないでください。また、可能な限り <supports-screens> を使用してください。

    たとえば、小さい画面と標準サイズの画面をサポートする APK と、大きい画面と特大サイズの画面をサポートする APK を別々に提供できます。画面サイズや画面密度に応じて異なる APK を生成する方法の詳細については、複数の APK のビルドをご覧ください。

    すべての画面サイズをサポートするためのおすすめの方法は次のとおりです。

    • Android システムでは、単一の APK ですべての画面構成に対応できるよう、アプリに対して強力なサポートを提供しています。異なる画面構成に対応するために複数の APK を作成することは、そうせざるを得ない場合以外は避けてください。代わりに、複数画面構成に対応するためのガイドに沿って、アプリに柔軟性を持たせ、単一の APK ですべての画面構成に対応できるようにしてください。
    • デフォルトでは、<supports-screens> 要素のすべての画面サイズ属性は、特に宣言しない限り「true」です。ただし、android:xlargeScreens 属性は Android 2.3(API レベル 9)で追加されたため、アプリで android:minSdkVersion または android:targetSdkVersion を「9」以上に設定していない場合、Google Play ではこの属性は「false」と見なされます。
    • マニフェスト ファイルで <supports-screens> 要素と <compatible-screens> 要素の両方を組み合わせないでください。両方を使用すると、競合によりエラーが発生する可能性が高くなります。どちらを使用するべきかについては、特定の画面のデバイスへの配信をご覧ください。両方を使用しなければならない場合は、特定のサイズに対する競合では「false」が優先されることに注意してください。
  • デバイスの機能セット

    これは、マニフェスト ファイルの <uses-feature> 要素に基づきます。

    たとえば、マルチタッチをサポートするデバイスと、サポートしないデバイスには、異なる APK を提供できます。プラットフォームがサポートする機能の一覧については、機能リファレンスをご覧ください。

  • Android(Go バージョン)

    Android(Go バージョン)搭載のデバイスをターゲットにするには、APK で <uses-feature android:name="android.hardware.ram.low" android:required="true"> を宣言し、API レベル 26 以上をターゲットにして、Go バージョン以外の APK よりも高いバージョン コードを設定する必要があります。

  • API レベル

    これは、マニフェスト ファイルの <uses-sdk> 要素に基づきます。android:minSdkVersion 属性と android:maxSdkVersion 属性の両方を使用して、さまざまな API レベルのサポートを指定できます。

    たとえば、API レベル 16~19(Android 4.1.x~4.4.4)をサポートする APK(API レベル 16 以前から利用可能な API のみを使用)と、API レベル 21 以降 (Android 5.0 以降)をサポートするもう 1 つの APK(API レベル 21 以前から利用可能な API を使用)を使用して、アプリを公開できます。それぞれが異なる範囲の API をターゲットとする複数の APK を作成する方法については、プロダクト フレーバーの設定をご覧ください。

    この特性を使用して APK を複数に分割する場合は、android:minSdkVersion 値が高い APK ほど android:versionCode 値を高くする必要があります。別のサポート対象フィルタによって、2 つの APK でデバイス サポートが重複する場合も同様です。こうすることで、デバイスがシステム アップデートを受信したときに、Google Play からアプリのアップデートも提供されるようになります(アップデートはアプリのバージョン コードの増加に基づくため)。この要件については、複数 APK のルールに関する下記のセクションでさらに説明します。

    通常は、android:maxSdkVersion を使用しないようにします。これは、公開 API を使用してアプリを適切に開発している限り、Android の将来のバージョンとは常に互換性があるためです。より高い API レベル用の APK を別に公開する場合でも、最大バージョンを指定する必要はありません。これは、android:minSdkVersion が、ある APK では "16"、別の APK では "21" の場合、API レベル 21 以降をサポートするデバイスは、常に後者の APK を受け取るためです(前述のとおり、後者のバージョン コードの方が大きいため)。


  • CPU アーキテクチャ(ABI)

    一部のネイティブ ライブラリは、特定の CPU アーキテクチャ、つまりアプリケーション バイナリ インターフェース(ABI)用に個別のパッケージを提供します。利用できるライブラリをすべて 1 つの APK にパッケージ化する代わりに、ABI ごとに個別の APK を作成し、そこに該当の ABI に必要なライブラリのみを含めることができます。ターゲットの ABI ごとに個別の APK を作成する方法の詳細については、複数の APK のビルドをご覧ください。

Google Play フィルタを有効にする他のマニフェスト要素(ここには挙げられていないもの)も、通常どおり各 APK に適用されます。ただし、Google Play では、そのようなデバイス特性のバリエーションに基づいて個別の APK を公開することはできません。したがって、上に挙げたフィルタが各 APK で同じ場合は、複数 APK を公開することはできません(ただし、APK はマニフェストまたは APK の他の特性に基づいて異なるものになります)。たとえば、<uses-configuration> 特性が違うだけの複数の APK を提供することはできません。

複数 APK のルール

アプリの複数 APK を公開する前に、次のルールを理解する必要があります。

  • 同じアプリ用に公開するすべての APK には、同じパッケージ名を付け、同じ証明書鍵で署名する必要があります
  • 各 APK には、android:versionCode 属性で異なるバージョン コードを指定する必要があります
  • 各 APK は、構成サポートを他の APK とまったく同じにはできません

    つまり、各 APK では、サポートされている Google Play フィルタ(上記)の少なくとも 1 つについて、少しでも異なるサポートを宣言する必要があります。

    通常、特定の特性(サポートするテクスチャ圧縮形式など)に基づいて APK に違いを持たせるため、各 APK で別々のデバイスに対するサポートを宣言します。ただし、公開する複数の APK で多少サポートが重複してもかまいません。2 つの APK が重複する場合(両方にサポートされるデバイス構成がある場合)、その重複範囲に入るデバイスは、バージョン コード(android:versionCode で定義される)が高い方の APK を受け取ります。

  • 新しい APK のバージョン コードの方が既存の APK よりも低いと、新しい APK をアクティブにできません。たとえば、小~標準の画面サイズ用の、バージョン コードが 0400 の APK がアクティブな場合に、これを同じ画面サイズ用の、バージョン コードが 0300 の APK に置き換えようとしたとします。その結果はエラーになります。これでは、以前の APK のユーザーはアプリを更新できないためです。
  • より高い API レベルを必要とする APK には、より高いバージョン コードが必要です。

    これは、APK 同士の違いが、サポートする API レベルのみの場合(その他のサポート対象フィルタでは APK を区別できない場合)、または、APK で他のサポート対象フィルタが使用されているものの、そのフィルタでは APK 間に重複が生じる場合のいずれかにのみ適用されます。

    これが重要なのは、ユーザーのデバイスで Google Play からアプリのアップデートを受け取れるのは、Google Play にある APK のバージョン コードの方が現在デバイスにある APK のバージョン コードよりも高い場合に限られるためです。こうすることで、デバイスがシステム アップデートを受信して、より高い API レベルの APK をインストールできるようになった際に、デバイスはより高いバージョン コードを持つアプリのアップデートを確実に受信できます。

    注: バージョン コードの増加量に決まりはありません。より高い API レベルをサポートするには、より高いバージョン コードが必要というだけです。

    以下に、例をいくつか示します。

    • API レベル 16 以上(Android 4.1.x 以降)用としてアップロードした APK のバージョン コードを 0400 にした場合、API レベル 21 以上(Android 5.0 以降)用の APK では 0401 以上にする必要があります。この場合、使用するサポート対象フィルタは API レベルだけであるため、ユーザーがシステム アップデート時にアプリのアップデートを受け取れるようにするには、APK でサポートする API レベルの増加に応じてバージョン コードも増加させる必要があります
    • API レベル 16(以上)用かつ小~大画面サイズ用の APK と、API レベル 21(以上)用かつ大~特大画面サイズ用の APK がある場合、バージョン コードは API レベルの増加に応じて増加させる必要があります。この場合、各 APK を区別するために API レベルのフィルタが使用されますが、画面サイズも使用されます。ただ、画面サイズには重複がある(両方の APK が大画面サイズをサポートしている)ため、バージョン コードはやはりルールに合わせる必要があります。これにより、API レベル 21 へのシステム アップデートを受け取った大画面デバイスは、確実に後者の APK アップデートを受け取ることになります。
    • API レベル 16(以上)用かつ小~通常画面サイズ用の APK と、API レベル 21(以上)用かつ大~特大画面用の APK がある場合、バージョン コードは、API レベルの増加に応じて増加させる必要はありません。画面サイズのフィルタ内に重複がないため、これら 2 つの APK 間を移動する可能性のあるデバイスはなく、よって低い API レベルから高い API レベルに上げるためにバージョン コードを増やす必要はありません。
    • API レベル 16(以上)用かつ ARMv7 CPU 用の APK と、API レベル 21(以上)用かつ ARMv5TE CPU 用の APK がある場合、バージョン コードは API レベルの増加に応じて増加させる必要があります。この場合、各 APK を区別するために API レベルのフィルタが使用されますが、CPU アーキテクチャも使用されます。ARMv5TE ライブラリを含む APK は、ARMv7 CPU を備えたデバイスとも互換性があるため、両 APK にはこの特性について重複があります。よって、API レベル 21 以上をサポートする APK のバージョン コードのほうを高くする必要があります。 これにより、API レベル 21 へのシステム アップデートを受け取った ARMv7 CPU のデバイスは、確実に API レベル 21 用に設計された後者の APK アップデートを受け取ることになります。ただし、このようなアップデートにより、ARMv7 デバイスでは CPU に完全に最適化されていない APK が使用されることになります。それぞれの CPU でアプリのパフォーマンスを最適化するためには、ARMv5TE と ARMv7 の両方に対して、各 API レベル用の APK を提供するようにします。注: この例は、ARMv5TE のライブラリを含む APK と ARMv7 のライブラリを含む APK の間にのみ適用されるものであり、他のネイティブ ライブラリには適用されません。

上記のルールに違反すると、APK をアクティブにしたときに Google Play Console でエラーが発生します。エラーを解消するまで、アプリは公開できません。

他にも、APK をアクティブにしたときに発生しうる競合がありますが、これらはエラーではなく警告になります。警告の原因には、次のものがあります。

  • デバイス特性のサポート範囲を「縮小」するよう APK を変更し、それによりサポート範囲から外れたデバイスが、他のいずれの APK でもサポートされない場合。たとえば、現在 APK で小~標準画面サイズをサポートしている場合、小画面サイズのみをサポートするよう変更すると、サポート対象デバイスの範囲を縮小したことになり、一部のデバイスでは Google Play にアプリが表示されなくなります。これを解決するには、それまでサポートしていたデバイスをすべて引き続きサポートするよう、標準画面サイズをサポートする別の APK を追加します。
  • 複数の APK の間に「重複」がある場合。たとえば、小、標準、大の画面サイズをサポートする APK と、大および特大の画面サイズをサポートする APK がある場合、大画面サイズは両方の APK にサポートされるため、重複があることになります。これを解決しない場合、両方の APK にサポートされるデバイス(この例では大画面サイズのデバイス)は、バージョン コードが高い方の APK を受け取ります。

    注: CPU アーキテクチャごとに個別の APK を作成する場合、ARMv5TE 用の APK は ARMv7 用の APK と重複することに注意してください。つまり、ARMv5TE デバイス用の APK は ARMv7 デバイスとも互換性があります。ただし、その逆は当てはまりません(ARMv7 用ライブラリのみを含む APK は、ARMv5TE デバイスとは互換性がありません)。

このような競合が発生すると、警告メッセージが表示されますが、アプリを公開することはできます。

複数 APK の作成

複数 APK を公開することにしたら、通常は公開する APK ごとに個別の Android プロジェクトを作成し、それぞれを分けて適切に開発できるようにする必要があります。これは、既存のプロジェクトを複製して新しい名前を付けるだけで行えます (または、ビルド構成に基づいて、テクスチャなどの個別のリソースを出力できるビルドシステムを使用する方法もあります)。

ヒント: アプリケーション コードの大部分が重複するのを避けるには、ライブラリ プロジェクトを使うのも 1 つの方法です。共通するコードとリソースをライブラリ プロジェクトに保持しておき、それを実際のアプリ プロジェクトに含めることができます。

1 つのアプリに対して複数のプロジェクトを作成する場合は、各 APK がカバーするデバイスの範囲を示す名前を付けて、プロジェクトを識別しやすくすることをおすすめします。たとえば、API レベル 21 以上用のアプリであれば、「HelloWorld_21」などにするとよいでしょう。

注: 同じアプリ用に公開するすべての APK には、同じパッケージ名を付け、同じ証明書鍵で署名する必要があります。個々の複数 APK のルールも必ず理解してください。

バージョン コードの割り当て

同じアプリの各 APK には、android:versionCode 属性で一意のバージョン コードを指定する必要があります。複数 APK を公開する場合、各 APK のバージョン コードは異なっている必要がありますが、場合によってはそれぞれの値の大小関係を、各 APK がサポートする構成に基づいて定義しなければならない、または定義した方がよいため、注意が必要です。

バージョン コードの順序付け

通常、より高い API レベルを必要とする APK には、より高いバージョン コードが必要です。たとえば、異なる API レベルをサポートするために 2 つの APK を作成する場合、より高い API レベルの APK にはより高いバージョン コードを付ける必要があります。そうすることで、デバイスがシステム アップデートを受信して、より高い API レベルの APK をインストールできるようになった際に、ユーザーはアプリを更新するための通知を確実に受信できます。この要件が適用される仕組みの詳細については、複数 APK のルールに関する上記のセクションをご覧ください。

また、バージョン コードの順序が、APK 間のサポート対象範囲の重複や APK に対する将来の変更と関連して、ユーザーが受信する APK にどのように影響するかを考慮する必要もあります。

たとえば、画面サイズに基づいて異なる APK(小~標準画面サイズ用と大~特大画面サイズ用など)があり、近い将来に APK を小画面サイズ用と標準~特大画面サイズ用に編成し直す予定がある場合は、大~特大画面サイズ用の APK のバージョン コードの方を高くするようにします。そうすれば、その変更を行った際に、標準画面サイズのデバイスは適切なアップデートを受け取ることができます。既存の APK より新たにそのデバイスをサポートすることになった APK の方がバージョン コードが高くなるためです。

また、サポートする OpenGL テクスチャ圧縮形式に基づいて複数の APK を作成する場合は、多くのデバイスが複数の形式をサポートすることに注意してください。2 つの APK 間でサポート対象範囲に重複がある場合、デバイスはバージョン コードが高い方の APK を受信します。そのため、最も適した形式の APK のバージョン コードが最高になるように順序付けします。たとえば、使用する圧縮形式 PVRTC、ATITC、ETC1 ごとに、アプリを個別にビルドするとします。圧縮形式をこのとおりの優先順序で使用する場合は、PVRTC を使用する APK のバージョン コードを最も高く、ATITC をそれよりも低く、ETC1 を最も低く設定します。そうすることで、PVRTC と ETC1 の両方をサポートするデバイスは、より高いバージョン コードを持つ PVRTC の APK を受け取ることになります。

ターゲット デバイスにインストールすべき適切な APK が Google Play ストアで識別できない場合に備え、サポートするすべてのデバイス バリエーションのリソースを含む「ユニバーサル」APK を作成することもできます。ユニバーサル APK には、最も低い versionCode を設定します。Google Play ストアからは、ターゲット デバイスと互換性があり、最も高い versionCode のアプリがインストールされます。そのため、ユニバーサル APK に低い versionCode を割り当てておけば、Google Play ストアでは、サイズの大きなユニバーサル APK のインストールの前に、他の APK のインストールが確実に試行されます。

バージョン コード スキームの使用

それぞれの APK が他とは独立してバージョン コードを更新できる(たとえば、ある APK のバグを修正した際に、他のすべての APK を更新しなくても済む)ようにするためには、ある APK のバージョン コードを増やしても他を増やさずに済むよう、各 APK のバージョン コード間に十分な余裕を設けたバージョン コード スキームを使用します。また、コードには実際のバージョン名(つまり、android:versionName に割り当てられているユーザーに表示されるバージョン)を含めるようにします。これにより、バージョン コードとバージョン名の関連付けが容易になります。

注: APK のバージョン コードを増やすと、以前のバージョンのユーザーは、Google Play からアプリの更新を促されます。したがって、不要な更新を避けるために、実際の変更を含まない APK についてはバージョン コードを増やすべきではありません。

バージョン コードは 7 桁以上にすることをおすすめします。その上位ビットには、サポート対象の構成を表す整数を、下位ビットには、バージョン名(android:versionName)を配置します。たとえば、アプリのバージョン名が 3.1.0 の場合、API レベル 4 用の APK と API レベル 11 用の APK のバージョン コードは、それぞれ 0400310、1100310 のようになります。最初の 2 桁は API レベル(それぞれ 4 と 11)用、その次の 2 桁は画面サイズまたは GL テクスチャ形式用(この例では使用していません)、最後の 3 桁はアプリのバージョン名(3.1.0)用に確保しています。図 1 は、プラットフォーム バージョン(API レベル)と画面サイズの両方に基づいて分割した 2 つの APK のバージョン コード例を示しています。

図 1. バージョン コードのスキーム例 - 最初の 2 桁は API レベル用、3 桁目と 4 桁目はそれぞれ最小画面サイズと最大画面サイズ用(1~4 は 4 種類の画面サイズを示す)またはテクスチャ形式用、最後の 3 桁はアプリ バージョン用

このバージョン コード スキームは、アプリの進化に合わせて拡張可能なパターンを確立する方法の一例にすぎません。特に、このスキームは、テクスチャ圧縮形式を識別するための方法を示していません。方法の一つとしては、アプリでサポートする各圧縮形式に異なる整数値を割り当てるテーブルを定義することが考えられます(たとえば、ETC1 は 1、ATITC は 2 など)。

どのようなスキームを使用するかは自由ですが、アプリの将来のバージョンでバージョン コードをどのように増やしていくか、また、デバイス構成の変更時(システム アップデートなど)や APK の構成サポートの変更時にデバイスでどのようにアップデートを受け取るかについて、慎重に検討してください。