ビルド バリアントを設定する

このページでは、ビルド バリアントを設定して単一のプロジェクトからさまざまなバージョンのアプリを作成する方法と、依存関係と署名設定を適切に管理する方法について説明します。

各ビルド バリアントは、ビルド可能なさまざまなバージョンのアプリを表しています。たとえば、コンテンツが限定された無料版と、より多くのコンテンツを含む有料版の両方を作成できます。API レベルまたは他のデバイスのバリエーションに基づいて、異なるデバイスをターゲットとするアプリの異なるバージョンをビルドすることもできます。

ビルド バリアントは、Gradle が特定のルールセットを使用して、ビルドタイプとプロダクト フレーバー内で構成された設定、コード、リソースを組み合わせた結果です。ビルド バリアントは直接構成するものではなく、ビルド バリアントを形成するビルドタイプとプロダクト フレーバーを構成します。

たとえば、「demo」プロダクト フレーバーでは特定の機能やデバイス要件(カスタム ソースコード、リソース、最小 API レベルなど)を指定し、「debug」ビルドタイプではさまざまなビルド設定とパッケージ化設定(デバッグ オプションや署名鍵など)を適用します。この 2 つを組み合わせたビルド バリアントがアプリの「demoDebug」バージョンであり、「demo」プロダクト フレーバー、「debug」ビルドタイプ、main/ ソースセットに含まれる構成とリソースを組み合わせたものです。

ビルドタイプを設定する

ビルドタイプの作成と構成は、モジュール レベルの build.gradle.kts ファイルの android ブロック内で行うことができます。新しいモジュールを作成すると、Android Studio により debug ビルドタイプと release ビルドタイプが自動的に作成されます。デバッグ ビルドタイプはビルド構成ファイルに表示されませんが、Android Studio では debuggable true を使用して構成されます。これにより、安全な Android デバイスでアプリをデバッグし、汎用デバッグ キーストアでアプリ署名を設定できます。

特定の設定を追加または変更する場合、debug ビルドタイプを設定に追加することができます。次のサンプルでは、debug ビルドタイプに applicationIdSuffix を指定し、debug ビルドタイプの設定を使用して初期化される「staging」ビルドタイプを設定しています。

Kotlin

