Gradle の ProductFlavors で APK を作って生活を豊かにする
小倉唯さんブログ再開おめでとうございます。
今日は、これまでの Android 開発でおきがちなビルド時の問題と、 Gradle を使ってアプリケーションのビルドをすると生活が豊かになる、ということについて書きたいと思います。
Gradle 以前のビルドツール (Ant とか Maven とか) で起こりがちな問題
ビルド時に DEBUG
とか RELEASE
のフラグを切り替えたいけど出来ない!!
定数クラスを作って手動で切り替える
- 利点
- 猿でも使い方が瞬時に分かる
- 問題点
- オペミスが起きやすい
- チェックアウトしてきた直後にビルドすると何が出来あがるか分からない
- リポジトリには
DEBUG = true
しかコミットしてはいけないというルールを作ることに - でもだれかが
DEBUG = false
にしたままうっかりコミットして崩壊する
- リポジトリには
public final Constants { // リリース時には false にして!! public static final boolean DEBUG = true; }
Java にはマクロが無いのがいけないんだ
- C や C++ 開発からやって来た人たちが陥りがち
#ifdef DEBUG setApiEndpoint("http://api.dev.example.com/"); #else setApiEndpoint("https://api.example.com/"); #endif
ant debug -DDEBUG
- こういうことがしたいんだ!! (実際には出来ない)
- m4 を使い始める人とか出てくる
- IDE の三角ボタンが押せなくなる
スクリプトで (sed とかを使って) ソースコードを書き換える
- 利点
- 自動化されてる
- CI する時に便利
- 問題点
./build_myproject.sh release
#!/bin/sh ... sed -i "s/boolean DEBUG = true/boolean DEBUG = false/g" src/**/*.java ... ant $1
この後続けて開発してコミットをするといつの間にか DEBUG = false
な状態になり、だれが DEBUG = false
にしたんだ!! と喧嘩が起きる。
AndroidManifest.xml の android:debuggable で切り替えるようにする
- 利点
- この設定はだいたいみんな知ってるから使いやすい
- 問題点
if ((info.flags & ApplicationInfo.FLAG_DEBUGGABLE) == ApplicationInfo.FLAG_DEBUGGABLE) { isDebug = true; } ... if (isDebug) { setApiEndpoint("http://api.dev.example.com/"); } else { setApiEndpoint("https://api.example.com/"); }
ユーザは apktool などを使って AndroidManifest.xml
を書き換えることによって api.dev.example.com
に繋がるアプリを作ることが可能になってしまう。
BuildConfig を使うようにする (ADT 17 以降)
- 利点
- コンパイル時に指定される定数なので不要なコードは最適化で消える
- 問題点
- だんだん複雑な条件を作りたくなる
if (BuildConfig.DEBUG) { setApiEndpoint("http://api.dev.example.com/"); } else { setApiEndpoint("https://api.example.com/"); }
Gradle で BuildTypes と ProductFlavors を使い分けて APK を作り分ける
Gradle で ProductFlavor を使うとビルド時に簡単にソースコードを差し替えられる。
ProductFlavors は有料版と無料 (広告) 版の切り替えとかに使うと便利、みたいなことを書いているけど、実際には API エンドポイントとか API トークンとかを切り替えるときに便利だと思う。
DEBUG と RELEASE の切り替えは BuildTypes というやつで別途設定できる。
apply plugin: 'android' android { signingConfigs { debug { storeFile file('keys/debug.keystore') } release { storeFile file('keys/release.keystore') storePassword 'STORE_PASSWORD' keyAlias 'KEY_ALIAS' keyPassword 'KEY_PASSWORD' } } buildTypes { release { signingConfig signingConfigs.release } } productFlavors { beta {} real {} } }
Release を指定したときには以下をやればよい。
- リリース用証明書で署名する
- ProGuard を有効にする
- パッケージ名の変更もできる
- 開発版とリリース版を両方一つの端末にインストールすることができる
エンドポイントや API トークンは ProductFlavors で切り替える。 Gradle のディレクトリ構成はちょっと特殊だけど、以下のようなディレクトリ構成にする。
+ src + main | + java | + res | + ... + beta | + java | + res | + ... + real + java + res + ...
そして、 例えば API のエンドポイントを変えたい場合は以下のようにする。
src/beta/res/values/config.xml
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="api_endpoint">http://api.dev.example.com/</string> </resources>
src/real/res/values/config.xml
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="api_endpoint">http://api.example.com/</string> </resources>
開発してるときには以下のコマンドで、
# beta 版 API の場合 ./gradlew clean assembleBetaDebug # real 版 API の場合 ./gradlew clean assembleRealDebug
リリース物を作るときは以下のコマンドを使えばよい。
./gradlew clean assembleRealRelease
gradlew を使っておけば、 Java さえあれば様々な環境ですぐにビルドできるようになる。
まとめ
Gradle を使えば Android 開発で起きがちだった DEBUG
や RELEASE
の切り替え、さらには API エンドポイントや API トークンの切り替えが気軽に出来るようになる。