[Android]シークレットキーなどの秘匿情報をプロジェクトで使うための設定

Android アプリを開発していく中で、シークレットキーなどの秘匿情報をプロジェクトで扱うことがあるかと思います。

例えば [Qiita API](https://qiita.com/api/v2/docs) を使った Android アプリを開発する場合、アクセストークンを発行するためには [POST /api/v2/access_tokens](https://qiita.com/api/v2/docs#post-apiv2access_tokens) を実行する必要がありますが、この時リクエストパラメータに `client_id` と `client_secret` が必要になります。

これらのパラメータは [Qiita のアプリケーション](https://qiita.com/settings/applications) ページからアプリケーションを登録することによって発行できますが、このような秘匿すべきパラメータを、以下のような条件で Android プロジェクトで扱うための設定について考えます。

- 漏洩防止のため Git のバージョン管理には含めない
- BuildConfig のフィールドとして、これらのパラメータをプログラムから参照できるようにする

今回は以下の3つの方法について紹介したいと思います。

1. gradle.properties を使う
2. 環境変数として設定する
3. [secrets-gradle-plugin](https://github.com/google/secrets-gradle-plugin) を使う

# 1. gradle.properties を使う

一つ目の方法は `gradle.properties` を使う方法です。

## gradle.properties の作成

`gradle.propeties` を以下のように作成し、`~/.gradle/gradle.properties` に配置します。

```~/.gradle/gradle.properties
QIITA_CLIENT_ID=xxxxxxxxxxxxxxxxxx
QIITA_CLIENT_SECRET=xxxxxxxxxxxxxxxxxx
```

## build.gradle への設定

そして Android プロジェクトの `app/build.gradle` で以下のように設定します。

```app/build.gradle
...

android {
    ...
    
    defaultConfig {
        ...
    
        buildConfigField "String", "QIITA_CLIENT_ID", "\"${project.properties['QIITA_CLIENT_ID']}\""
        buildConfigField "String", "QIITA_CLIENT_SECRET", "\"${project.properties['QIITA_CLIENT_SECRET']}\""
    }
    ...
}
```

Gradle で `project.properties['QIITA_CLIENT_ID']` のようにして、`gradle.properties` に設定した値を取得することができます。

これでプログラムから `BuildConfig.QIITA_CLIENT_ID`、`BuildConfig.QIITA_CLIENT_SECRET` として設定した値を参照することができます。

## CI でのビルド

もし CI でビルドするのであれば、必要なパラメータを CI で環境変数として設定しておいて、ビルドを実行する前に一度以下のコマンドを実行して `gradle.properties` を作成しておく必要があります。
（以下の例では CI で環境変数 `QIITA_CLIENT_ID` と `QIITA_CLIENT_SECRET` が設定されているものとします）

```
cat <<EOF > ~/.gradle/gradle.properties
QIITA_CLIENT_ID=$QIITA_CLIENT_ID
QIITA_CLIENT_ID=$QIITA_CLIENT_SECRET
EOF
```

もしくは、ビルド時に `-P` オプションを指定することによってパラメータを渡すことも可能です。
（以下の例でも環境変数 `QIITA_CLIENT_ID` と `QIITA_CLIENT_SECRET` が設定されているものとします）

```
./gradlew assembleRelease -PQIITA_CLIENT_ID=$QIITA_CLIENT_ID -PQIITA_CLIENT_SECRET=$QIITA_CLIENT_SECRET
```

# 2. 環境変数として設定する

先ほど紹介したように CI でビルドする際に環境変数として設定する必要があるのであれば、ローカルで開発する際にも環境変数で設定してしまう方法もあります。

## 環境変数への設定

OS や使用しているシェルによって設定方法は異なるかと思いますが、私の場合は Mac で zsh を使用しているので `~/.zshrc` に以下の設定を追記します。

```
export QIITA_CLIENT_ID=xxxxxxxxxxxxxxxxxx
export QIITA_CLIENT_SECRET=xxxxxxxxxxxxxxxxxx
```

### direnv を使って環境変数を設定する

余談ですが Unix 系の OS であれば [direnv](https://github.com/direnv/direnv) を使うのがオススメです。

これを使うことによって、指定したディレクトリ以下に対して環境変数が適用されるようになります。

また `~/.zshrc` に環境変数を設定する必要がないため、プロジェクトごとにいくつか設定が必要な場合でも `~/.zshrc` に追加していく必要がなくなります。

導入方法や使い方については、[こちらの記事](https://qiita.com/kompiro/items/5fc46089247a56243a62) などが参考になるかと思います。

## build.gradle への設定

そして Android プロジェクトの `app/build.gradle` で以下のように設定します。

```app/build.gradle
...

android {
    ...
    
    defaultConfig {
        ...
    
        buildConfigField "String", "QIITA_CLIENT_ID", "\"${System.getenv('QIITA_CLIENT_ID')}\""
        buildConfigField "String", "QIITA_CLIENT_SECRET", "\"${System.getenv('QIITA_CLIENT_SECRET')}\""
    }
    ...
}
```

環境変数の場合は `System.getenv('QIITA_CLIENT_ID')` のようにして環境変数を取得できます。

## CI でのビルド

CI 側に環境変数を設定しておくだけで OK です。

# 3. secrets-gradle-plugin を使う

[google/secrets-gradle-plugin](https://github.com/google/secrets-gradle-plugin) という Gradle プラグインを使うことによって、`local.properties` などに設定されているプロパティを `BuildConfig` のフィールドに設定してくれます。

設定はとても簡単で、まずは `app/build.gradle` に以下のようにプラグインを導入します。

```app/build.gradle
plugins {
    ...
    id 'com.google.secrets_gradle_plugin' version '0.6'
}
```

そして、`local.properties` に以下のように設定を追記します。

```local.properties
QIITA_CLIENT_ID=xxxxxxxxxxxxxxxxxx
QIITA_CLIENT_SECRET=xxxxxxxxxxxxxxxxxx
```

この状態でビルドを行うとプログラムから `BuildConfig.QIITA_CLIENT_ID`、`BuildConfig.QIITA_CLIENT_SECRET` として設定した値を参照することができるようになります。

また、このプラグインを使うことによって、設定した値が `AndroidManifest.xml` 内でも参照できるようになります。

その他に `local.properties` 以外にも設定ファイルを指定することができたり、指定したキーを無視するなどのオプションが設定できるようなので [ドキュメント](https://github.com/google/secrets-gradle-plugin#configuration-options) を参照してみてください。


## CI でのビルド

`local.properties` のファイルがあればよいので、ビルドを実行する前に以下のコマンドでファイルを作成する必要があります。
（以下の例では CI で環境変数 `QIITA_CLIENT_ID` と `QIITA_CLIENT_SECRET` が設定されているものとします）

```
cat <<EOF > local.properties
QIITA_CLIENT_ID=$QIITA_CLIENT_ID
QIITA_CLIENT_ID=$QIITA_CLIENT_SECRET
EOF
```

# 参考サイト

- [Android Developers / カスタム フィールドとリソース値をアプリのコードと共有する](https://developer.android.com/studio/build/gradle-tips?hl=ja#share-custom-fields-and-resource-values-with-your-app-code)
- [google/secrets-gradle-plugin](https://github.com/google/secrets-gradle-plugin)
- [direnv/direnv](https://github.com/direnv/direnv)
- [direnvを使おう](https://qiita.com/kompiro/items/5fc46089247a56243a62)