android {
    defaultConfig {
        manifestPlaceholders["hostName"] = "www.example.com"
        ...
    }
    buildTypes {
        getByName("release") {
            isMinifyEnabled = true
            proguardFiles(getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro")
        }

        getByName("debug") {
            applicationIdSuffix = ".debug"
            isDebuggable = true
        }

        /**
         * The `initWith` property lets you copy configurations from other build types,
         * then configure only the settings you want to change. This one copies the debug build
         * type, and then changes the manifest placeholder and application ID.
         */
        create("staging") {
            initWith(getByName("debug"))
            manifestPlaceholders["hostName"] = "internal.example.com"
            applicationIdSuffix = ".debugStaging"
        }
    }
}

Groovy

android {
    defaultConfig {
        manifestPlaceholders = [hostName:"www.example.com"]
        ...
    }
    buildTypes {
        release {
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }

        debug {
            applicationIdSuffix ".debug"
            debuggable true
        }

        /**
         * The `initWith` property lets you copy configurations from other build types,
         * then configure only the settings you want to change. This one copies the debug build
         * type, and then changes the manifest placeholder and application ID.
         */
        staging {
            initWith debug
            manifestPlaceholders = [hostName:"internal.example.com"]
            applicationIdSuffix ".debugStaging"
        }
    }
}

注: ビルド構成ファイルに変更を加えると、Android Studio は新しい設定のプロジェクトを同期するよう要求します。プロジェクトを同期するには、変更を加えたときに表示される通知バーで [Sync Now] をクリックするか、ツールバーの [Sync Project] をクリックします。Android Studio が設定のエラーを通知する場合は、問題の説明が記載された [Messages] ウィンドウが表示されます。

ビルドタイプで構成できるすべてのプロパティの詳細については、 BuildType リファレンスをご覧ください。

プロダクト フレーバーを設定する

プロダクト フレーバーの作成は、ビルドタイプの作成に似ています。ビルド構成の productFlavors ブロックにプロダクト フレーバーを追加し、必要な設定を含めます。 defaultConfig が実際に ProductFlavor クラスに属しているため、プロダクト フレーバーは defaultConfig と同じプロパティをサポートします。つまり、defaultConfig ブロックですべてのフレーバーの基本設定を提供でき、各フレーバーによって applicationId などのデフォルト値が変更される場合があります。アプリケーション ID について詳しくは、アプリケーション ID の設定をご覧ください。

注: main/ マニフェスト ファイルの package 属性を使用してパッケージ名を指定する必要もあります。また、ソースコード内でそのパッケージ名を使用して、R クラスを参照したり、関連するアクティビティやサービス登録を解決したりする必要があります。これにより、applicationId を使用して、ソースコードを変更することなく、パッケージ化および配布用の各プロダクト フレーバーに一意の ID を付与できます。

すべてのフレーバーは、名前の付いたフレーバー ディメンションに属していなければなりません。フレーバー ディメンションとは、プロダクト フレーバーのグループです。すべてのフレーバーをフレーバー ディメンションに割り当てる必要があります。割り当てない場合、次のビルドエラーが発生します。

  Error: All flavors must now belong to a named flavor dimension.
  The flavor 'flavor_name' is not assigned to a flavor dimension.

特定のモジュールで 1 つのフレーバー ディメンションのみが指定されている場合、Android Gradle プラグインはモジュールのすべてのフレーバーをそのディメンションに自動的に割り当てます。

次のサンプルコードでは、「version」という名前のフレーバー ディメンションを作成し、「demo」と「full」というプロダクト フレーバーを追加しています。これらのフレーバーでは、独自の applicationIdSuffixversionNameSuffix が用意されています。

Kotlin

android {
    ...
    defaultConfig {...}
    buildTypes {
        getByName("debug"){...}
        getByName("release"){...}
    }
    // Specifies one flavor dimension.
    flavorDimensions += "version"
    productFlavors {
        create("demo") {
            // Assigns this product flavor to the "version" flavor dimension.
            // If you are using only one dimension, this property is optional,
            // and the plugin automatically assigns all the module's flavors to
            // that dimension.
            dimension = "version"
            applicationIdSuffix = ".demo"
            versionNameSuffix = "-demo"
        }
        create("full") {
            dimension = "version"
            applicationIdSuffix = ".full"
            versionNameSuffix = "-full"
        }
    }
}

Groovy

android {
    ...
    defaultConfig {...}
    buildTypes {
        debug{...}
        release{...}
    }
    // Specifies one flavor dimension.
    flavorDimensions "version"
    productFlavors {
        demo {
            // Assigns this product flavor to the "version" flavor dimension.
            // If you are using only one dimension, this property is optional,
            // and the plugin automatically assigns all the module's flavors to
            // that dimension.
            dimension "version"
            applicationIdSuffix ".demo"
            versionNameSuffix "-demo"
        }
        full {
            dimension "version"
            applicationIdSuffix ".full"
            versionNameSuffix "-full"
        }
    }
}

注: Google Play で APK を使用して配信する以前のアプリ(2021 年 8 月より前に作成)がある場合、Google Play で複数 APK のサポートを使用してアプリを配布するには、すべてのバリアントに同じ applicationId 値を割り当て、各バリアントに異なる versionCode を割り当てます。Google Play でさまざまなバリアントのアプリを個別のアプリとして配布するには、各バリアントに異なる applicationId を割り当てる必要があります。

プロダクト フレーバーを作成して設定した後、通知バーで [Sync Now] をクリックします。同期が完了すると、Gradle はビルドタイプとプロダクト フレーバーに基づいてビルド バリアントを自動的に作成し、<product-flavor><Build-Type> に応じた名前を付けます。たとえば、「demo」と「full」のプロダクト フレーバーを作成し、ビルドタイプをデフォルトの「debug」と「release」のままにした場合、Gradle は次のビルド バリアントを作成します。

  • demoDebug
  • demoRelease
  • fullDebug
  • fullRelease

ビルドして実行するビルド バリアントを選択するには、[Build] > [Select Build Variant] に移動して、メニューからビルド バリアントを選択します。独自の機能やリソースで各ビルド バリアントをカスタマイズするには、このページで説明するように、ソースセットを作成して管理する必要があります。

ビルド バリアント向けにアプリケーション ID を変更する

アプリの APK または AAB をビルドすると、ビルドツールは、次の例に示すように、build.gradle.kts ファイルの defaultConfig ブロックで定義されたアプリケーション ID をアプリにタグ付けします。ただし、「free」バージョンや「pro」バージョンなど、さまざまなバージョンのアプリを作成して Google Play ストアで別々の掲載情報として表示する場合は、異なるアプリケーション ID を持つ個別のビルド バリアントを作成する必要があります。

この場合、各ビルド バリアントを個別のプロダクト フレーバーとして定義します。productFlavors ブロック内のフレーバーごとに、applicationId プロパティを再定義するか、以下の例に示すように applicationIdSuffix を使用してデフォルトのアプリケーション ID の末尾にセグメントを付加することができます。

Kotlin

android {
    defaultConfig {
        applicationId = "com.example.myapp"
    }
    productFlavors {
        create("free") {
            applicationIdSuffix = ".free"
        }
        create("pro") {
            applicationIdSuffix = ".pro"
        }
    }
}

Groovy

android {
    defaultConfig {
        applicationId "com.example.myapp"
    }
    productFlavors {
        free {
            applicationIdSuffix ".free"
        }
        pro {
            applicationIdSuffix ".pro"
        }
    }
}

これにより、「free」プロダクト フレーバーのアプリケーション ID は「com.example.myapp.free」となります。

また、以下の例に示すように、applicationIdSuffix を使用し、ビルドタイプに基づいてセグメントを末尾に付加することもできます。

Kotlin

android {
    ...
    buildTypes {
        getByName("debug") {
            applicationIdSuffix = ".debug"
        }
    }
}

Groovy

android {
    ...
    buildTypes {
        debug {
            applicationIdSuffix ".debug"
        }
    }
}

Gradle はプロダクト フレーバーの後にビルドタイプ設定を適用するため、「free debug」ビルド バリアントのアプリケーション ID は「com.example.myapp.free.debug」です。2 つのアプリで同じアプリケーション ID を使用することはできないため、この方法はデバッグビルドとリリースビルドの両方を同じデバイスに組み込みたい場合に便利です。

Google Play で APK を使用して配布する以前のアプリ(2021 年 8 月より前に作成)があり、同じアプリ掲載情報を使用して、API レベルなど異なるデバイス設定をターゲットとする複数の APK を配布する場合は、各ビルド バリアントに同じアプリケーション ID を使用し、各 APK に異なる versionCode を指定する必要があります。詳しくは、複数 APK サポートをご覧ください。デフォルトで単一のバージョン コードとアプリケーション ID を使用する単一のアーティファクトが使用されるため、AAB を使用した公開は影響を受けません。

ヒント: マニフェスト ファイルでアプリケーション ID を参照する必要がある場合は、任意のマニフェスト属性で ${applicationId} プレースホルダを使用できます。Gradle はビルド時にこのタグを実際のアプリケーション ID に置き換えます。詳細については、マニフェストにビルド変数を挿入するをご覧ください。

複数のプロダクト フレーバーとフレーバー ディメンションを組み合わせる

複数のプロダクト フレーバーの設定を組み合わせることが必要となる場合があります。たとえば、API レベルに応じて「full」と「demo」のプロダクト フレーバーで異なる設定を作成する必要がある場合などです。これを行うには、Android Gradle プラグインを使用して、フレーバー ディメンションとしてプロダクト フレーバーの複数のグループを作成します。

アプリをビルドする際、Gradle は定義された各フレーバー ディメンションに含まれるプロダクト フレーバー設定を組み合わせ、さらにビルドタイプ設定を使用して最終的なビルド バリアントを作成します。Gradle は、同じフレーバー ディメンションに属するプロダクト フレーバーを結合しません。

次のコードサンプルでは、 flavorDimensions プロパティを使用して「mode」フレーバー ディメンションを作成し、「full」プロダクト フレーバーと「demo」プロダクト フレーバーをグループ化しています。また、「api」フレーバー ディメンションを作成し、API レベルに基づいてプロダクト フレーバー設定をグループ化しています。

Kotlin

android {
  ...
  buildTypes {
    getByName("debug") {...}
    getByName("release") {...}
  }

  // Specifies the flavor dimensions you want to use. The order in which you
  // list the dimensions determines their priority, from highest to lowest,
  // when Gradle merges variant sources and configurations. You must assign
  // each product flavor you configure to one of the flavor dimensions.
  flavorDimensions += listOf("api", "mode")

  productFlavors {
    create("demo") {
      // Assigns this product flavor to the "mode" flavor dimension.
      dimension = "mode"
      ...
    }

    create("full") {
      dimension = "mode"
      ...
    }

    // Configurations in the "api" product flavors override those in "mode"
    // flavors and the defaultConfig block. Gradle determines the priority
    // between flavor dimensions based on the order in which they appear next
    // to the flavorDimensions property, with the first dimension having a higher
    // priority than the second, and so on.
    create("minApi24") {
      dimension = "api"
      minSdk = 24
      // To ensure the target device receives the version of the app with
      // the highest compatible API level, assign version codes in increasing
      // value with API level.
      versionCode = 30000 + (android.defaultConfig.versionCode ?: 0)
      versionNameSuffix = "-minApi24"
      ...
    }

    create("minApi23") {
      dimension = "api"
      minSdk = 23
      versionCode = 20000  + (android.defaultConfig.versionCode ?: 0)
      versionNameSuffix = "-minApi23"
      ...
    }

    create("minApi21") {
      dimension = "api"
      minSdk = 21
      versionCode = 10000  + (android.defaultConfig.versionCode ?: 0)
      versionNameSuffix = "-minApi21"
      ...
    }
  }
}
...

Groovy

android {
  ...
  buildTypes {
    debug {...}
    release {...}
  }

  // Specifies the flavor dimensions you want to use. The order in which you
  // list the dimensions determines their priority, from highest to lowest,
  // when Gradle merges variant sources and configurations. You must assign
  // each product flavor you configure to one of the flavor dimensions.
  flavorDimensions "api", "mode"

  productFlavors {
    demo {
      // Assigns this product flavor to the "mode" flavor dimension.
      dimension "mode"
      ...
    }

    full {
      dimension "mode"
      ...
    }

    // Configurations in the "api" product flavors override those in "mode"
    // flavors and the defaultConfig block. Gradle determines the priority
    // between flavor dimensions based on the order in which they appear next
    // to the flavorDimensions property, with the first dimension having a higher
    // priority than the second, and so on.
    minApi24 {
      dimension "api"
      minSdkVersion 24
      // To ensure the target device receives the version of the app with
      // the highest compatible API level, assign version codes in increasing
      // value with API level.

      versionCode 30000 + android.defaultConfig.versionCode
      versionNameSuffix "-minApi24"
      ...
    }

    minApi23 {
      dimension "api"
      minSdkVersion 23
      versionCode 20000  + android.defaultConfig.versionCode
      versionNameSuffix "-minApi23"
      ...
    }

    minApi21 {
      dimension "api"
      minSdkVersion 21
      versionCode 10000  + android.defaultConfig.versionCode
      versionNameSuffix "-minApi21"
      ...
    }
  }
}
...

Gradle で作成されるビルド バリアントの数は、各フレーバー ディメンション内のフレーバーの数と、設定したビルドタイプをすべて乗算した数となります。Gradle が各ビルド バリアントまたは対応するアーティファクトに名前を付けると、優先度の高いフレーバー ディメンションに属するプロダクト フレーバーが最初に表示され、その後に優先度の低いディメンションのプロダクト フレーバー、ビルドタイプの順に表示されます。

前述のビルド構成を例にとると、Gradle は次の命名スキームで合計 12 個のビルド バリアントを作成します。

  • ビルド バリアント: [minApi24, minApi23, minApi21][Demo, Full][Debug, Release]
  • 対応する APK: app-[minApi24, minApi23, minApi21]-[demo, full]-[debug, release].apk
  • 次に例を示します。
    ビルド バリアント: minApi24DemoDebug
    対応する APK: app-minApi24-demo-debug.apk

個別のプロダクト フレーバーおよびビルド バリアント用のソースセット ディレクトリの作成に加え、プロダクト フレーバーの各組み合わせに対してもソースセット ディレクトリを作成することが可能です。たとえば、Java ソースを作成して src/demoMinApi24/java/ ディレクトリに追加すると、Gradle はこの 2 つのプロダクト フレーバーを組み合わせたバリアントのビルド時にのみ、これらのソースを使用します。

プロダクト フレーバーの組み合わせに対して作成したソースセットは、個別の各プロダクト フレーバーに属するソースセットより優先されます。ソースセットの詳細と Gradle がリソースを統合する仕組みについては、ソースセットを作成するをご覧ください。

バリアントのフィルタリング

Gradle は、設定されたプロダクト フレーバーとビルドタイプのすべての可能な組み合わせでビルド バリアントを作成します。ただし、不要なビルド バリアントや、プロジェクトのコンテキストでは意味をなさないビルド バリアントも存在する可能性があります。特定のビルド バリアント設定を削除するには、モジュール レベルの build.gradle.kts ファイル内にバリアント フィルタを作成します。

例として前のセクションのビルド構成を使用し、アプリのデモバージョンでは API レベル 23 以上のみをサポートすると仮定します。variantFilter ブロックを使用して、「minApi21」と「demo」のプロダクト フレーバーを組み合わせたすべてのビルド バリアント設定を除外できます。

Kotlin

android {
  ...
  buildTypes {...}

  flavorDimensions += listOf("api", "mode")
  productFlavors {
    create("demo") {...}
    create("full") {...}
    create("minApi24") {...}
    create("minApi23") {...}
    create("minApi21") {...}
  }
}

androidComponents {
    beforeVariants { variantBuilder ->
        // To check for a certain build type, use variantBuilder.buildType == "<buildType>"
        if (variantBuilder.productFlavors.containsAll(listOf("api" to "minApi21", "mode" to "demo"))) {
            // Gradle ignores any variants that satisfy the conditions above.
            variantBuilder.enable = false
        }
    }
}
...

Groovy

android {
  ...
  buildTypes {...}

  flavorDimensions "api", "mode"
  productFlavors {
    demo {...}
    full {...}
    minApi24 {...}
    minApi23 {...}
    minApi21 {...}
  }

  variantFilter { variant ->
      def names = variant.flavors*.name
      // To check for a certain build type, use variant.buildType.name == "<buildType>"
      if (names.contains("minApi21") && names.contains("demo")) {
          // Gradle ignores any variants that satisfy the conditions above.
          setIgnore(true)
      }
  }
}
...

ビルド構成にバリアント フィルタを追加して、通知バーの [Sync Now] をクリックすると、指定した条件を満たすビルド バリアントが Gradle によって無視されます。メニューバーから [Build] > [Select Build Variant] をクリックするか、ツール ウィンドウ バーで [Build Variants] をクリックしても、ビルド バリアントがメニューに表示されなくなりました。

ソースセットを作成する

Android Studio はデフォルトで、全ビルド バリアントで共有するすべての要素の main/ ソースセットとディレクトリを作成しますが、ただし、新しいソースセットを作成して、特定のビルドタイプ、プロダクト フレーバー、プロダクト フレーバーの組み合わせ(フレーバー ディメンションを使用している場合)、ビルド バリアントごとに Gradle でコンパイルおよびパッケージ化するファイルを正確に制御できます。

たとえば、main/ ソースセットで基本的な機能を定義してプロダクト フレーバーのソースセットでクライアントごとにアプリのブランディングを変えることや、debug ビルドタイプを使用するビルド バリアント専用の特別なパーミッションやログ機能を含めることが可能です。

Gradle は、ソースセット ファイルとディレクトリが main/ ソースセットと同様に特定の方法で編成されていることを前提としています。たとえば、「debug」ビルドタイプに固有の Kotlin または Java のクラスファイルは、src/debug/kotlin/ ディレクトリまたは src/debug/java/ ディレクトリに配置する必要があります。

Android Gradle プラグインには、ビルドタイプ、プロダクト フレーバー、ビルド バリアントごとにファイルを整理する方法を示す便利な Gradle タスクが用意されています。たとえば、以下のタスク出力サンプルは、Gradle で「debug」ビルドタイプの特定のファイルがあると予想される場所を示しています。

------------------------------------------------------------
Project :app
------------------------------------------------------------

...

debug
----
Compile configuration: debugCompile
build.gradle name: android.sourceSets.debug
Java sources: [app/src/debug/java]
Kotlin sources: [app/src/debug/kotlin, app/src/debug/java]
Manifest file: app/src/debug/AndroidManifest.xml
Android resources: [app/src/debug/res]
Assets: [app/src/debug/assets]
AIDL sources: [app/src/debug/aidl]
RenderScript sources: [app/src/debug/rs]
JNI sources: [app/src/debug/jni]
JNI libraries: [app/src/debug/jniLibs]
Java-style resources: [app/src/debug/resources]

この出力を表示する手順は次のとおりです。

  1. ツール ウィンドウ バーで [Gradle] をクリックします。
  2. [MyApplication] > [Tasks] > [android] に移動して、[sourceSets] をダブルクリックします。

    Tasks フォルダを表示するには、Gradle で同期中にタスクリストを作成できるようにする必要があります。手順は次のとおりです。

    1. [File] > [Settings] > [Experimental](macOS では [Android Studio] > [Settings] > [Experimental])をクリックします。
    2. [Do not build Gradle task list during Gradle sync] をオフにします。
  3. Gradle がタスクを実行すると、[Run] ウィンドウが開いて出力が表示されます。

注: タスク出力には、アプリのテストを実行するために使用するファイルのソースセット(test/androidTest/ など)のテスト ソースセットを整理する方法も示されます。

新しいビルド バリアントを作成する際に、Android Studio ではソースセット ディレクトリは作成されませんが、便利なオプションがいくつか提供されます。たとえば、「debug」ビルドタイプ用の java/ ディレクトリを作成するには次の手順で操作します。

  1. [Project] ペインを開き、ペインの上部にあるメニューから [Project] ビューを選択します。
  2. MyProject/app/src/ に移動します。
  3. src ディレクトリを右クリックして、[New] > [Directory] を選択します。
  4. [Gradle Source Sets] のメニューから、[full/java] を選択します。
  5. Enter キーを押します。

Android Studio は、debug ビルドタイプのソースセット ディレクトリを作成し、その中に java/ ディレクトリを作成します。または、特定のビルド バリアント用の新しいファイルをプロジェクトに追加するときに、Android Studio によってディレクトリを作成することもできます。

たとえば、「debug」ビルドタイプの values.xml ファイルは次の手順で作成します。

  1. [Project] ペインで src ディレクトリを右クリックし、[New] > [XML] > [Values XML File] を選択します。
  2. XML ファイルの名前を入力するか、デフォルトの名前のままにします。
  3. [Target Source Set] の横にあるメニューから、[debug] を選択します。
  4. [Finish] をクリックします。

「debug」ビルドタイプがターゲット ソースセットとして指定されているため、Android Studio は XML ファイルを作成するときに必要となるディレクトリを自動的に作成します。作成されたディレクトリ構造は図 1 のようになります。

図 1. 「debug」ビルドタイプ用の新しいソースセット ディレクトリ。

アクティブなソースセットのアイコンには、アクティブであることを示す緑色のインジケーターが表示されます。debug ソースセットには、main ソースセットにマージされることを示すために、末尾に [main] が付いています。

同じ手順で、src/demo/ などプロダクト フレーバーのソースセット ディレクトリや、src/demoDebug/ などビルド バリアントのソースセット ディレクトリを作成できます。また、src/androidTestDemoDebug/ など特定のビルド バリアントを対象とするテスト ソースセットも作成できます。詳細については、テスト ソースセットをご覧ください。

デフォルトのソースセットの構成を変更する

前のセクションのソースセットの作成で説明したように、Gradle で想定されているデフォルトのソースセット ファイル構造に整理されていないソースがある場合は、 sourceSets ブロックを使用して、Gradle がソースセットの各コンポーネントのファイルを収集する際に参照する場所を変更できます。

sourceSets ブロックは android ブロックに含める必要があります。ソースファイルを再配置する必要はありません。必要なのは、モジュール レベルの build.gradle.kts ファイルからの相対パスを Gradle に指定するだけです。ここで、Gradle は各ソースセット コンポーネントのファイルを見つけることができます。設定可能なコンポーネントと、それらを複数のファイルやディレクトリにマッピングできるかどうかについては、Android Gradle プラグイン API リファレンスをご覧ください。

次のコードサンプルでは、app/other/ ディレクトリのソースを main ソースセットの特定のコンポーネントにマッピングし、androidTest ソースセットのルート ディレクトリを変更します。

Kotlin

android {
  ...
  // Encapsulates configurations for the main source set.
  sourceSets.getByName("main") {
    // Changes the directory for Java sources. The default directory is
    // 'src/main/java'.
    java.setSrcDirs(listOf("other/java"))

    // If you list multiple directories, Gradle uses all of them to collect
    // sources. Because Gradle gives these directories equal priority, if
    // you define the same resource in more than one directory, you receive an
    // error when merging resources. The default directory is 'src/main/res'.
    res.setSrcDirs(listOf("other/res1", "other/res2"))

    // Note: Avoid specifying a directory that is a parent to one
    // or more other directories you specify. For example, avoid the following:
    // res.srcDirs = ['other/res1', 'other/res1/layouts', 'other/res1/strings']
    // Specify either only the root 'other/res1' directory or only the
    // nested 'other/res1/layouts' and 'other/res1/strings' directories.

    // For each source set, you can specify only one Android manifest.
    // By default, Android Studio creates a manifest for your main source
    // set in the src/main/ directory.
    manifest.srcFile("other/AndroidManifest.xml")
    ...
  }

  // Create additional blocks to configure other source sets.
  sourceSets.getByName("androidTest") {
      // If all the files for a source set are located under a single root
      // directory, you can specify that directory using the setRoot property.
      // When gathering sources for the source set, Gradle looks only in locations
      // relative to the root directory you specify. For example, after applying the
      // configuration below for the androidTest source set, Gradle looks for Java
      // sources only in the src/tests/java/ directory.
      setRoot("src/tests")
      ...
  }
}
...

Groovy

android {
  ...
  sourceSets {
    // Encapsulates configurations for the main source set.
    main {
      // Changes the directory for Java sources. The default directory is
      // 'src/main/java'.
      java.srcDirs = ['other/java']

      // If you list multiple directories, Gradle uses all of them to collect
      // sources. Because Gradle gives these directories equal priority, if
      // you define the same resource in more than one directory, you receive an
      // error when merging resources. The default directory is 'src/main/res'.
      res.srcDirs = ['other/res1', 'other/res2']

      // Note: Avoid specifying a directory that is a parent to one
      // or more other directories you specify. For example, avoid the following:
      // res.srcDirs = ['other/res1', 'other/res1/layouts', 'other/res1/strings']
      // Specify either only the root 'other/res1' directory or only the
      // nested 'other/res1/layouts' and 'other/res1/strings' directories.

      // For each source set, you can specify only one Android manifest.
      // By default, Android Studio creates a manifest for your main source
      // set in the src/main/ directory.
      manifest.srcFile 'other/AndroidManifest.xml'
      ...
    }

    // Create additional blocks to configure other source sets.
    androidTest {

      // If all the files for a source set are located under a single root
      // directory, you can specify that directory using the setRoot property.
      // When gathering sources for the source set, Gradle looks only in locations
      // relative to the root directory you specify. For example, after applying the
      // configuration below for the androidTest source set, Gradle looks for Java
      // sources only in the src/tests/java/ directory.
      setRoot 'src/tests'
      ...
    }
  }
}
...

1 つのソース ディレクトリは 1 つのソースセットにのみ所属できます。たとえば、test ソースセットと androidTest ソースセットで同じテストソースを共有することはできません。これは、Android Studio がソースセットごとに別々の IntelliJ モジュールを作成し、ソースセット間で重複するコンテンツ ルートをサポートできないためです。

ソースセットを使用してビルドする

ソースセット ディレクトリには、特定の設定でのみパッケージ化するコードやリソースを入れておくことができます。たとえば、「demo」プロダクト フレーバーと「debug」ビルドタイプのクロス積である「demoDebug」ビルド バリアントをビルドする場合、Gradle はこれらのディレクトリを参照して次の優先順位を付与します。

  1. src/demoDebug/(ビルド バリアントのソースセット)
  2. src/debug/(ビルドタイプのソースセット)
  3. src/demo/(プロダクト フレーバーのソースセット)
  4. src/main/(メインのソースセット)

プロダクト フレーバーの組み合わせに対して作成されたソースセットには、すべてのフレーバー ディメンションを含める必要があります。たとえば、ビルド バリアント ソースセットは、ビルドタイプとすべてのフレーバー ディメンションを組み合わせたものである必要があります。複数のフレーバー ディメンション(すべてではない)を対象とするフォルダを含むコードとリソースのマージはサポートされていません。

複数のプロダクト フレーバーを組み合わせる場合、プロダクト フレーバーの優先順位は、各プロダクト フレーバーが属するフレーバー ディメンションによって決まります。 android.flavorDimensions プロパティでフレーバー ディメンションを一覧表示すると、最初に指定したフレーバー ディメンションに属するプロダクト フレーバーが 2 番目のフレーバー ディメンションに属するプロダクト フレーバーの優先順位が 2 番目のフレーバー ディメンションに属するプロダクト フレーバーより優先度が高くなります。また、プロダクト フレーバーの組み合わせに対して作成したソースセットは、個々のプロダクト フレーバーに属するソースセットよりも優先されます。

Gradle がコードとリソースを組み合わせる際に、優先度の高いソースセットは、優先順位によって決定されます。demoDebug/ ソースセット ディレクトリにはそのビルド バリアント固有のファイルが含まれる可能性が高いため、debug/ で定義されているファイルが demoDebug/ に含まれている場合、Gradle は demoDebug/ ソースセットのファイルを使用します。Gradle では同様に、ビルドタイプとプロダクト フレーバーのソースセットのファイルに対して main/ にある同じファイルよりも高い優先度を付与します。Gradle では、以下のビルドルールを適用するときに、この優先順位が考慮されます。

  • kotlin/ ディレクトリまたは java/ ディレクトリ内のすべてのソースコードは、まとめてコンパイルされて単一の出力を生成します。

    注: 特定のビルド バリアントについて、同じ Kotlin クラスまたは Java クラスを定義している複数のソースセット ディレクトリがある場合、Gradle はビルドエラーをスローします。たとえば、デバッグアプリをビルドするときに、src/debug/Utility.ktsrc/main/Utility.kt の両方を定義することはできません。これは、Gradle がビルドプロセス中にこの両方のディレクトリを参照し、「duplicate class」エラーをスローするためです。ビルドタイプごとに異なるバージョンの Utility.kt が必要な場合は、各ビルドタイプで独自のバージョンのファイルを定義し、main/ ソースセットに含めないようにする必要があります。

  • 複数のマニフェストは単一のマニフェストにマージされ、優先度は前の例のリストと同じ順序で指定されます。つまり、ビルドタイプのマニフェスト設定により、プロダクト フレーバーなどのマニフェスト設定がオーバーライドされます。詳しくは、マニフェストのマージをご覧ください。
  • values/ ディレクトリ内のファイルはマージされます。strings.xml ファイルが 2 つであるなど、2 つのファイルの名前が同じ場合は、前の例のリストと同じ優先順位が付与されます。つまり、ビルドタイプのソースセットのファイルで定義されている値により、プロダクト フレーバーなどの同じファイルで定義されている値がオーバーライドされます。
  • res/asset/ ディレクトリのリソースは一緒にパッケージ化されます。2 つ以上のソースセットで同じ名前のリソースが定義されている場合、前の例のリストと同じ優先順位が付与されます。
  • Gradle は、アプリをビルドするときに、ライブラリ モジュールの依存関係に含まれているリソースとマニフェストを最も低い優先度にします。

依存関係の宣言

特定のビルド バリアントまたはテスト ソースセットの依存関係を構成するには、次の例に示すように、ビルド バリアントまたはテスト ソースセットの名前を Implementation キーワードの前に付けます。

Kotlin

dependencies {
    // Adds the local "mylibrary" module as a dependency to the "free" flavor.
    "freeImplementation"(project(":mylibrary"))

    // Adds a remote binary dependency only for local tests.
    testImplementation("junit:junit:4.12")

    // Adds a remote binary dependency only for the instrumented test APK.
    androidTestImplementation("com.android.support.test.espresso:espresso-core:3.5.1")
}

Groovy

dependencies {
    // Adds the local "mylibrary" module as a dependency to the "free" flavor.
    freeImplementation project(":mylibrary")

    // Adds a remote binary dependency only for local tests.
    testImplementation 'junit:junit:4.12'

    // Adds a remote binary dependency only for the instrumented test APK.
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.5.1'
}

依存関係の設定について詳しくは、ビルド依存関係の追加をご覧ください。

バリアント認識型の依存関係管理を使用する

Android Gradle プラグイン 3.0.0 以降には、ライブラリの使用時にバリアントを自動的に照合する新しい依存関係メカニズムが含まれています。つまり、アプリの debug バリアントは自動的にライブラリの debug バリアントを使用するというようになります。これはフレーバーを使用する場合にも機能します。アプリの freeDebug バリアントはライブラリの freeDebug バリアントを消費します。

プラグインがバリアントと正確にマッチングするためには、直接マッチングが不可能な場合に、次のセクションで説明するようにマッチング用のフォールバックを提供する必要があります。

たとえば、アプリが「staging」というビルドタイプを構成しているが、そのライブラリ依存関係の 1 つに「staging」が含まれていないとします。プラグインでアプリの「staging」バージョンをビルドしようとしたときに、どのバージョンのライブラリを使用すべきかを判断できません。そのため、次のようなエラー メッセージが表示されます。

Error:Failed to resolve: Could not resolve project :mylibrary.
Required by:
    project :app

バリアントのマッチングに関連するビルドエラーの解決

このプラグインには、アプリと依存関係の直接的なバリアント マッチングが不可能な状況において、Gradle が解決する方法を制御する DSL 要素が含まれています。

バリアント認識型の依存関係マッチングに関連する問題と、DSL プロパティを使用してそれらを解決する方法を以下に示します。

  • ライブラリ依存関係に含まれていないビルドタイプがアプリに含まれている。

    たとえば、アプリに「staging」ビルドタイプが含まれているのに、依存関係に「debug」ビルドタイプと「release」ビルドタイプしか含まれていない場合などです。

    なお、アプリに含まれていないビルドタイプがライブラリ依存関係に含まれている場合は、特に問題ありません。プラグインが依存関係からそのビルドタイプをリクエストすることはないためです。

    特定のビルドタイプの代わりに一致するビルドタイプを指定するには、次のように matchingFallbacks を使用します。

    Kotlin

    // In the app's build.gradle.kts file.
    android {
        buildTypes {
            getByName("debug") {}
            getByName("release") {}
            create("staging") {
                // Specifies a sorted list of fallback build types that the
                // plugin can try to use when a dependency does not include a
                // "staging" build type. You may specify as many fallbacks as you
                // like, and the plugin selects the first build type that's
                // available in the dependency.
                matchingFallbacks += listOf("debug", "qa", "release")
            }
        }
    }

    Groovy

    // In the app's build.gradle file.
    android {
        buildTypes {
            debug {}
            release {}
            staging {
                // Specifies a sorted list of fallback build types that the
                // plugin can try to use when a dependency does not include a
                // "staging" build type. You may specify as many fallbacks as you
                // like, and the plugin selects the first build type that's
                // available in the dependency.
                matchingFallbacks = ['debug', 'qa', 'release']
            }
        }
    }
    
  • アプリとそのライブラリ依存関係の両方に存在する特定のフレーバー ディメンションにおいて、ライブラリに含まれていないフレーバーがアプリに含まれている。

    たとえば、アプリとそのライブラリ依存関係の両方に「tier」フレーバー ディメンションが存在するが、ただし、アプリの「tier」ディメンションには「free」と「paid」というフレーバーが含まれていますが、依存関係には、同じディメンションの「demo」と「paid」というフレーバーしか含まれていません。

    なお、アプリとそのライブラリ依存関係の両方に存在する特定のフレーバー ディメンションについては、アプリに含まれていないプロダクト フレーバーがライブラリに含まれていても問題ありません。プラグインが依存関係からそのフレーバーをリクエストすることはないためです。

    次のように、matchingFallbacks を使用してアプリの「free」プロダクト フレーバーの代わりにマッチングするフレーバーを指定します。

    Kotlin

    // In the app's build.gradle.kts file.
    android {
        defaultConfig{
        // Don't configure matchingFallbacks in the defaultConfig block.
        // Instead, specify fallbacks for a given product flavor in the
        // productFlavors block, as shown below.
      }
        flavorDimensions += "tier"
        productFlavors {
            create("paid") {
                dimension = "tier"
                // Because the dependency already includes a "paid" flavor in its
                // "tier" dimension, you don't need to provide a list of fallbacks
                // for the "paid" flavor.
            }
            create("free") {
                dimension = "tier"
                // Specifies a sorted list of fallback flavors that the plugin
                // can try to use when a dependency's matching dimension does
                // not include a "free" flavor. Specify as many
                // fallbacks as you like; the plugin selects the first flavor
                // that's available in the dependency's "tier" dimension.
                matchingFallbacks += listOf("demo", "trial")
            }
        }
    }
    

    Groovy

    // In the app's build.gradle file.
    android {
        defaultConfig{
        // Don't configure matchingFallbacks in the defaultConfig block.
        // Instead, specify fallbacks for a given product flavor in the
        // productFlavors block, as shown below.
      }
        flavorDimensions 'tier'
        productFlavors {
            paid {
                dimension 'tier'
                // Because the dependency already includes a "paid" flavor in its
                // "tier" dimension, you don't need to provide a list of fallbacks
                // for the "paid" flavor.
            }
            free {
                dimension 'tier'
                // Specifies a sorted list of fallback flavors that the plugin
                // can try to use when a dependency's matching dimension does
                // not include a "free" flavor. Specify as many
                // fallbacks as you like; the plugin selects the first flavor
                // that's available in the dependency's "tier" dimension.
                matchingFallbacks = ['demo', 'trial']
            }
        }
    }
    
  • アプリに含まれていないフレーバー ディメンションがライブラリ依存関係に含まれている。

    たとえば、ライブラリ依存関係には「minApi」ディメンション用のフレーバーが含まれているが、アプリには「tier」ディメンション用のフレーバーしか含まれていない場合などです。アプリの「freeDebug」バージョンをビルドする場合、プラグインは「minApi23Debug」と「minApi18Debug」のどちらのバージョンの依存関係を使用すべきかを判断できません。

    なお、ライブラリ依存関係に含まれていないフレーバー ディメンションがアプリに含まれている場合は、特に問題ありません。プラグインでは、ライブラリ依存関係に存在するディメンションのみのフレーバーをマッチングするためです。たとえば、依存関係に ABI のディメンションが含まれていない場合、アプリの「freeX86Debug」バージョンは「freeDebug」バージョンの依存関係を使用します。

    次の例に示すように、defaultConfig ブロックで missingDimensionStrategy を使用して、欠落している各ディメンションからプラグインが選択するデフォルトのフレーバーを指定します。また、productFlavors ブロック内で選択肢をオーバーライドして、存在しないディメンションに対してフレーバーごとに異なるマッチング方針を指定することもできます。

    Kotlin

    // In the app's build.gradle.kts file.
    android {
        defaultConfig{
        // Specifies a sorted list of flavors that the plugin can try to use from
        // a given dimension. This tells the plugin to select the "minApi18" flavor
        // when encountering a dependency that includes a "minApi" dimension.
        // You can include additional flavor names to provide a
        // sorted list of fallbacks for the dimension.
        missingDimensionStrategy("minApi", "minApi18", "minApi23")
        // Specify a missingDimensionStrategy property for each
        // dimension that exists in a local dependency but not in your app.
        missingDimensionStrategy("abi", "x86", "arm64")
        }
        flavorDimensions += "tier"
        productFlavors {
            create("free") {
                dimension = "tier"
                // You can override the default selection at the product flavor
                // level by configuring another missingDimensionStrategy property
                // for the "minApi" dimension.
                missingDimensionStrategy("minApi", "minApi23", "minApi18")
            }
            create("paid") {}
        }
    }
    

    Groovy

    // In the app's build.gradle file.
    android {
        defaultConfig{
        // Specifies a sorted list of flavors that the plugin can try to use from
        // a given dimension. This tells the plugin to select the "minApi18" flavor
        // when encountering a dependency that includes a "minApi" dimension.
        // You can include additional flavor names to provide a
        // sorted list of fallbacks for the dimension.
        missingDimensionStrategy 'minApi', 'minApi18', 'minApi23'
        // Specify a missingDimensionStrategy property for each
        // dimension that exists in a local dependency but not in your app.
        missingDimensionStrategy 'abi', 'x86', 'arm64'
        }
        flavorDimensions 'tier'
        productFlavors {
            free {
                dimension 'tier'
                // You can override the default selection at the product flavor
                // level by configuring another missingDimensionStrategy property
                // for the 'minApi' dimension.
                missingDimensionStrategy 'minApi', 'minApi23', 'minApi18'
            }
            paid {}
        }
    }
    

詳細については、Android Gradle プラグインの DSL リファレンスの matchingFallbacksmissingDimensionStrategy をご覧ください。

署名設定を行う

Gradle は、リリースビルドの署名設定を明示的に定義しない限り、リリースビルドの APK または AAB に署名しません。署名鍵がまだない場合は、Android Studio を使用してアップロード鍵とキーストアを生成します。

Gradle ビルド設定を使用して release ビルドタイプの署名設定を手動で設定するには、次の手順を行います。

  1. キーストアを作成します。キーストアは一連の秘密鍵を含むバイナリ ファイルです。キーストアは安全な場所に保管する必要があります。
  2. 秘密鍵を作成します。秘密鍵は、配布するアプリへの署名に使用されます。アプリに含められたり、許可されていない第三者に開示されたりすることはありません。
  3. 署名設定をモジュール レベルの build.gradle.kts ファイルに追加します。

    Kotlin

    ...
    android {
        ...
        defaultConfig {...}
        signingConfigs {
            create("release") {
                storeFile = file("myreleasekey.keystore")
                storePassword = "password"
                keyAlias = "MyReleaseKey"
                keyPassword = "password"
            }
        }
        buildTypes {
            getByName("release") {
                ...
                signingConfig = signingConfigs.getByName("release")
            }
        }
    }

    Groovy

    ...
    android {
        ...
        defaultConfig {...}
        signingConfigs {
            release {
                storeFile file("myreleasekey.keystore")
                storePassword "password"
                keyAlias "MyReleaseKey"
                keyPassword "password"
            }
        }
        buildTypes {
            release {
                ...
                signingConfig signingConfigs.release
            }
        }
    }

注: リリースキーとキーストアのパスワードをビルドファイルに含めることは、セキュリティ上の理由からおすすめできません。代わりに、これらのパスワードを環境変数から取得するか、ビルドプロセスでパスワードが要求されるようにビルドファイルを構成します。

これらのパスワードを環境変数から取得するには:

Kotlin

storePassword = System.getenv("KSTOREPWD")
keyPassword = System.getenv("KEYPWD")

Groovy

storePassword System.getenv("KSTOREPWD")
keyPassword System.getenv("KEYPWD")

また、ローカルのプロパティ ファイルからキーストアを読み込むこともできます。セキュリティ上の理由から、このファイルをソース管理に追加しないでください。代わりに、デベロッパーごとにローカルで設定します。詳細については、 ビルドファイルから署名情報を削除するをご覧ください。

このプロセスが完了したら、アプリを配布して Google Play で公開できます。

警告: キーストアと秘密鍵は安全な場所に保管し、セキュア バックアップを取るようにしてください。Play アプリ署名を使用していて、アップロード鍵を紛失した場合は、Play Console からリセットをリクエストできます。 Play アプリ署名を使用せずにアプリを公開する場合(2021 年 8 月より前に作成したアプリの場合)、アプリ署名鍵を紛失すると、それ以降アプリを更新できなくなります。アプリのすべてのバージョンに同じ署名鍵で署名する必要があるためです。

Wear OS アプリへの署名

Wear OS アプリを公開する場合は、スマートウォッチ APK とオプションのスマートフォン APK の両方を同じ鍵で署名する必要があります。Wear OS アプリのパッケージ化と署名について詳しくは、Wear アプリのパッケージ化と配布をご覧ください。