Product FlavorとBuild Type
Android Gradle pluginにはProduct Flavor(以下Flavor)とBuild Typeという機能があり、テスト用、本番用などでアプリのビルド設定を切り替えることができる。
Flavorは主にアプリで使用する文字列や画像などのリソースの切り替え、Build Typeは署名や圧縮の設定切り替えをすることが多い。
Flavorは任意の名前のものを自分で定義するが、Build Typeは標準でdebugとrelease
の2種類が用意されている。
Build Typeを追加することもできるが、特に必要なければdebugとreleaseをそのまま使用すればよい。
Build Variants
FlavorとBuild Typeを組み合わせたものをBuild Variantsという。
例えば、Flavorをa、b、cの3種類定義し、Build Typeを標準のdebugとreleaseのままにした場合、Build Variantsは以下の6種類となる。
- aDebug
- aRelease
- bDebug
- bRelease
- cDebug
- cRelease
Android Studioでアプリをビルドする場合、Build Variantsのウィンドウで任意のBuild Variantを選択してビルドすることができる。
Variant Filter
Build VariantはFlavorとBuild Typeの全ての組み合わせが自動で作成されるが、variantFilterを用いて不要な組み合わせを作成しないようにできる。
variantFilter { variant ->
// buildTypeが"debug"、flavorが"a"のBuild Variantは作成しない
if (variant.buildType.name == "debug" && variant.flavors*.name.contains("a")) {
setIgnore(true)
}
}
variantFilter内に任意の判定を書いて、setIgnore(true)
とするとそのBuild Variantは作成されなくなる。
Flavorはvariant.flavorsの形でListで取得されるが、ここに記載するbuild.gradleではflavorsには一つのflavorしか入らない。
FlavorおよびBuild Typeで切り替えられること
必要であれば様々な設定を切り替えられるが、主に以下を切り替えることが多い。
- applicationId
- applicationIdをFlavor毎に変えることで、各Flavorでビルドしたアプリを別アプリとして同じ端末にインストールできる
- 文字列リソース
- strings.xml などの文字列リソースをFlavorによって切り替えられる
- プログラム処理
- Flavorによってプログラム処理を切り替えられる
- 署名の設定(SigningConfig)
- Build TypeまたはFlavorによってアプリの署名設定を切り替えられる
- プロガード(難読化)の設定
- Build TypeまたはFlavorによってプロガードの有効/無効などを切り替えられる
build.gradleの設定
以下はproduction、staging、develop3つのFlavorを定義して、それぞれapplicationIdを変更するbuild.gradleの例。
apply plugin: 'com.android.application'
android {
compileSdkVersion 26
defaultConfig {
applicationId "net.sample.myapplication"
minSdkVersion 21
targetSdkVersion 26
versionCode 1
versionName "1.0"
}
// !!!! ProductFlavorの設定 !!!!!
flavorDimensions "default"
productFlavors {
production {
applicationId "net.sample.myapplication"
}
staging {
applicationId "net.sample.myapplication_staging"
}
develop {
applicationId "net.sample.myapplication_develop"
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:26.1.0'
implementation 'com.android.support.constraint:constraint-layout:1.0.2'
}
リソースの切り替え
build.gradleにFlavorを定義すると、各Flavorで別々に文字列や画像などのリソースを保持することができる。(もちろん共有することも可能)
リソースをFlavor毎に定義する場合、"res/values" フォルダで右クリックし、コンテキストメニューから "New > Values resource file" を選択した後、"Source set"の欄で追加先のFlavorを選択してリソースファイルを追加する。(mainは全Flavorで共通)
各ProductFlaovrに固有のリソースは、srcフォルダの下の各ProductFlaovr名のフォルダに配置される。
また、FlavorだけでなくBuild Typeごとにリソースを定義したり、FlavorとBuild Typeの組み合わせに対して定義することもできる。
文字列リソースの切り替え
Androidプロジェクトを作成すると標準でmain/resフォルダの下に文字列を定義するための strings.xml ファイルが用意されるが、Flaovr毎に文字列リソースを切り替える場合、これとは別に各Flavor用のxmlファイルを作成する。
ファイル名はstrings.xml
でも良いが、別の名前にしておくと共通の文字列リソースと区別がついて分かりやすい。
ここでは各Flavorごとの文字列リソースファイルをenvironment.xml
として作成する前提で話を進める。
アプリ名の切り替え
上記「リソースの切り替え」を用いて、ProductFlavor毎にアプリの表示名(ホーム画面のアプリアイコンの下に表示される名前)を変えることができる。
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="net.sample.myapplication">
<application
android:label="@string/app_name">
<!-- 以下略 -->
</application>
</manifest>
AndroidManifestに記載されたアプリ名は、上記のように標準で文字列リソースのapp_name
を参照するようになっているので、各Flavorの文字列リソースファイルに以下のように別々のapp_name
を記載してやれば、Flavor毎にアプリ名を切り替えることができる。
Flavor developのenvironment.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">DevApp</string>
</resources>
Flavor stagingのenvironment.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">STGApp</string>
</resources>
Flavor productionのenvironment.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">本番アプリ名</string>
</resources>
プログラム内での処理分岐方法
Flavorによってプログラム内の処理を分岐させることができる。
BuildConfig.FLAVOR
から現在のFlavorを文字列で取得できるので、その値を見て処理を分岐させる。
public class Environment {
String apiURL = null;
public Environment() {
if (BuildConfig.FLAVOR.equals("production")) {
apiURL = "https://api-prod.net";
} else if (BuildConfig.FLAVOR.equals("staging")) {
apiURL = "https://api-stg.net";
} else if (BuildConfig.FLAVOR.equals("develop")) {
apiURL = "https://api-develop.net";
}
}
}
signingConfigsの切り替え
signingConfigs(署名の設定)はFlavorやBuild Typeとは別に定義して、各FlavorやBuild Typeで任意のsigningConfigを使うことができる。
// 複数のsigningConfigsを定義
signingConfigs {
foo {
storeFile = new File('keystore_foo.p12')
storePassword = 'password'
keyPassword = 'password'
keyAlias = '1'
}
bar {
storeFile = new File('keystore_bar.p12')
storePassword = 'password'
keyPassword = 'password'
keyAlias = '1'
}
}
buildTypes {
release {
// BuildType=releaseの場合、signingConfig fooを使用
signingConfig signingConfigs.foo
}
debug {
// BuildType=debugの場合、signingConfig barを使用
signingConfig signingConfigs.bar
}
}
上記の例はBuild TypeによってsigningConfigを切り替えているが、Flavorによって切り替えることもできる。
カスタムフィールド(buildConfigField)の定義
buildConfigFieldを使って各Flavorごとに任意の値をプログラムに渡すことができる。
productFlavors {
a {
applicationId "net.sample.myapplication"
buildConfigField "boolean", "IS_LOG_ENABLED", "false"
}
b {
applicationId "net.sample.myapplication_staging"
buildConfigField "boolean", "IS_LOG_ENABLED", "true"
}
c {
applicationId "net.sample.myapplication_develop"
buildConfigField "boolean", "IS_LOG_ENABLED", "true"
}
}
if (BuildConfig.IS_LOG_ENABLED) {
Log.d("tag", "message");
}
Flavorによって挙動を変えたいが、BuildConfig.FLAVORの判定では分かりづらい場合などに用いる。
boolean以外にStringなども定義できるが、StringについてはFlavorごとに文字列リソースを用意できるので不要かと思われる。
PUSH通知のパーミッション設定
プッシュ通知(GCM)を使う場合、AndroidManifest.xmlにカスタムのパーミッションを記載する必要があるが、どこかのAndroidバージョンからpermission名が重複するアプリがインストールできなくなってしまった。
そのため、複数Flavorのアプリを同時インストールしたい場合、パーミッション名を以下のようにapplicationId
によって動的に切り替える。
<permission android:name="${applicationId}.permission.C2D_MESSAGE" android:protectionLevel="signature" />
<uses-permission android:name="${applicationId}.permission.C2D_MESSAGE" />