ビルド時にいろんな値を生成する
ビルドに応じて値を動的に制御したい欲はあると思います。いくつか方法をまとめました。
BuildConfigに追加する
build.gradle
に定義することで、自動生成されるBuildConfig.java
に値を定義できます。
build.gradle
に、直接値を書くのではなくて、gradle.properties
から読み込む方法をとります。
gradle.properties
の扱いについては、過去の記事を参考にしていただけると。
gradle.properties
に適当な値を設定します。
... from_properties=true hoge_api_key=hogehogehoge hoge_version=10000 hoge_array={"a", "b", "c"} hoge_pi=3.14 properties_margin=48dp properties_color=#dddddd hoge_host=http://google.com hoge_meta_key=hogekey hoge_meta_id=100 hoge_meta_value=hogevalue ...
build.gradle
から次のように取り込みます。
定義した値は、${HOGE}
でbuild.gradle
内で呼ぶことができます。
... android { ... defaultConfig { ... buildConfigField("boolean", "FROM_PROPERTIES", "${from_properties}") buildConfigField("String", "HOGE_API_KEY", "\"${hoge_api_key}\"") buildConfigField "int[]", "HOGE_ARRAY", "{1, 2, 3}" buildConfigField "String[]", "PROPERTIES_ARRAY", "${hoge_array}" buildConfigField("int", "HOGE_VERSION", "${hoge_version}") buildConfigField("double", "HOGE_PI", "${hoge_pi}") buildConfigField("java.util.ArrayList<String>", "HUGA_LIST", "new java.util.ArrayList<>()") ... } ... } ...
生成されるBuildConfig.java
は次のようになります。
public final class BuildConfig { public static final boolean DEBUG = Boolean.parseBoolean("true"); public static final String APPLICATION_ID = "com.sakebook.sample.gradlepropertiessample"; public static final String BUILD_TYPE = "debug"; public static final String FLAVOR = "log"; public static final int VERSION_CODE = 1; public static final String VERSION_NAME = "1.0"; // Fields from default config. public static final boolean FROM_PROPERTIES = true; public static final String HOGE_API_KEY = "hogehogehoge"; public static final int[] HOGE_ARRAY = {1, 2, 3}; public static final double HOGE_PI = 3.14; public static final int HOGE_VERSION = 10000; public static final java.util.ArrayList<String> HUGA_LIST = new java.util.ArrayList<>(); public static final String[] PROPERTIES_ARRAY = {"a", "b", "c"}; }
定義したものが そのまま 呼び出されます。
そのため、フルパスで定義すればArrayList
なども生成できます。用途はわかりませんが。。
resourceに追加する
build.gradle
からResource
も追加できます。
resValue
で定義します。
... android { ... defaultConfig { ... resValue "dimen", "properties_dimen", "${properties_margin}" resValue "color", "properties_color", "${properties_color}" resValue "string", "hoge_host", "${hoge_host}" resValue "string", "hoge_meta_id", "${hoge_meta_id}" resValue "string", "hoge_meta_key", "${hoge_meta_key}" ... } ... } ...
第一引数は、リソースの種類、第二引数はなまえ、第三引数が値となります。 String
ではなく string
なので注意が必要です。
生成される値は次のようになります。
<?xml version="1.0" encoding="utf-8"?> <resources> <!-- Automatically generated file. DO NOT MODIFY --> <!-- Values from product flavor: log --> <string name="hoge_id">log</string> <!-- Values from default config. --> <string name="hoge_host">http://google.com</string> <string name="hoge_meta_id">100</string> <string name="hoge_meta_key">hogekey</string> <color name="properties_color">#dddddd</color> <dimen name="properties_dimen">48dp</dimen> </resources>
<resource>
タグの中で定義するものならなんでもできそうです。
既に存在する名前を使ってしまうとエラーになります。
Error:Execution failed for task ':app:mergeLogDebugResources'. > [string/app_name] 省略/app/src/main/res/values/strings.xml [string/app_name] 省略/app/build/generated/res/resValues/log/debug/values/generated.xml: Error: Duplicate resources
AndroidManifest.xmlを置き換える
生成するだけではなく、置き換えることも可能です。AndroidManifest.xml
内で、${HOGE}
と書くことで、ビルド時に置き換えることが可能です。
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.sakebook.sample.gradlepropertiessample" > <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="${base_app_name}" android:supportsRtl="true" android:theme="@style/AppTheme" > <activity android:name=".MainActivity" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <meta-data android:name="hoge_key" android:value="@string/hoge_meta_key" /> <meta-data android:name="hoge_id" android:value="@string/hoge_meta_id" /> <meta-data android:name="hoge_value" android:value="${meta_value}" /> </application> </manifest>
${base_app_name}
と${meta_value}
というplaceholder
を置きました。
これらを何に置き換えるか、build.gradle
で定義します。
... android { ... defaultConfig { ... manifestPlaceholders = [meta_value: "@string/hoge_id"] manifestPlaceholders = [base_app_name: "1name"] ... } ... } ...
manifestplaceholder = [Manifestに書いたPlaceholder名: 変えたい値]
という風に定義します。複数まとめることも可能です。
manifestPlaceholders = [ meta_value: "${hoge_meta_value}", base_app_name: "2name" ]
applicationId
も、実は デフォルトで用意されているplaceholder
です。それ以外は、manifestplaceholder
と明示して定義する必要があります。
定義できる場所
これらのbuildConfigField
, resValue
, manifestplaceholder
は、build.gradle
のandroidのDSLの中で、
defaultConfig
productFlavors
の各フレーバー内buildTypes
の各ビルドタイプ内
で定義できます。
そのビルドにおいて、どこかしらで定義さえしていれば大丈夫です。
しかし、同じものを定義していれば defaultConfig
< productFlavors
< buildTypes
の順で上書きされます。
まとめ
ビルド時にそもそもの値を切り替えておけば、APIのホストやGAのIDなどを、BuildConfig.DEBUG
で制御したりする必要がなくなります。
AndroidManifestのmeta-data
も変更できるので、各種SDKの切り替えなどにも使えると思います。
荒いですがサンプルをおいておきます。