GradleのTaskでGooglePlayにAPKとスクショ類をアップロードする ver 2017.Q1

結構前にGoogle Play Developer APIが公開され、それなりに便利そうな割にはあんまり使ってる人を見かけないので、何が便利でどういう問題があるのか、実際に触れ合ってみました。

* 最初に書いときますが、APIだけでは個人的に必要な要望を満たせませんでした。
* Google Playの機能拡張待ちです。

## Google Play Developer APIとは

* Google Playのコンソール画面(アプリを公開したりする画面)の操作を行えるAPI
* 2015.4月現在はv2が提供されている
* 各種言語から扱えるライブラリやサンプルコードが配布されている
	* Javaだと[Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cgoogle-api-services-androidpublisher)とかで配布
* API自体は非常にカンタンに覚えられる

## Gradleからアップロードしたい

Gradleからアップロードできれば、Jenkinsやら流行りのTravisやらCircleやらのCIでアップロードできるし、属人的な部分を減らせるので非常によろしいかと思います。なのでGradleのカスタムタスクとして実装しました。

ついでに、gitのリポジトリにスクリーンショットや説明テキストの変更履歴を残しておけるので良さげですね（たぶん）。

## 事前準備

APIを有効化するには、Google Play Developer ConsoleとGoogle Developer Consoleを往復していろいろと設定をする必要があります。やるのは一回だけなので、多少複雑でも諦めましょう。

### Google PlayのコンソールでAPIを有効化する

APIを利用するためには、GoogleDeveloperConsole上のプロジェクトとGoogle Play Developer Consoleを対応させなければなりません。
GooglePlay Developer Consoleの「設定」→「APIアクセス」から、ガイドに従って既存プロジェクトもしくは新規プロジェクトとGoogle Playをリンクします

### サービスアカウントとp12ファイルを作成する

Google Developer Consoleに移動し、Google Playとリンクしたプロジェクトの「APIと認証」→「認証情報」から「新しいクライアントIDを作成」でサービスアカウントを作成します。

作成するとJSONがDLされますが、必要なのはp12ファイルなので、「新しいP12キーを作成」で*.p12ファイルをダウンロードします。

### サービスアカウントの権限を設定する

サービスアカウントを作成すると、Google Play Developer Consoleの「設定」→「APIアクセス」と「ユーザーアカウントと権限」でサービスアカウントの権限を設定できるので、適度に権限を与えます。

最終的なリリースを含めてやらせるかどうかは判断に迷いますが、今回は試験運用なので製品版のAPK配布はチェックを外しました。

この設定はDeveloperアカウントの所有者しか行えないので、作成権限がある人間が作業するつようがあります。

## Gradleのタスクとしてアップロードする

### dependenciesを修正する

Maven形式でJarを配布しているので気になったら試してください。

build.gradleのbuildscritにmavenのリポジトリURLとclasspathを追加します。アップロード機能はカスタムタスクとして配布されているので、適当にタスクを作成します。

```groovy:build.gradle
buildscript {
    repositories {
        maven { url "http://eaglesakura.github.io/maven/" }
        jcenter()
    }
    dependencies {
        classpath "com.eaglesakura:plugin-ci-support:1.1.196"
    }
}
```

### APKのみをアップロードする

APKのみをアップロードする場合はカンタンで、最低限の認証情報(applicationId,p12ファイル,サービスアカウント)及び、アップロード先のトラック("alpha","beta","rollout","production")とapkファイルへのパスを指定すれば行えます。

```groovy:build.gradle
/**
 * APKのみをアップロードする
 */
task uploadApkOnlyToGooglePlay(type: com.eaglesakura.gradle.task.AndroidGooglePlayPublishTask) {
    applicationId = "アプリのpackage名";
    track = "beta";
    apk = getApk("apkへのパス");
    serviceAccountEmail = "サービスアカウント@${プロジェクト名}.iam.gserviceaccount.com";
    p12 = file("p12ファイルへのパス")
}
```

### APKに更新情報を付与する

Google Playでは、アプリバージョンごとに「更新情報」を付与することができます。更新情報は複数の言語（例えば日本語と英語等）で設定可能なので、1ファイルに全言語分のテキストを記述してもあんまり良いことは無さそうです。

そこで言語ごとフォルダを作成し、その下に"apk.txt"という更新情報を書いたテキストファイルを配置して更新情報を管理することにしました。gitでdiffを管理できるし、githubならWeb上で更新できるので、そこそこ有効な気がします。

