こんにちは, またくです。

Android でアプリを作っている時に, コード内で秘匿したい鍵の値を参照したい場合がありました。 元々 private repository で開発していたので直書きでも良いのですが, アプリを作成したら public にするということで進めていたので, コード内で定数で参照できるようにしています。

もし Android Studio と Gradle を使っていたら, gradle.properties が1つの答えです。

設定

値の定義

gradle.properties に, 参照したい key-value の組を記述します。

# gradle.properties
API_KEY="amazing_key"
COMSUMER_SECRET="amazing_secret"
DEBUG_API_KEY="debug123"
DEBUG_COMSUMER_SECRET="debug456"

このファイルは git 等の管理に含めないように除外しておきます。プロジェクト直下にあるものか, もしくは $HOME/.gradle/ に gradle.properties があれば, 読み込んでくれました。

値の読み込み

gradle.properties に書かれた値を読み込めるように, app/build.gradle に以下のように記述します。

buildTypes {
  debug {
    // format: '型', 'プロジェクト内で参照できる Key名', '参照元の Key名'
    buildConfigField 'String', 'API_KEY', project.DEBUG_API_KEY
    buildConfigField 'String', 'COMSUMER_SECRET', project.DEBUG_COMSUMER_SECRET
    // プロジェクト内で BuildConfig.key名 で参照できるようになる
    // e.g. BuildConfig.API_KEY

  }

  release {
    buildConfigField 'String', 'API_KEY', project.API_KEY
    buildConfigField 'String', 'COMSUMER_SECRET', project.COMSUMER_SECRET
  }
}

上の例では, デバッグビルドとリリースビルドで参照する値を変更した場合を想定していますが, もし共通の何かを定義したい場合には build.gradle 内の defaultConfig に記述すると良かったです。

// app/build.config
defaultConfig {
  buildConfigField 'String', 'API_KEY', project.API_KEY
}

今回は String のみですが, その他 Java で使える型なら大丈夫そうです。

CI サービス上ではどうする?

key-value の組のファイルが管理下にないので, なにもしないと app/build.gradle の読み込みでエラーになってしまいます。

CI のサービス上でのみ有効な, 環境変数をセットできる部分があるかと思うので, そこに設定したい key-value の組を書いておいて, 以下のようにその値を出力させた gradle.properties を作ってあげると良さそうでした。

#!/bin/bash
set -e
GRADLE_PROPERTIES=$HOME"/.gradle/gradle.properties"
echo "API_KEY=\"$API_KEY\"" >> $GRADLE_PROPERTIES
echo "COMSUMER_SECRET=\"$COMSUMER_SECRET\"" >> $GRADLE_PROPERTIES

参考: Gradle Tips and Recipes | Android Studio - Android Developers


追記

Twitter でコメントをいただくことができたので追記します。

gradle.properties には jvm の設定も書かれるため, 今回の用途ではキーを記述した local.properties を用意し, バージョン管理下におかないようにして, それを build.gradle に読み込ませるのがスマートなのだと学びました。

build.gradle を以下のようになります。

 // app/build.config
defaultConfig {
    def properties = new Properties()
    properties.load(project.rootProject.file('local.properties').newDataInputStream())
    def API_KEY = properties.getProperty("DEBUG_API_KEY")
    buildConfigField("String", "API_KEY", "\"${API_KEY}\"")
}

@serenegiant さん, ありがとうございます!