AndroidアプリでDevOpsを導入する方法

**DevOps**とは、ソフトウェアの納品を自動化するための有名なプラクティスのセットを指します。デザインによって、**DevOps**はメンテナンスと更新を容易にします。

*本ブログは英語版からの翻訳です。オリジナルは[こちら](https://www.alibabacloud.com/blog/android-devops%EF%BC%9Afrom-a-single-push-command-to-production_145532)からご確認いただけます。一部機械翻訳を使用しております。翻訳の間違いがありましたら、ご指摘いただけると幸いです。*

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/a2b2e211-7c96-689c-a0fd-f751074d8c6e.png)

#序章
DevOpsとは、ソフトウェアの納品を自動化するための有名なプラクティスのセットを指します。設計上、DevOpsは、継続的なテスト、コード品質の向上、機能開発を通じたメンテナンスと更新を容易にします。DevOps を利用する主な目的の 1 つは、開発者が人間の干渉を受けることなく、迅速で信頼性の高い自動パブリッシングを実行できるようにすることです。このドキュメントでは、AndroidアプリでDevOpsを実装する方法を説明します。

#継続的インテグレーション
継続的な配信を実現するためには、堅牢な継続的インテグレーションが不可欠です。継続的インテグレーションはAndroid環境の中でも簡単に利用できますが、もう一度おさらいしておきましょう。

すべての Android アプリは継続的インテグレーションをサポートする必要があります。実際、継続的インテグレーションは、現代のアプリ開発に次のようないくつかの大きなメリットをもたらします。

- ビルドの自動化：この機能を使えば、"でも自分のコンピュータでうまくビルドできる "ということはなくなります。代わりに、必要な場所でアプリをビルドすることができます。
- プロアクティブなデバッグ：各プッシュ後にアプリをビルドすることで、潜在的なエラーを早期に発見することができます。
- 継続的なテスト：この機能により、継続的なテストが可能になります。
- 継続的なパッケージング：この機能により、バイナリ コードのパッケージング中のヒューマン エラーを排除できます。
- パブリッシングの高速化:：すべてのビルドステップで信頼性が高まるため、パブリッシュが簡素化されます。
- 信頼性の向上：コードを信頼し、予期せぬエラーを減らすことができます。


#典型的で連続的なインテグレーションプロセス
継続的インテグレーションを導入する前に、JenkinsやTravisなどのインテグレーションサーバを用意する必要があります。継続的インテグレーションに関わるステップは以下の通りです。

1、ソースコードリポジトリ（GitやSVNなど）でのプッシュが完了すると、ジョブが開始されます。このジョブは、開発チャンネルを表示し、コードをコンパイルし、ユニットテストを実行し、APKのパッケージ化とデバッグを行います。
2、最初のジョブが成功すると、次のジョブが開始されます。このジョブは、（Espresso または Robotium を通じて）統合テストを実行し、シナリオの再現や画像の内容を確認することで、ユーザーエクスペリエンスの品質を確保します。これを行うには、接続デバイス（CIサーバの入手が困難な場合はこれは厳しいかもしれません）、Genymotion、またはAndroid Studio 2.0（推奨）に付属の最新の内蔵シミュレータを操作に利用することができます。
3、別のジョブでコード計測（Sonarqube経由など）を実行して、コードの品質を監視します。例えば、このジョブを毎日深夜に実行します。
4、最後に、マスターブランチをプッシュしたり、ブランチを公開したりした後に、別のジョブを実行します。このジョブはコードをコンパイルした後、APKを生成して公開します。

以上です。ご覧のように、プロセス全体が単純であるだけでなく、継続的インテグレーションのすべての利点を確実に実装することができます。

#テストが鍵を握る
アプリが期待通りに動作することを証明する唯一の方法なので、テストは非常に重要です。優れたテストコードを書くのに役立つツールはたくさんありますが、それでも情報に基づいた選択をしなければなりません。

また、アプリに統合する関数ライブラリを選択する際には、実用的でなければなりません。実際、より高いテストカバレッジを持つ関数ライブラリは、アプリのテストを容易にすることを理解する必要があります。なぜなら、これらのライブラリは、テストの精度だけでなく、テストを通じて開発を改善する方法も考慮しているからです（IMO、OkHttp、Retrofitはすべて良い例です）。

Daggerのような関数ライブラリもテスト性を高めることができます。実際、コードを適切に分離してテストを簡素化する「単一責任原則」に従うことを強制されます。