言語のフォルダ名は[API仕様](https://developers.google.com/android-publisher/api-ref/edits/listings/update)にある通り、"BCP-47 language tag"の命名規則に従う必要があります。

| 内容 | Path |
|:-----------|:------------|
|日本語の更新内容テキスト|listings/ja-JP/apk.txt|
|英語の更新内容テキスト|listings/en-rUS/apk.txt|

```groovy:build.gradle
/**
 * APKと更新情報をアップロードする
 */
task uploadApkToGooglePlay(type: com.eaglesakura.gradle.task.AndroidGooglePlayPublishTask) {
    applicationId = "アプリのpackage名";
    track = "beta";
    apk = getApk("apkへのパス");
    apkListings = file("lisgings"); // listingsディレクトリのパス
    serviceAccountEmail = "サービスアカウント@${プロジェクト名}.iam.gserviceaccount.com";
    p12 = file("p12ファイルへのパス")
}
```

### アプリの詳細テキストやアイコン・スクリーンショットを更新する

詳細テキストやスクリーンショットも各言語で分けられることが前提なので、これもディレクトリごとに所定のファイルやフォルダを作って管理するようにしました。

これを複数言語対応しようと思うと、結構な量になります。また、今のところ公開するために必要最低限のリソースしか更新に対応していません。

| 内容 | Path |
|:-----------|:------------|
| 携帯電話用スクショ | listings/ja-JP/phone/0.png〜8.png |
|7inchタブレット用スクショ|listings/ja-JP/tablet-7/0.png〜8.png|
|10inchタブレット用スクショ|listings/ja-JP/tablet-7/0.png〜8.png|
|TV用スクショ|listings/ja-JP/tv/0.png〜8.png|
|テレビ用バナー|listings/ja-JP/banner-tv.png|
|プロモーション画像|listings/ja-JP/promo.png|
|宣伝画像|listings/ja-JP/feature.png|
|アプリアイコン|listings/ja-JP/icon.png|
|簡易説明テキスト|listings/ja-JP/shortDescription.txt|
|詳細説明テキスト|listings/ja-JP/fullDescription.txt|
|アプリタイトル|listings/ja-JP/title.txt|

```groovy:build.gradle
/**
 * アプリ情報を更新する
 */
task uploadListingToGooglePlay(type: com.eaglesakura.gradle.task.AndroidGooglePlayPublishTask) {
    applicationId = "アプリのpackage名";
    serviceAccountEmail = "サービスアカウント@developer.gserviceaccount.com";
    p12 = file("p12ファイルへのパス")
    listings = file("listings"); // listingsディレクトリのパス
}
```

### タスクを実行する

コンソールからgradleのタスクを実行するとアップロードを行えます。Jenkins等のCIからでも、Gradleさえ実行可能な環境ならアップロード出来ると思います。

```bash:APKのみをアップロード
./gradlew uploadApkOnlyToGooglePlay
```

```bash:APKと更新情報をアップロード
./gradlew uploadApkToGooglePlay
```

```bash:アプリ内容をアップロード
./gradlew uploadListingToGooglePlay
```

### ソースコード

ソースコード自体は複雑じゃないので、Gradleに直接書いても問題ないかもしれないです。

* [plugin-ci-support](https://github.com/eaglesakura/plugin-ci-support)

## 現時点でのAPIの問題点

### 新規アプリの作成(create系)は行えなさそう

最低限、Google Play Developer Consoleにアクセスして手動で最初のapkをアップロードしなければ、API経由でアップロードできなさそうです。1回手動アップロードすれば「公開」ステータスにする必要はなく、下書き状態のママ準備を全てAPI経由で行えます。

### 公開以降、アップデート時の下書き機能が欲しい

Google Play Developer Consoleはアプリアップデート時に各種テキストやスクリーンショットの「下書き」保存が出来ないようです。なので、uploadListingToGooglePlayでAPI経由でスクリーンショットやテキストをアップロードしてしまうと、いきなり内容が反映されてしまいます。

個人的には、「下書き」状態でアップロードできて、最後まで確認したうえでWeb上で「公開」できるような仕組みも用意されているとありがたかったですね。

### 運用的にどうする？

2017年Q1現在、相変わらずGoogle Playには下書き機能が無く、アプリ説明テキストも公開ライン（beta, production等）で切り替えできません。
ぶっつけ本番運用するか、検証用の別なプロジェクトにアップロードするという作戦を使うしか無いです。