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

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

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

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

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

ビルドタイプを設定する

モジュール レベルの build.gradle.kts ファイルの android ブロック内でビルドタイプを作成して設定できます。新しいモジュールを作成すると、Android Studio により debug ビルドタイプと release ビルドタイプが自動的に作成されます。debug ビルドタイプはビルド構成ファイルに表示されませんが、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] をクリックするか、ツールバーのプロジェクトの同期アイコン をクリックします。Android Studio が設定のエラーを通知する場合は、問題の説明が記載された [Messages] ウィンドウが表示されます。

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

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

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

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

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

  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 をアプリにタグ付けします。ただし、「無料」版や「プロ」版など、異なるバージョンのアプリを作成して 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 サポートをご覧ください。AAB を使用した公開は、デフォルトで単一のバージョン コードとアプリケーション ID を使用する単一のアーティファクトを使用するため、影響を受けません。

ヒント: マニフェスト ファイルでアプリケーション 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 は、デバッグ ビルドタイプのソースセット ディレクトリを作成し、その中に 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 ブロック内に存在する必要があります。ソースファイルを再配置する必要はありません。Gradle に指定する必要があるのは、モジュール レベルの build.gradle.kts ファイルからの相対パスだけです。ここで、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 モジュールを作成し、ソースセット間で重複するコンテンツ ルートはサポートできないためです。

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

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

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

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

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

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

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

    注: 特定のビルド バリアントについて、同じ Kotlin クラスまたは Java クラスを定義しているソースセット ディレクトリが複数ある場合、Gradle はビルドエラーをスローします。たとえば、デバッグアプリをビルドするときに src/debug/Utility.ktsrc/main/Utility.kt の両方を定義することはできません。これは、Gradle がビルドプロセス中にこれらのディレクトリを確認し、「重複クラス」エラーをスローするためです。ビルドタイプごとに異なるバージョンの 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 アプリのパッケージ化と配布をご覧ください。