BITRISEを用いたAndroidアプリの自動配布

# BITRISEを用いたAndroidアプリの自動配布
**Androidその２ Advent Calendar 2016** 3日目になります！
ここでは、 Android アプリの最新版を自動でテスターに配布する仕組みを説明します :blush:

## はじめに
友人とアプリ開発を始めることになり、[BITRISE](https://www.bitrise.io/)でAndroidアプリ開発のCI環境を構築しました。
**開発中のapkを友人や家族に使ってもらう際のハードルをできるだけ下げたくて**、Google Play経由でアプリを配布する方法を検討しました。


すでにBITRISEとAndroidの連携は分かりやすい記事がいくつかありますので、
今回はBITRISEを通じてGoogle Play Developer Consoleにα版apkをアップロードする点を中心に記事にしたいと思います。

## 概要
![bitrise.jpeg](https://qiita-image-store.s3.amazonaws.com/0/107434/dd7955e7-6b98-dc3e-2600-07f444950c39.jpeg)

* 背景
	* GitHubのdevelopブランチ更新時に、apkをα版としてGoogle Playに自動アップロードしたい
	* β版はGoogle Play経由でα版からプロモートしたい

* やったこと
	* `gradle-play-publisher`でGoogle Playに自動アップロードするgradle taskを作成する
	* apkのバージョンをBITRISEのビルド番号に対応づける
	* BITRISEでアプリのreleaseビルドを自動化する
	* BITRISEでGoogle Playへのアップを自動化する

> バージョンをインクリメントしないとGoogle Playにアップロードできないので注意

## 手順
### 1. Google Playのサービスアカウントのキーファイルを取得する
* キーファイルを取得

    参考：[【android】apkのuploadを自動化 - Qiita](http://qiita.com/AAkira@github/items/895713b505c3d2fe85b1)
\# 本記事では推奨通りjson形式で取得

### 2. `gradle-play-publisher`でGoogle Playにアップロードするgradle taskを作成する
* `build.gradle(Project)`を修正
    * `gradle-play-publisher`を`dependencies`に追加する

````build.gradle(Project)
buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:2.2.1'
　　　　　// gradle-play-publisherのプラグインの読み込み設定を追加
        classpath 'com.github.triplet.gradle:play-publisher:1.1.5'
    }
}

allprojects {
    repositories {
        jcenter()
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}
````


* `build.gradle(Module)`を修正
    * `gradle-play-publisher`のプラグインの読み込み設定を追加する
    * バージョン情報をgradleの実行オプション化する
    * キーストアをgradleの実行オプション化する

````build.gradle(Module)
apply plugin: 'com.android.application'
// gradle-play-publisherのプラグインの読み込み設定を追加
apply plugin: 'com.github.triplet.play'

// gradle実行オプションからバージョン情報を取得
final exampleVersionCode = hasProperty('version_code') ? property('version_code').toInteger() : 1
final exampleVersionName = hasProperty('version_name') ? '0.1.0.' + property('version_name') : '0.1.0.0'

// gradle実行オプションからキーストアを取得
final exampleStorePassword = hasProperty('keystore_password') ? property('keystore_password') : ''
final exampleKeyAlias = hasProperty('key_alias') ? property('key_alias') : ''
final exampleKeyPassword = hasProperty('key_password') ? property('key_password') : ''
final exampleStoreFile = hasProperty('key_file') ? property('key_file') : ''
final examplePlayJson = hasProperty('play_json') ? property('play_json') : ''

android {
    compileSdkVersion 25
    buildToolsVersion "24.0.1"

　　// gradle実行オプションからキーストアを取得
    signingConfigs {
        src {
            storeFile file(exampleStoreFile)
            storePassword exampleStorePassword
            keyAlias exampleKeyAlias
            keyPassword exampleKeyPassword
        }
    }
    defaultConfig {
        applicationId "com.sjn.demo.bitrisedemo"
        minSdkVersion 14
        targetSdkVersion 25
　　　　　// gradle実行オプションからバージョン情報を取得
        versionCode exampleVersionCode
        versionName exampleVersionName
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
　　　　　　　// gradle実行オプションからキーストアを取得
            signingConfig signingConfigs.src
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
    compile 'com.android.support:appcompat-v7:25.0.0'
    testCompile 'junit:junit:4.12'
}

// GooglePlayサービスアカウントを設定
play {
    track = 'alpha'
    serviceAccountCredentials = file(examplePlayJson)
}
```

* `gradle.properties(global)`の修正
    * ローカル環境でもreleaseビルドができるようにキーストアの設定とGoogle Playのサービスアカウントの設定を追加します

```gradle.properties
key_password=password
keystore_password=password
key_alias=alias
key_file=/path/to/keystore
version_code=1
version_name=0.1
play_json=/path/to/json
```
> * ファイルパスについては、参照されなくても正しい場所を設定しておかないとビルドエラーになるので設定が必要です。(他に方法がありそう)  
> * `version_code`, `version_name`はローカルでビルドしたものをリリースすることはないと思うので適当に設定します。
> * `play_json`は「1. Google Playのサービスアカウントのキーファイルを取得する」でダウンロードしたファイルです。
> * キーストアの参考：[さぁAPKつくるか！keystore....( ﾟдﾟ)ﾊｯ? - Qiita](http://qiita.com/toguri/items/6c17cec931a83a5ae5e9)

### 3. 確認
1. Terminalでgradle taskを確認する
    
        $ ./gradlew tasks


2. 以下のようなtaskが定義されていることを確認する
    
        Play Store tasks
        ----------------
        bootstrapReleasePlayResources - Downloads the play store listing for the Release build. No download of image resources. See #18.
        generateReleasePlayResources - Collects play store resources for the Release build
        publishApkRelease - Uploads the APK for the Release build
        publishListingRelease - Updates the play store listing for the Release build
        publishRelease - Updates APK and play store listing for the Release build


### 4. Webページからアプリをアップロードする(初回のみ)
下記の通り、最初の１回目はWebからアップロードする必要があります。

```
FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':app:publishApkRelease'.
> No application was found for the package name com.example.myapplication. Is this the first release for this app? The first version has to be uploaded via the web interface.
```

#### signedApkの作成
1. Android Studioのメニューから「Build」を選択
2. 「Generate Signed APK...」を選択
3. 「Next」
4. `gradle.properties`と同様の入力をして「Next」
> ここで使うkeyStoreはBITRISEに登録するものと共通にしてください

5. 「Finish」 
6. `app`以下に`app-release.apk`が生成

#### signedApkのアップロード
1. [Google Play Developer Console](https://play.google.com/apps/publish/?hl=JA)にアクセス
2. 「新しいアプリを追加」
3. 「APKをアップロード」
4. 「アルファ版テスト」
5. 生成した`app-release.apk`をアップロード

### 5. BITRISEにworkflowを作成する
1. GitHubにリポジトリを作る
2. 「Add New App」から下記のとおり設定
参考：[Android用CI環境をBitriseで構築 - Qiita](http://qiita.com/e-takazawa/items/b1d6ff8acccc462e198b)
> * Connect your repository
>     * 「1.」で作ったリポジトリを選択
>     * 「No, auto-add SSH-Key」
> * Validation setup
>     * 今回は「develop」
> * Project build configuration
>     * 「Select Gradle task to run」で「assembleRelease」を選択し「confirm」
> * Webhook setup
>     * 「Register a Webhook for me!」
> 
> \# privateなリポジトリだと違うかもしれないです。

3. Workflowを修正する
#### Code signing & Files
| ファイル | 内容 | 備考 |
|:----------:|:----------:|:------------:|
| キーストア   | リリース用のkeyStore | パスワードやエイリアスを入力 |
| キーファイル | 「1. Google Playのサービスアカウントのキーファイルを取得する」で取得した`***.json` | `unique id`は`PLAY`にしました |
#### App Env Vars
| 変数名 | 値 | 備考 |
|:----------:|:----------:|:------------:|
| GRADLE_BUILD_FILE_PATH   | build.gradle | |
| GRADLE_TASK | publishApkRelease | |
| GRADLEW_PATH | ./gradlew | |
| KEYSTORE_PATH | $BITRISE_SOURCE_DIR/[アップしたキーストアのファイル名] | Ex. `$BITRISE_SOURCE_DIR/release.jks`|
| PLAY_KEY_PATH | $BITRISE_SOURCE_DIR/[アップしたキーファイルのファイル名] | Ex. `$BITRISE_SOURCE_DIR/play.json`|
| GRADLE_PUBLISH_OPTION | `--stacktrace -Pkey_password=$BITRISEIO_ANDROID_KEYSTORE_PRIVATE_KEY_PASSWORD -Pkeystore_password=$BITRISEIO_ANDROID_KEYSTORE_PASSWORD -Pkey_alias=$BITRISEIO_ANDROID_KEYSTORE_ALIAS -Pkey_file=$KEYSTORE_PATH -Pversion_code=$BITRISE_BUILD_NUMBER -Pversion_name=$BITRISE_BUILD_NUMBER -Pplay_json=$PLAY_KEY_PATH` |  |
#### Triggers
| タブ | トリガー | 対象ブランチ |
|:----------:|:----------:|:------------:|
| PUSH   | PUSH BRANCH | develop|
| PULL REQUEST | SOURCE BRANCH | develop |
|  | TARGET BRANCH | * |
#### Workflow
| 番号 | Work | 変更項目 | 値 |
|:----------:|:----------:|:----------:|:------------:|
| 1 | Activate SSH key (RSA private key) |変更なし | |
| 2 | Git Clone Repository | 変更なし | |
| 3 | Do anything with Script step | 変更なし | |
| 4 | Update Android Extra packages | 変更なし | |
| 5 | File Downloader | Download source url | $BITRISEIO_PLAY_URL |
| |  | Download destination path | $PLAY_KEY_PATH |
| 6 | File Downloader | Download source url | $BITRISEIO_ANDROID_KEYSTORE_URL |
| |  | Download destination path | $KEYSTORE_PATH |
| 7 | Gradle Runner | Additional options for Gradle call | $GRADLE_PUBLISH_OPTION |
| 8 | Deploy to Bitrise.io | 変更なし | |


## 実際に動かす
* GitHub経由じゃなくても、画面のbuildボタンでビルド開始できます。

できました！！:tada:
#### BITRISE
<img width="1857" alt="スクリーンショット 2016-12-02 15.20.12.png" src="https://qiita-image-store.s3.amazonaws.com/0/107434/9cfdca2b-698a-eaa7-fecc-828c752b0834.png">
#### GooglePlayDeveloperConsole
<img width="1459" alt="スクリーンショット 2016-12-02 15.20.00.png" src="https://qiita-image-store.s3.amazonaws.com/0/107434/acb0234f-4d1a-d699-32ef-afa7bd4a161e.png">


> * 時差がありますが、11:23のトリガーでPublishできてます。
> * bitriseのbuild番号に対応したアプリバージョンになってます。
> * α版のテストが終わったら画面からβ版にプロモートします。

---

以上で、労力をかけずに常に最新版のアプリをテスターに配布できるようになりました！
アプリ配布を自動化することで開発に集中できます :innocent:
最新のアプリのフィードバックをもらい顧客に届く価値をドンドン増やしていきましょう！！！！