Android開発におけるBuild Variantとは、build typeとproduct flavorの組み合わせであり、APKまたはAABのビルド方法(パラメータ、リソース、コード)を決定します。各ビルドバリアントは、独自のapplicationId、署名キー、および依存関係を持つ独立したGradle設定を表します。Google Android Developers、2025によると、Build Variantsを適切に設定すると、各バリアントの不要なリソースを除外することで、ビルド時間を最大40%短縮できます。ビルドバリアントシステムは、最新のAndroidプロジェクトにおける設定管理の基盤です。
重要なポイント
Build Variantとは、1つのBuild Typeと1つのProduct Flavorを組み合わせた結果です。プロジェクトでProduct Flavorsが定義されていない場合、Build VariantはBuild Typeと一致します。Gradleは、すべてのFlavorDimensions、Product Flavors、Build Typesのデカルト積として、バリアントの完全なセットを自動生成します。例えば、free/paidフレーバーとdebug/releaseタイプの場合、freeDebug、freeRelease、paidDebug、paidReleaseの4つのバリアントが作成されます。
各Build Variantには、<Flavor><Type>形式の独自の名前が付けられます(フレーバーは大文字で始まります)。Gradleはこのバリアント用に個別のタスク(assembleFreeDebug、installFreeDebug、bundleFreeRelease)を生成します。Android Studioでは、Build Variantsパネル(View → Tool Windows → Build Variants)からバリアントを切り替えられます。バリアントを選択すると、コンパイルされるコード、含まれるリソース、生成されるAPK/AABが変わります。
Build Variantsシステムは、次の3つの主要なタスクを解決します。異なる環境(dev/staging/production)の設定分離、アプリの複数バージョン(free/paid)の作成、ビルドのA/Bテスト。Build Variantsがない場合、開発者は手動でフラグや設定を切り替える必要があり、人的ミスが発生します。Gradle Inc.、2024の調査によると、Build Variantsを導入すると、3つ以上のデプロイ環境を持つプロジェクトでビルドエラーが60%削減されます。
AGP(Android Gradle Plugin)は、設定フェーズですべての組み合わせを計算します。プロジェクトに2つの次元があり、それぞれ2つと3つのフレーバーがある場合、Gradleは2 × 2 × 3 = 12の組み合わせを作成し、それにBuild Typesの数(通常2)を掛けます。各組み合わせには、一意の名前とタスクセットが与えられます。AGPは各バリアント用のsource setを自動追加します:src/freeDebug/、src/paidRelease/、および一般化されたsrc/free/とsrc/debug/。リソース読み取りの優先順位は、variant → flavor → type → mainです。
// 例:4つのBuild Variants
// flavorDimensions "version", "server"
// version: demo, prod
// server: mock, live
// buildTypes: debug, release
// 合計:2 × 2 × 2 = 8バリアント
android {
flavorDimensions "version", "server"
productFlavors {
demo { dimension "version" }
prod { dimension "version" }
mock { dimension "server" }
live { dimension "server" }
}
}
Build Typeはアプリケーションのビルド方法(デバッグ情報の有無、最適化の有無、署名)を定義します。Product Flavorはビルドするもの(製品のバージョン)を定義します。Build Typeはビルドメカニズム(debug、release、staging)です。Product Flavorは製品バリアント(free、paid、enterprise、demo)です。両方の概念は直交しており、任意のBuild Typeを任意のProduct Flavorに適用できます。
デフォルトのBuild Typesには、debug(debuggable=true、minification=false、signing=debug.keystore)とrelease(debuggable=false、minification=true、signing=production.keystore)が含まれます。デフォルトのProduct Flavorは1つで名前がありません(実質的にmain source set)。開発者は独自のBuild Types(例:debuggable=true、minification=trueの“staging”)や任意の数のProduct Flavorsを追加できます。もう1つの違いは、Build Typesは次元にグループ化できませんが、Product Flavorsはできることです。
主要な実践的な違い:build.gradleのdefaultConfigはすべてのVariantsに適用されますが、productFlavorsとbuildTypesで上書きできます。buildTypeに追加されたBuildConfigFieldはそのタイプのすべてのフレーバーで表示され、productFlavorに追加されたものはそのフレーバーのすべてのタイプで表示されます。両方でフィールドが定義されている場合、buildTypeが優先されます(チェーン内で最後に適用されます)。
| 特性 | Build Type | Product Flavor |
|---|---|---|
| 目的 | ビルド方法 | ビルド内容 |
| 例 | debug、release、staging | free、paid、demo、enterprise |
| デフォルト | debug + release | 1つ(main) |
| Source Set | src/debug/、src/release/ | src/free/、src/paid/ |
| 次元 | なし | flavorDimensions |
| 適用順序 | flavorの後、上書き | defaultConfigの後 |
| BuildConfigField | flavorを上書き | defaultConfigを上書き |
Build Variantsの設定は、モジュールレベルのbuild.gradleファイルのandroidブロックで行います。最初にbuildTypesをパラメータとともに宣言し、次にflavorDimensionsとproductFlavorsを宣言します。Gradleはこれらの宣言に基づいてバリアントを自動生成します。各バリアントはモジュールのdefaultConfigを継承し、指定されたフィールドを上書きします。宣言の順序は優先順位に影響します。buildTypesはproductFlavorsの後に適用されます。
Gradleスクリプトで特定のBuild Variantにアクセスするには、android.applicationVariants(アプリモジュールの場合)またはandroid.libraryVariants(ライブラリモジュールの場合)を使用します。これはコレクションであり、設定ランタイム時に各バリアントの設定を変更するために反復処理できます。例えば、“demo”という単語を含むすべてのバリアントにプログラムでbuildConfigFieldを追加できます。
Android Gradle Plugin 8.xは、ラムダを介してバリアントを設定するためのよりクリーンなAPIであるonVariantsのサポートを追加しました。古いAPI(variantOutput、variantFilter)は非推奨としてマークされています。ライブラリモジュールでは、onEachとともにonVariantsを使用することをお勧めします。variantOutputからonVariantsへの移行は、AGPを7.xから8.xにアップグレードする際の推奨手順です。
android {
buildTypes {
debug {
debuggable true
minification false
signingConfig signingConfigs.debug
}
release {
debuggable false
minification true
proguardFiles "proguard-rules.pro"
signingConfig signingConfigs.release
}
staging {
debuggable true
minification true
versionNameSuffix "-staging"
}
}
flavorDimensions "tier", "region"
productFlavors {
free { dimension "tier" }
paid { dimension "tier" }
us { dimension "region" }
eu { dimension "region" }
}
}
android.onVariants { variant ->
if (variant.name.contains("Demo")) {
variant.setEnabled(false)
}
}
各Build Variantには、独自のsource sets階層(ソースコード、リソース、マニフェストを含むディレクトリ)が与えられます。source setはsrc/<variantName>/(例:src/freeDebug/)に配置され、java/、res/、AndroidManifest.xml、assets/を含めることができます。バリアントのsource setにファイルが存在する場合、メインのsource set(src/main/)の同じ名前のファイルを上書きします。リソースについては、置き換えではなくマージが行われます。システムはアクティブなすべてのsource setsからリソースをマージし、バリアント固有のものを優先します。
Build Variantのsource setsは、チェーンで構築されます:src/main/ → src/flavor/ → src/type/ → src/flavorType/。例えば、paidReleaseの場合、最初にmain、次にpaid、次にrelease、最後にpaidReleaseが適用されます。後続の各source setは前のものを上書きします。つまり、src/release/res/values/strings.xmlはsrc/paid/の同じ文字列を上書きしますが、src/paidRelease/res/はさらに優先度が高くなります。
バリアントにsource setsを使用することは、リソースをカスタマイズする推奨方法です。コード内でBuildConfig.FLAVORをチェックしてロジックを分岐する代わりに、異なるsource setsに異なるファイルを配置するだけです。例えば、free版とpaid版のアイコンはそれぞれsrc/free/res/とsrc/paid/res/に配置し、異なる権限を持つAndroidManifestはsrc/free/AndroidManifest.xmlとsrc/paid/AndroidManifest.xmlに配置します。これはよりクリーンで高速(リソースはコンパイル時に処理され、ランタイムチェック不要)かつ安全(コードのバグにより無料版に誤って有料機能を含めることがない)です。
マルチモジュールプロジェクトでは、各モジュール(ライブラリ)が独自のBuild Variantsを持つことができます。AGPはバリアントを自動同期します。アプリモジュールがpaidReleaseをビルドする場合、依存するすべてのライブラリもpaidReleaseに対応するバリアントでビルドされます。ライブラリにproduct flavorsがなく、アプリモジュールにある場合に問題が発生します。その場合、ライブラリは1回(タイプに応じてreleaseまたはdebug)ビルドされます。
ライブラリモジュールの場合、Build VariantはデフォルトでアプリモジュールのBuild Typeと一致します(ライブラリにはproduct flavorsがないため)。ライブラリがアプリモジュールのフレーバーに適応する必要がある場合、同じflavorDimensionsとproductFlavorsをライブラリで宣言する必要があります。AGPは正確な名前の一致でフレーバーを照合します。Gradleは、ルートプロジェクトでsubprojectsまたはConvention Pluginsを使用したビルド設定によるフレーバー同期を推奨しています。
AGP 8.1以降、ライブラリはmultiple variantsを公開できます。つまり、すべてのライブラリバリアントをmavenリポジトリに同時に公開できます。これにより、アプリモジュールが有料フレーバーを使用しているが、ライブラリが無料版でのみ公開されている場合の問題が解決されます。Multiple variants publishing(MVP)により、依存プロジェクトが必要なバリアントを自動的に選択できます。MVPを有効にするには、ライブラリのbuild.gradleにpublishing { multipleVariants { ... } }を追加します。
一部のBuild Variantsを無効にする必要がある場合があります。例えば、mockReleaseの組み合わせが意味をなさない場合(モックサーバーを本番環境に出すべきでない)などです。GradleはvariantFilterを提供します。これは、各バリアントのプロパティをチェックし、setIgnore(true)で無効化できるDSLブロックです。VariantFilterはタスク作成前の設定フェーズで適用されるため、無効化されたバリアントはassembleタスクやinstallタスクを生成しません。
フィルタリングはビルドの高速化にも役立ちます。プロジェクトに8つのバリアントがあるが、開発者が1つだけで作業している場合、残りの7つのバリアントも設定を通過します。variantFilterを使用すると、無効化されたバリアントはタスクを作成せず、6つ以上のフレーバー次元を持つプロジェクトの設定時間を30-50%削減します。CI/CDでは、コマンドラインパラメータ-PbuildOnly=paidReleaseで動的にバリアントをフィルタリングできます。
android {
variantFilter { variant ->
// release用のmockとproduction用のdemoを無効化
def names = variant.flavors*.name
def isMock = names.contains("mock")
def isDemo = names.contains("demo")
def isRelease = variant.buildType.name == "release"
if ((isMock && isRelease) || (isDemo && !isMock)) {
variant.setIgnore(true)
}
}
}
// パラメータによる動的フィルタリング
if (project.hasProperty("buildOnly")) {
def target = project.property("buildOnly")
android.variantFilter { variant ->
variant.setIgnore(variant.name != target)
}
}
よくある質問
制限はありませんが、Gradleはすべてのフレーバーとタイプのデカルト積を作成します。3つの次元にそれぞれ3つのフレーバーと3つのbuild typesがある場合、27のバリアントになります。バリアントが多すぎると設定が遅くなります。1つのモジュールでは10〜12個以下のバリアントにすることをお勧めします。
flavorDimensionsはProduct Flavorsを独立した軸にグループ化します。例えば、“tier”次元(free、paid)と“region”次元(us、eu)です。次元がない場合、すべてのフレーバーは1つの軸に属し、Gradleはすべてから1つのフレーバーのみを選択します(free+usとpaid+euを別々のバリアントとして持つことはできません)。
productFlavorまたはbuildTypeブロックでapplicationIdを指定します。例えば、無料版の場合:free { applicationId “com.example.app.free” }。マニフェストでは${applicationId}を使用します。Gradleが自動的に値を代入します。これにより、両方のバリアントを1つのデバイスにインストールできます。
iOSでは、Build Variantsに相当するものはScheme + Configurationの組み合わせです。Xcode Schemesは、異なるパラメータを持つDebug/Release設定を通じて構成されます。複数バージョン(free/paid)の場合は、Build ConfigurationsとPreprocessor Macrosが使用されます。Androidでは、コンセプトがより形式化されており、Gradleに組み込まれています。
はい、各バリアントでAPKサイズが異なる場合があります。Debugビルドにはデバッグ情報、SDK、サポートされていないリソースが含まれます。minificationとresource shrinkingを使用したReleaseビルドは最小サイズになります。Product Flavorもサイズに影響します。有料ライブラリのない無料版は、それらのライブラリのサイズ分だけ有料版より小さくなります。
まとめ
ターンキー方式のモバイルアプリケーションを開発します
IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。