注意: 2021 年 8 月以降、すべての新規アプリは App Bundle として公開する必要があります。アプリを Google Play に公開する場合は、Android App Bundle をビルドしてアップロードします。こうすることで、各ユーザーのデバイス設定に合わせて最適化された APK が Google Play によって自動的に生成、配信されるため、ユーザーはアプリの実行に必要なコードとリソースをダウンロードするだけで済みます。複数の APK を公開することは、AAB 形式をサポートしていないストアに公開する場合に便利です。その場合は、各 APK のビルド、署名、管理を自分で行う必要があります。
可能であれば、すべての対象デバイスをサポートする 1 つの APK をビルドすることをおすすめしますが、さまざまな 画面密度やアプリケーション バイナリ インターフェース(ABI)をサポートするために必要なファイルが原因で、APK のサイズが非常に大きくなることがあります。APK のサイズを小さくする方法の 1 つとして、特定の画面密度や ABI 用のファイルを含む複数の APK を作成する方法があります。
Gradle では、各画面密度や ABI に固有のコードとリソースのみを含む APK を個別に作成できます。このページでは、複数の APK を生成するようにビルドを構成する方法について説明します。画面密度や ABI に基づかないさまざまなバージョンのアプリを作成する必要がある場合は、代わりにビルド バリアントを使用します。
複数の APK 用のビルドを構成する
複数の APK 用のビルドを構成するには、モジュール レベルの build.gradle
ファイルに splits
ブロックを追加します。splits
ブロック内で、Gradle で密度ごとの APK を生成する方法を規定する density
ブロック、または Gradle で ABI ごとの APK を生成する方法を規定する abi
ブロックを指定します。画面密度ブロックと ABI ブロックの両方を指定でき、画面密度と ABI の組み合わせに応じた APK がビルドシステムによって作成されます。
画面密度用の複数の APK の構成
画面密度ごとに異なる APK を作成するには、splits
ブロック内に density
ブロックを追加します。density
ブロックでは、目的の画面密度と互換性のある画面サイズのリストを指定します。互換性のある画面サイズのリストは、各 APK のマニフェストで特定の
<compatible-screens>
要素が必要な場合にのみ使用してください。
画面密度用の複数の APK を構成するには、以下の Gradle DSL オプションを使用します。
-
Groovy の場合は
enable
、Kotlin スクリプトの場合はisEnable
-
この要素を
true
に設定すると、Gradle により、定義した画面密度に基づいて複数の APK が生成されます。デフォルト値はfalse
です。 -
exclude
-
Gradle で個別の APK を生成しない画面密度をカンマ区切りのリストで指定します。ほとんどの画面密度用の APK を生成するものの、アプリでサポートしない一部の画面密度を除外する必要がある場合は、
exclude
を使用します。 -
reset()
-
画面密度のデフォルトのリストをクリアします。
include
要素と組み合わせて、追加したい画面密度を指定する場合にのみ使用します。次のスニペットは、
reset()
を呼び出してリストをクリアしてからinclude
を使用することで、ldpi
とxxhdpi
にのみ画面密度のリストを設定しています。reset() // Clears the default list from all densities // to no densities. include "ldpi", "xxhdpi" // Specifies the two densities to generate APKs // for.
-
include
-
Gradle で APK を生成する画面密度をカンマ区切りのリストで指定します。画面密度の正確なリストを指定するには、
reset()
と組み合わせて使用する必要があります。 -
compatibleScreens
-
互換性のある画面サイズをカンマ区切りのリストで指定します。これにより、一致する
<compatible-screens>
ノードが各 APK のマニフェストに追加されます。この設定を使用すると、画面密度と画面サイズの両方を同じ
build.gradle
セクションで簡単に管理できます。ただし、<compatible-screens>
を使用すると、アプリが動作するデバイスのタイプが制限されることがあります。さまざまな画面サイズをサポートする別の方法については、画面の互換性の概要をご覧ください。
画面密度に基づく各 APK には、APK がサポートする画面タイプに関する特定の制限付きの <compatible-screens>
タグが含まれるため、複数の APK を公開しても、新しいデバイスが複数の APK のフィルタと一致しないことがあります。そのため、Gradle は常に、あらゆる画面密度に対応するアセットを含み、<compatible-screens>
タグを含まない追加のユニバーサル APK を生成します。このユニバーサル APK を画面密度ごとの APK とともに公開し、<compatible-screens>
タグを含む APK と一致しないデバイスにはフォールバックを提供する必要があります。
次の例では、ldpi
、xxhdpi
、xxxhdpi
を除く画面密度ごとに個別の APK が生成されます。そのために、exclude
を使用して、すべての画面密度のデフォルトのリストから 3 つの画面密度を削除しています。
Groovy
android { ... splits { // Configures multiple APKs based on screen density. density { // Configures multiple APKs based on screen density. enable true // Specifies a list of screen densities you don't want Gradle to create multiple APKs for. exclude "ldpi", "xxhdpi", "xxxhdpi" // Specifies a list of compatible screen size settings for the manifest. compatibleScreens 'small', 'normal', 'large', 'xlarge' } } }
Kotlin
android { ... splits { // Configures multiple APKs based on screen density. density { // Configures multiple APKs based on screen density. isEnable = true // Specifies a list of screen densities you don't want Gradle to create multiple APKs for. exclude("ldpi", "xxhdpi", "xxxhdpi") // Specifies a list of compatible screen size settings for the manifest. compatibleScreens("small", "normal", "large", "xlarge") } } }
アプリのさまざまなビルド バリアントを特定の画面タイプとデバイスに合わせてカスタマイズする方法について詳しくは、画面サポートの制限の宣言をご覧ください。
ABI 用の複数の APK の構成
ABI ごとに異なる APK を作成するには、splits
ブロックの内側に abi
ブロックを追加します。abi
ブロックで、希望する ABI のリストを指定します。
各 ABI に複数の APK を構成するには、以下の Gradle DSL オプションを使用します。
-
Groovy の場合は
enable
、Kotlin スクリプトの場合はisEnable
- この要素を
true
に設定すると、定義した ABI に基づいて Gradle で複数の APK が生成されます。デフォルト値はfalse
です。 -
exclude
-
Gradle で APK を個別に生成しない ABI をカンマ区切りのリストで指定します。ほとんどの ABI 用の APK を生成するものの、アプリでサポートしない一部の ABI を除外する必要がある場合は、
exclude
を使用します。 -
reset()
-
ABI のデフォルトのリストをクリアします。
include
要素と組み合わせて、追加したい ABI を指定する場合にのみ使用します。次のスニペットは、
reset()
を呼び出してリストをクリアしてからinclude
を使用することで、x86
とx86_64
にのみ ABI のリストを設定しています。reset() // Clears the default list from all ABIs to no ABIs. include "x86", "x86_64" // Specifies the two ABIs we want to generate APKs for.
-
include
-
Gradle で APK を生成する ABI をカンマ区切りのリストで指定します。
reset()
と組み合わせて ABI の正確なリストを指定する場合にのみ使用します。 -
Groovy の場合は
universalApk
、Kotlin スクリプトの場合はisUniversalApk
-
true
の場合、Gradle は ABI ごとの APK に加えてユニバーサル APK を生成します。ユニバーサル APK では、1 つの APK にすべての ABI のコードとリソースが含まれます。デフォルト値はfalse
です。このオプションを指定できるのは
splits.abi
ブロックのみです。画面密度に基づいて複数の APK をビルドする場合、Gradle では常に、すべての画面密度用のコードとリソースを含むユニバーサル APK が生成されます。
次の例では、各 ABI(x86
と x86_64
)用の APK を個別に生成しています。そのために、reset()
を使用して ABI の空のリストを作成してから、APK をそれぞれ取得する ABI のリストを include
で指定しています。
Groovy
android { ... splits { // Configures multiple APKs based on ABI. abi { // Enables building multiple APKs per ABI. enable true // By default all ABIs are included, so use reset() and include to specify that you only // want APKs for x86 and x86_64. // Resets the list of ABIs for Gradle to create APKs for to none. reset() // Specifies a list of ABIs for Gradle to create APKs for. include "x86", "x86_64" // Specifies that you don't want to also generate a universal APK that includes all ABIs. universalApk false } } }
Kotlin
android { ... splits { // Configures multiple APKs based on ABI. abi { // Enables building multiple APKs per ABI. isEnable = true // By default all ABIs are included, so use reset() and include to specify that you only // want APKs for x86 and x86_64. // Resets the list of ABIs for Gradle to create APKs for to none. reset() // Specifies a list of ABIs for Gradle to create APKs for. include("x86", "x86_64") // Specifies that you don't want to also generate a universal APK that includes all ABIs. isUniversalApk = false } } }
サポート対象 ABI のリストについては、サポート対象 ABI をご覧ください。
ネイティブ / C++ コードを含まないプロジェクト
ネイティブ/C++ コードを含まないプロジェクトの場合、[Build Variants] パネルには、図 1 に示すように、[Module] と [Active Build Variant] の 2 つの列が表示されます。
図 1. ネイティブ/C++ コードを含まないプロジェクトの場合、[Build Variants] パネルには 2 つの列が表示されます。
モジュールの [Active Build Variant] 値により、デプロイされ、エディタで表示されるビルド バリアントが決定されます。バリアントを切り替えるには、モジュールの [Active Build Variant] セルをクリックし、リスト フィールドから目的のバリアントを選択します。
ネイティブ / C++ コードを含むプロジェクト
ネイティブ/C++ コードを使用するプロジェクトの場合、[Build Variants] パネルには、図 2 に示すように、[Module]、[Active Build Variant]、[Active ABI] の 3 つの列が表示されます。
図 2. ネイティブ/C++ コードを含むプロジェクトの場合、[Build Variants] パネルに [Active ABI] 列が追加されます。
デプロイされ、エディタに表示されるビルド バリアントは、モジュールの [Active Build Variant] 値によって決定されます。ネイティブ モジュールの場合は、[Active ABI] 値によってエディタが使用する ABI が決定されますが、デプロイされるものには影響しません。
ビルドタイプまたは ABI を変更するには:
- [Active Build Variant] 列または [Active ABI] 列のセルをクリックします。
- リストから目的のバリアントまたは ABI を選択します。新しい同期が自動的に実行されます。
アプリまたはライブラリ モジュールのいずれかの列を変更すると、すべての依存行に変更が適用されます。
バージョン管理の構成
Gradle で複数の APK を生成する場合、デフォルトでは、モジュール レベルの build.gradle
ファイルまたは build.gradle.kts
ファイルで指定されているバージョン情報がすべての APK に対して適用されます。Google Play ストアでは、同一アプリの複数の APK が同じバージョン情報を持つことは認められていないため、Play ストアにアップロードする前に、各 APK の
versionCode
が一意の値になっていることを確認する必要があります。
APK ごとに versionCode
をオーバーライドするように、モジュール レベルの build.gradle
ファイルを構成できます。複数の APK を構成する ABI と画面密度ごとに一意の数値を割り当てるマッピングを作成することで、出力バージョン コードをオーバーライドし、defaultConfig
ブロックまたは productFlavors
ブロック内で定義されたバージョン コードと、画面密度または ABI に割り当てられた数値を組み合わせた値を指定できます。
次の例では、x86
ABI の APK には versionCode
2004 が割り当てられ、x86_64
ABI の APK には 3004 が割り当てられます。versionCode
1000 のような増分の大きいバージョン コードを割り当てると、後でアプリの更新が必要になったときに一意のバージョン コードを割り当てることができます。たとえば、その後のアップデートで defaultConfig.versionCode
が 5 に進められると、Gradle によって x86
APK には versionCode
2005、x86_64
APK には 3005 が割り当てられます。
ヒント: ビルドにユニバーサル APK が含まれている場合は、他のどの APK よりも小さい versionCode
を割り当てます。Google Play ストアは、対象デバイスと互換性があり、versionCode
が最も大きいアプリのバージョンをインストールするため、小さい versionCode
をユニバーサル APK に割り当てることで、Google Play ストアでユニバーサル APK にフォールバックする前に、いずれかの APK がインストールされるようになります。次のサンプルコードは、ユニバーサル APK のデフォルトの versionCode
をオーバーライドしないことにより、これに対処しています。
Groovy
android { ... defaultConfig { ... versionCode 4 } splits { ... } } // Map for the version code that gives each ABI a value. ext.abiCodes = ['armeabi-v7a':1, x86:2, x86_64:3] // For per-density APKs, create a similar map: // ext.densityCodes = ['mdpi': 1, 'hdpi': 2, 'xhdpi': 3] import com.android.build.OutputFile // For each APK output variant, override versionCode with a combination of // ext.abiCodes * 1000 + variant.versionCode. In this example, variant.versionCode // is equal to defaultConfig.versionCode. If you configure product flavors that // define their own versionCode, variant.versionCode uses that value instead. android.applicationVariants.all { variant -> // Assigns a different version code for each output APK // other than the universal APK. variant.outputs.each { output -> // Stores the value of ext.abiCodes that is associated with the ABI for this variant. def baseAbiVersionCode = // Determines the ABI for this variant and returns the mapped value. project.ext.abiCodes.get(output.getFilter(OutputFile.ABI)) // Because abiCodes.get() returns null for ABIs that are not mapped by ext.abiCodes, // the following code doesn't override the version code for universal APKs. // However, because you want universal APKs to have the lowest version code, // this outcome is desirable. if (baseAbiVersionCode != null) { // Assigns the new version code to versionCodeOverride, which changes the // version code for only the output APK, not for the variant itself. Skipping // this step causes Gradle to use the value of variant.versionCode for the APK. output.versionCodeOverride = baseAbiVersionCode * 1000 + variant.versionCode } } }
Kotlin
android { ... defaultConfig { ... versionCode = 4 } splits { ... } } // Map for the version code that gives each ABI a value. val abiCodes = mapOf("armeabi-v7a" to 1, "x86" to 2, "x86_64" to 3) // For per-density APKs, create a similar map: // val densityCodes = mapOf("mdpi" to 1, "hdpi" to 2, "xhdpi" to 3) import com.android.build.api.variant.FilterConfiguration.FilterType.* // For each APK output variant, override versionCode with a combination of // abiCodes * 1000 + variant.versionCode. In this example, variant.versionCode // is equal to defaultConfig.versionCode. If you configure product flavors that // define their own versionCode, variant.versionCode uses that value instead. androidComponents { onVariants { variant -> // Assigns a different version code for each output APK // other than the universal APK. variant.outputs.forEach { output -> val name = output.filters.find { it.filterType == ABI }?.identifier // Stores the value of abiCodes that is associated with the ABI for this variant. val baseAbiCode = abiCodes[name] // Because abiCodes.get() returns null for ABIs that are not mapped by ext.abiCodes, // the following code doesn't override the version code for universal APKs. // However, because you want universal APKs to have the lowest version code, // this outcome is desirable. if (baseAbiCode != null) { // Assigns the new version code to output.versionCode, which changes the version code // for only the output APK, not for the variant itself. output.versionCode.set(baseAbiCode * 1000 + (output.versionCode.get() ?: 0)) } } } }
別のバージョン コード スキームの例については、バージョン コードの割り当てをご覧ください。
複数の APK をビルドする
複数の APK をビルドするようにモジュール レベルの build.gradle
または build.gradle.kts
ファイルを構成したら、[Build] > [Build APK] をクリックして、[Project] ペインで現在選択されているモジュールの APK をすべてビルドします。Gradle は、各画面密度または ABI 用の APK をプロジェクトの build/outputs/apk/
ディレクトリに作成します。
Gradle は、複数の APK を構成した画面密度または ABI ごとに APK をビルドします。 画面密度と ABI の両方で複数の APK を有効にすると、Gradle で画面密度と ABI の組み合わせごとに APK が作成されます。
たとえば次の build.gradle
スニペットでは、mdpi
と hdpi
の画面密度および x86
と x86_64
の ABI に対して複数の APK のビルドが可能です。
Groovy
... splits { density { enable true reset() include "mdpi", "hdpi" } abi { enable true reset() include "x86", "x86_64" } }
Kotlin
... splits { density { isEnable = true reset() include("mdpi", "hdpi") } abi { isEnable = true reset() include("x86", "x86_64") } }
この例の構成の出力には、以下の 4 つの APK が含まれます。
app-hdpiX86-release.apk
:hdpi
画面密度とx86
ABI のコードとリソースが含まれます。app-hdpiX86_64-release.apk
:hdpi
画面密度とx86_64
ABI のコードとリソースが含まれます。app-mdpiX86-release.apk
:mdpi
画面密度とx86
ABI のコードとリソースが含まれます。app-mdpiX86_64-release.apk
:mdpi
画面密度とx86_64
ABI のコードとリソースが含まれます。
画面密度に基づいて複数の APK をビルドする場合、Gradle では常に、画面密度ごとの APK に加え、すべての画面密度用のコードとリソースを含むユニバーサル APK が生成されます。
ABI に基づいて複数の APK をビルドする場合、build.gradle
ファイルの splits.abi
ブロックで universalApk true
を指定すると、Gradle により、すべての ABI 用のコードとリソースを含む APK のみが生成されます(Groovy の場合)。build.gradle.kts
ファイルの splits.abi
ブロックで isUniversalApk = true
を指定すると、Gradle により、すべての ABI 用のコードとリソースを含む APK のみが生成されます(Kotlin スクリプトの場合)。
APK ファイル名の形式
複数の APK をビルドする場合、Gradle は次のスキームを使用して APK ファイル名を生成します。
modulename-screendensityABI-buildvariant.apk
スキームのコンポーネントは次のとおりです。
-
modulename
- ビルド対象のモジュール名を指定します。
-
screendensity
-
APK の画面密度が有効になっている場合、APK の画面密度を指定します(
mdpi
など)。 -
ABI
-
ABI 用の複数の APK が有効になっている場合、APK の ABI を指定します(
x86
など)。画面密度と ABI の両方で複数の APK が有効になっている場合、Gradle は画面密度名を ABI 名と結合します(例:
mdpiX86
)。ABI ごとの APK でuniversalApk
が有効になっている場合、Gradle はユニバーサル APK のファイル名の ABI の部分としてuniversal
を使用します。 -
buildvariant
-
ビルド対象のビルド バリアントを指定します(
debug
など)。
たとえば、myApp のデバッグ バージョン用に mdpi
画面密度の APK をビルドする場合、APK のファイル名は myApp-mdpi-debug.apk
になります。mdpi
画面密度と x86
ABI の両方で複数の APK をビルドするように構成された myApp のリリース バージョンでは、APK のファイル名は myApp-mdpiX86-release.apk
になります。