複数の APK をビルドする

可能な限り、すべての対象デバイスをサポートする単一の APK をビルドすることをおすすめしますが、複数のアプリケーション バイナリ インターフェース(ABI)をサポートするファイルにより、APK のサイズが非常に大きくなる可能性があります。APK のサイズを縮小する方法の 1 つは、特定の ABI のファイルを含む複数の APK を作成することです。

Gradle では、各 ABI に固有のコードとリソースのみを含む個別の APK を作成できます。このページでは、複数の APK を生成するようにビルドを構成する方法について説明します。ABI に基づかないさまざまなバージョンのアプリを作成する必要がある場合は、代わりにビルド バリアントを使用します。

複数の APK 用のビルドを構成する

複数の APK 用にビルドを構成するには、モジュール レベルの build.gradle ファイルに splits ブロックを追加します。splits ブロック内に、Gradle で ABI ごとの APK を生成する方法を指定する abi ブロックを指定します。

ABI 用の複数の APK の構成

異なる ABI 用に個別の APK を作成するには、splits ブロック内に abi ブロックを追加します。abi ブロックで、選択した ABI のリストを指定します。

各 ABI に複数の APK を構成するには、以下の Gradle DSL オプションを使用します。

enable(Groovy の場合)または isEnable(Kotlin スクリプトの場合)
この要素を true に設定すると、Gradle は定義された ABI に基づいて複数の APK を生成します。デフォルト値は false です。
exclude
Gradle で個別の APK を生成しない ABI のカンマ区切りリストを指定します。ほとんどの ABI 用の APK を生成するものの、アプリがサポートしていない ABI をいくつか除外する必要がある場合は、exclude を使用します。
reset()

ABI のデフォルト リストを消去します。include 要素と組み合わせて、追加する ABI を指定する場合にのみ使用します。

次のスニペットでは、reset() を呼び出してリストをクリアし、include を使用して、ABI のリストを x86 と x86_64 のみに設定しています。

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 のカンマ区切りのリストを指定します。ABI の正確なリストを指定するには、reset() と組み合わせてのみ使用します。

universalApk(Groovy の場合)または isUniversalApk(Kotlin スクリプトの場合)

true の場合、Gradle は ABI ごとの APK に加えてユニバーサル APK を生成します。ユニバーサル APK には、すべての ABI のコードとリソースが 1 つの APK に含まれています。デフォルト値は false です。

次の例では、ABI ごとに個別の APK(x86 と x86_64)を生成します。これを行うには、reset() を使用して ABI の空のリストから開始し、次に include を使用して、それぞれが APK を取得する ABI のリストを指定します。

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] パネルには、[Module] と [Active Build Variant] という 2 つの列が表示されます(図 1 を参照)。

ネイティブ / C++ コードを含まないプロジェクトの場合、[ビルド バリアント] パネルには 2 つの列が表示されます。
図 1. ネイティブ / C++ コードを含まないプロジェクトの場合、[ビルド バリアント] パネルには 2 つの列が表示されます。

モジュールの [Active Build Variant] 値により、デプロイされ、エディタで表示されるビルド バリアントが決定されます。バリアントを切り替えるには、モジュールの [Active Build Variant] セルをクリックし、リスト フィールドから目的のバリアントを選択します。

ネイティブ / C++ コードを含むプロジェクト

ネイティブ / C++ コードを使用するプロジェクトの場合、[Build Variants] パネルには、[Module]、[Active ビルド バリアント]、[Active ABI] の 3 つの列が表示されます(図 2)。

ネイティブ / C++ コードを含むプロジェクトの場合、[ビルド バリアント] パネルに [Active ABI] 列が追加されます。
図 2. ネイティブ / C++ コードを含むプロジェクトの場合、[ビルド バリアント] パネルに [ABI] 列が追加されます。

モジュールの [Active Build Variant] 値により、デプロイされ、エディタで表示されるビルド バリアントが決定されます。ネイティブ モジュールの場合は、[Active ABI] 値によってエディタが使用する ABI が決定されますが、デプロイされるものには影響しません。

ビルドタイプまたは ABI を変更するには:

  1. [ビルド バリアント] または [Active ABI] 列のセルをクリックします。
  2. リスト フィールドから、選択したバリアントまたは ABI を選択します。新しい同期が自動的に実行されます。

アプリまたはライブラリ モジュールのいずれかの列を変更すると、すべての依存行に変更が適用されます。

バージョン管理の構成

デフォルトでは、Gradle が複数の APK を生成すると、モジュール レベルの build.gradle ファイルまたは build.gradle.kts ファイルで指定されているとおり、各 APK に同じバージョン情報が設定されます。Google Play ストアでは、同じアプリの複数の APK に同じバージョン情報を指定することはできないため、Play ストアにアップロードする前に、各 APK に一意の versionCode を指定する必要があります。

モジュール レベルの build.gradle ファイルを構成して、APK ごとに versionCode をオーバーライドできます。複数の APK を構成する ABI ごとに一意の数値を割り当てるマッピングを作成することで、defaultConfig ブロックまたは productFlavors ブロック内で定義されたバージョン コードと、ABI に割り当てられた数値を組み合わせた値で、出力バージョン コードをオーバーライドできます。

次の例では、x86 ABI の APK の versionCode は 2004、x86_64 ABI の versionCode は 3004 になります。

バージョン コードを 1,000 などの大きな単位で増やすように設定すると、後でアプリを更新する必要が生じたときに、一意の バージョン コードを割り当てることができます。たとえば、後続の更新で defaultConfig.versionCode が 5 に増えた場合、Gradle は x86 APK に 2005 の versionCode を割り当て、x86_64 APK に 3005 の を割り当てます。

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]

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)

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 は、プロジェクトの build/outputs/apk/ ディレクトリに各 ABI の APK を作成します。

Gradle は、複数の APK を構成する ABI ごとに APK をビルドします。

たとえば、次の build.gradle スニペットでは、x86 ABI と x86_64 ABI 用に複数の APK をビルドできます。

Groovy

...
  splits {
    abi {
      enable true
      reset()
      include "x86", "x86_64"
    }
  }

Kotlin

...
  splits {
    abi {
      isEnable = true
      reset()
      include("x86", "x86_64")
    }
  }

この例の構成の出力には、以下の 4 つの APK が含まれます。

  • app-X86-release.apk: x86 ABI のコードとリソースが含まれます。
  • app-X86_64-release.apk: x86_64 ABI のコードとリソースが含まれます。

ABI に基づいて複数の APK をビルドする場合、build.gradle ファイル(Groovy の場合)の splits.abi ブロックで universalApk true を指定するか、build.gradle.kts ファイル(Kotlin スクリプトの場合)の splits.abi ブロックで isUniversalApk = true を指定すると、Gradle はすべての ABI のコードとリソースを含む APK のみを生成します。

APK ファイル名の形式

複数の APK をビルドする場合、Gradle は次のスキームを使用して APK ファイル名を生成します。

modulename-ABI-buildvariant.apk

スキームのコンポーネントは次のとおりです。

modulename
ビルドするモジュール名を指定します。
ABI
ABI 用の複数の APK が有効になっている場合、APK の ABI(x86 など)を指定します。
buildvariant
ビルド中のビルド バリアント(debug など)を指定します。