今更ながらAndroid の keystore と 署名(signingConfigs) の管理・運用について考えてみた

## はじめに
AndroidアプリをGoogle Play Storeに公開する上で、[アプリへの署名](https://developer.android.com/guide/publishing/app-signing.html?hl=ja)は避けては通れません。
しかし、以下の理由からあまり意識せずに開発している（できてしまっている）人も多いのではないかと思います。

* 趣味でアプリを作っていて、Google Play Storeに公開するつもりはない
* Android の新機能の技術検証・学習が目的で、サンプルコードを書くだけ
* 開発会社にいて、すでにGoogle Play Storeに公開されているアプリに対して開発を行っている

自分自身もあまり意識せずにいたのですが、新規アプリを作ってGoogle Play Storeに公開しようとした際、keystore の管理方法・signingConfigs の設定が色々あって、それを採用したときのメリット・デメリットを考えてみてまとめました。
こういう方法がある、こうしたほうがもっといいなどありましたら、コメントをお願いします。

## 前提条件
keystoreは、Android Studioで `Build` > `Generate Signed APK...` からGUIで作成することができます。
もしくは、以下のコマンドで作成することもできます。

```
keytool -genkey -v -keystore my-release-key.keystore -alias alias_name -keyalg RSA -validity 10000
```

## app/build.gradle に直接書き込む

```gradle:app/build.gradle
android {
    // ...

    signingConfigs {
        release {
            storeFile file('./release.keystore')
            storePassword 'releaseStorePassword'
            keyAlias 'releaseKeyAlias'
            keyPassword 'releaseKeyPassword'
        }
    }

    buildTypes {
        release {
            signingConfig signingConfigs.release
        }
    }
}
```
これが一番楽な方法です。
パスワードが直に書いてあるのは好ましくありませんが、
以下の場合なら、採用してもいいのかなと思います。

* ローカル環境のみで開発
* privateリポジトリ or 社内LAN上にGit環境 で開発

しかし、この方法を採用するとリリース用の keystore のパスワードの情報がバレバレになってしまうので、以下のような公に見せたくない場合は使えません。

* アプリをOSS運用する場合
* チーム開発する場合

## local.properties から読み込む

```:local.properties
sdk.dir=/XXXX/Android/sdk

RELEASE_STORE_PASSWORD=releaseStorePassword
RELEASE_KEY_ALIAS=releaseKeyAlias
RELEASE_KEY_PASSWORD=releaseKeyPassword
```

```gradle:app/build.gradle
android {
    // ...

    Properties properties = new Properties()
    properties.load(project.rootProject.file('local.properties').newDataInputStream())

    signingConfigs {
        release {
            storeFile file('./release.keystore')
            storePassword  properties.getProperty("RELEASE_STORE_PASSWORD")
            keyAlias properties.getProperty("RELEASE_KEY_ALIAS")
            keyPassword properties.getProperty("RELEASE_KEY_PASSWORD")
        }
    }

    buildTypes {
        release {
            signingConfig signingConfigs.release
        }
    }
}
```
こうすることで、リポジトリに公開しなくない情報を隠すことができます。
`local.properties` はローカル環境で使う設定であり、 `.gitignore` に入れていることが前提です。
ただ、この方法だとパスワード情報を他のメンバーに教える時、テキストを1回1回教えることになり、少し面倒に感じます。
`local.properties` にはローカル環境のAndroid SDKのディレクトリ情報が含まれており、ファイルをただ渡すだけで済ますことができないためです。

## gradle.properties から読み込む

```:gradle.properties
RELEASE_STORE_PASSWORD=releaseStorePassword
RELEASE_KEY_ALIAS=releaseKeyAlias
RELEASE_KEY_PASSWORD=releaseKeyPassword
```

```gradle:app/build.gradle
android {
    // ...

    signingConfigs {
        release {
            storeFile file('./release.keystore')
            storePassword RELEASE_STORE_PASSWORD
            keyAlias RELEASE_KEY_ALIAS
            keyPassword RELEASE_KEY_PASSWORD
        }
    }

    buildTypes {
        release {
            signingConfig signingConfigs.release
        }
    }
}
```
それに加えて、`gradle.properties` を `.gitignore` に追加で入れる必要があります。

この方法でも、リポジトリに公開しなくない情報を隠すことができます。
`gradle.properties` で定義した値は、 `build.gradle` 内でそのまま使うことができるので、`local.properties` のときよりシンプルに書けます。
また、`local.properties`の場合と異なり、`gradle.properties` を渡すだけでパスワード情報を共有できる点も良いです。

ただ、 `gradle.properties` をGit管理する必要が出てきた場合、`local.properties` のときと同じ悲しみが起きてします。
Git管理する必要あるのは、以下の場合です。

* `gradle.properties` にプロジェクト全体にわたるGradle設定（Gradle デーモンの最大ヒープサイズなど）をする場合
* Jenkins や Travis CI などのCI環境でビルドをする場合<br/>`gradle.properties` がないとビルドでエラーになることがあります。

~~実際に経験したプロジェクトで上記の方法を採用してたのですが、1回1回テキストで伝えることが面倒になり、keystore のパスワードを含んだ `gradle.properties` がリポジトリに入っていました。（本末転倒）~~

## gradleファイルを外出して読み込む

```gradle:signingConfigs/release.gradle
signingConfigs {
    release {
        storeFile file('./release.keystore')
        storePassword 'releaseStorePassword'
        keyAlias 'releaseKeyAlias'
        keyPassword 'releaseKeyPassword'
    }
}
```

```gradle:app/build.gradle
android {
    // ...

    apply from: 'signingConfigs/release.gradle', to: android

    buildTypes {
        release {
            signingConfig signingConfigs.release
        }
    }
}
```
それに加えて、`signingConfigs/release.gradle` を `.gitignore` に追加で入れる必要があります。

`signingConfigs` の設定だけを外出して、`apply from` を使って、ファイルを読み込むことができます。
この方法なら、`local.properties` や `gradle.properties` で起きた悲しみは起こりません。
個人的にはこれがベストかなと思っています。