ロバストな継続的インテグレーションの実装に慣れたところで、アップグレードプロセスの例を見てみましょう。


#継続的なデリバリー：無制限のアップグレード
Trainline EUは、予約アプリ「Captain Train」の新バージョンを6週間ごとにリリースしています。現在はベータ段階で、4つのロケール、4つの言語環境、3種類のデバイス（スマホ、7インチ、9インチタブレット）に対応しています。開発者はリリースノートを作成し、ロールアウト機能を利用し、72枚のスクリーンショットをアップロードしており（スクリーンショット6枚 4ロケール3種類）、これにはAndroid Wearのコンパニオンがあり、現在はテスト段階にあります。

このアップグレード作業には時間がかかります。同社では最近、可能な限りバージョンリリースを加速させるために、プロセスの自動化に本気で取り組んでいます。さらに、この自動化によってヒューマンエラーを排除し、リリースされた異なるバージョン間での一貫性を確保しています。開発者はリリースプロセス全体をコントロールすることができ、マーケティングチームはリリースされた異なるバージョンに変更を統合するために彼らと協力する必要があります。

開発者はAndroidのあらゆる側面をコントロールできないので、Googleは必要なツールを開発者に提供しなければなりません。例えば、Googleは開発者がGoogle Playコンソールと簡単にやりとりできるように、HTTP APIを提供しています。また、GoogleはJava（これは必須）、Python、Rubyなどの様々な開発言語のクライアントを提供しています。

このドキュメントでは、Android開発者にとって最もよく知られているクライアントであるJavaクライアントについて主に説明します。


#パブリッシャーの開発
このプロセスには 2 つのステップがあります: クライアントを有効にするためにコンソールを設定し、次に API を検出します。設定は、Google との接続を確立しようとする際に最も難しい部分です。

###設定
まず、プロジェクトがない場合は、Googleコンソールでプロジェクトを作成する必要があります。次に、`Google Play Android Developer API`を有効にします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/05462295-dd42-c0c4-caac-18f222aeefe5.png)


完了したら、サービスアカウントキー型のクレデンシャルを作成します。

次に、`サービスアカウントキー`型の証明書を作成します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/98bb7df6-523c-0d15-7bcf-5c1f2d6fed64.png)

テーブルを完成させ、JSON証明書ファイルをダウンロードします。この間に、`private_key_id`、`private_key`、`client_email`の3つの値を保存する必要があります。`private_key`の値をその`secret.pem`ファイルに保存します。

これで開発者コンソールの準備は完了です。次に、2つ目のコンソールに移動します。

開始するには、Google Play[コンソール](https://play.google.com/apps/publish?spm=a2c65.11461447.0.0.12985c95o0Gg5V)に接続します。これを行うには、`設定` >`API アクセス`に移動します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/7eb4e27b-c0cb-efd3-1d8d-0bde001f4a77.png)

プロジェクトに接続します。`サービスアカウント`のJSONファイルの`client_email`に入力したメールアドレスを認証します。

以上で必要な手順は完了です。

###APIの発見
Javaクライアントを介してアクセスインターフェイスを設定する必要があります。これを行うには、パブリッシャーでJavaプロジェクトを作成し、以下の依存関係（maven centralで入手可能）を追加します。

コンパイル 'com.google.apis:google-api-services-androidpublisher.
v2-rev20-1.21.0'をコンパイルします。

そして、新しい`AndroidPublisher`を作成します。これを行うには、まず、クライアント接続、JSON ファクトリ、`private_key_id` に対応する秘密鍵 ID、`client_email` に対応するアカウント ID、`ANDROIDPUBLISHER` の範囲、`private_key` に対応し、秘密鍵情報を含む鍵ファイルを `GoogleCredential` に更新します。

そして、アプリパッケージを使用して`AndroidPublisher`インスタンスを作成します。

```
http = GoogleNetHttpTransport.newTrustedTransport();
json = JacksonFactory.getDefaultInstance();

Set<String> scopes =
      Collections.singleton(AndroidPublisherScopes.ANDROIDPUBLISHER);

GoogleCredential credential = new GoogleCredential.Builder().
                setTransport(http).
                setJsonFactory(json).
                setServiceAccountPrivateKeyId(KEY_ID).
                setServiceAccountId(SERVICE_ACCOUNT_EMAIL).
                setServiceAccountScopes(scopes).
                setServiceAccountPrivateKeyFromPemFile(secretFile).
                build();

publisher = new AndroidPublisher.Builder(http, json, credential).
                setApplicationName(PACKAGE).
                build();
```

AndroidPublisherは、Google APIのメインエントリーです。コンソールから取得したいデータを修正できる「edits」メソッドを提供しています。

新しいバージョンを作成するには、"insert "リクエストから始めて、その "id "を保存しなければならず、これはその後の各呼び出しの間に使用されます。

```
AndroidPublisher.Edits edits = publisher.edits();

AppEdit edit = edits.insert(PACKAGE, null).execute();
String id = edit.getId();
```

これで、コンソールデータの修正を始めることができます。例えば、ランキングを変更することができます。

```
Listings listings = edits.listings();

Listing listing = new Listing().
                        setFullDescription(description).
                        setShortDescription(shortDescription).
                        setTitle(title);

listings.update(PACKAGE, id, "en_US", listing).execute();
```

スクリーンショットをアップロードすることもできます。

```
Images images = edits.images();
FileContent content = new FileContent(PNG_MIME_TYPE, file);
images.upload(PACKAGE, id, "en_US", "phone5", content).execute();
```

最後に、APKをアップロードします。

```
// APK upload
Apks apks = edits.apks();
FileContent apkContent = new FileContent(APK_MIME_TYPE, apkFile);
Apk apk = apks.upload(PACKAGE, id, apkContent).execute();
int version = apk.getVersionCode();

// Assign APK to Track
Tracks tracks = edits.tracks();
List<Integer> versions = Collections.singletonList(version)
Track track = new Track().setVersionCodes(versions);
tracks.update(PACKAGE, id, "production", track).execute();

// Update APK listing
Apklistings apklistings = edits.apklistings();
ApkListing whatsnew = new ApkListing().setRecentChanges(changes);
apklistings.update(PACKAGE, id, version, "en_US", whatsnew).execute();
```

この[インターフェイス](https://developers.google.com/android-publisher/api-ref/?spm=a2c65.11461447.0.0.12985c95o0Gg5V)を深く理解することをお勧めします。それは非常に強力であり、最小の複雑さを持っています。

最後に、バージョンを提出しなければなりません。実際、Google はあなたの変更要求をすべて記録しますが、あなたがバージョンを提出しない限り保存しません。提出前にそれらの変更を検証する必要があります。

edits.validate(PACKAGE, id).execute().
edits.commit(PACKAGE, id).execute().

ご覧のように、コードの最初に取得した ID をトランザクション ID として使用することができます。トランザクションを開始するために変更内容の `insert, update/upload` をコールすることで、変更内容を検証してコミットすることができます。

#結論
現在、AndroidアプリはDevOps活動をサポートし、堅牢な継続的デリバリー機能を提供しています。キャプテン・トレインの例では、開発者はパブリッシングツールを開発して、各ステップと主要なステップの内容を完全に制御することができます。リリースタスクが完了すると、スクリプトとして実行することができます。同様に、[Jenkins](https://github.com/jenkinsci/google-play-android-publisher-plugin?spm=a2c65.11461447.0.0.12985c95o0Gg5V)プラグインや[Gradle](https://github.com/Triple-T/gradle-play-publisher?spm=a2c65.11461447.0.0.12985c95o0Gg5V)プラグインを使っても同じ目的で利用できます。ただし、この方法では注意が必要で、本番処理をしているときにはバックグラウンドで運用状況を監視することを忘れないようにしなければなりません。

このようなツールやプロセスを利用することで、マスターブランチをプッシュするだけで、本番環境で新しいバージョンをリリースすることができます。このような配置は、高いレベルのシンプルさ、効率性、信頼性を提供します。

明らかに、ある状況に適用される方法が、すべてのチーム、企業、アプリに適用されるとは限りません。そのため、ニーズとチームのダイナミクスに基づいて適切な方法を決定する必要があります。継続的な配信はすべての開発チームの共通の目的であるべきです。

*アリババクラウドは日本に２つのデータセンターを有し、世界で60を超えるアベラビリティーゾーンを有するアジア太平洋地域No.1(2019ガートナー)のクラウドインフラ事業者です。
アリババクラウドの詳細は、こちらからご覧ください。
[アリババクラウドジャパン公式ページ](https://www.alibabacloud.com/ja)*