AndroidアプリでGoogle Play Serviceの使用可否を検証する

AndroidアプリでGoogle APIやFirebaseを利用する場合、Google Play Service（Google Play開発者サービス） を介してGoogleの各サービスにアクセスします。
このとき、アプリは端末に入っているGoogle Play Serviceのバージョンが適切かどうかチェックするよう推奨しています。
一例として、[別のエントリ](https://qiita.com/outerlet/items/e3fe96a3d1e15ed42573)でFirebase Cloud Messagingの実装方法について書きましたが、Firebase公式のドキュメントには[こんなこと](https://firebase.google.com/docs/cloud-messaging/android/client#sample-play)が書かれていたりします。

> Play開発者サービスのSDKに依存するアプリについては、Google Play開発者サービス機能にアクセスする前に、互換性のあるGoogle Play開発者サービスのAPKが端末にインストールされているかどうかをアプリが必ずチェックする必要があります。

Googleサービスにアクセスするために必須と思われるこの作業について検証しました。

# Google Play Serviceについて
Androidユーザーなら一度は目にしたことのあるはずの**「Google Play開発者サービス」**がそれです。詳細については[この記事](http://www.atmarkit.co.jp/ait/articles/1501/08/news127.html)など、探せば色々出てきますので気になる方は調べてみてください。
アプリがGoogleの各種サービス（Google MapやGoogle Driveなど）にアクセスするための仲介をしてくれるものだと考えればだいたい間違いないと思います。
<img src="https://developers.google.com/android/images/play-services-diagram.png" width="480" />
Google Play Service自体はAndroidに内包されているものではなく、Google Playで配布されています。
そのため、アプリは**端末がGoogle Play Serviceをサポートしているか**を気にする必要がありません。必要ならGoogle Playからダウンロードして貰うというスタンスです。

# 環境
このページに書かれているコード等は以下の環境下で動作・検証しています。

* macOS Mojave 10.14.4
* Android Studio 3.4.1
* Nexus5x + Android 7.1.2

<details><summary>テスト可能な環境について</summary>書かれている内容をテストするには以下のいずれかが必要です。
<ul><li>PlayストアがインストールされたAndroid4.1以降の端末</li><li>Google APIsプラットフォームが含まれるAndroid4.2.2以上のエミュレータ</li></ul></details>

# Google Play Serviceのセットアップ
Android Studioのメニューから、**Tools > Android > SDK Manager** の順にクリック。
SDK Managerが起動したら、「SDK Tools」タブにある項目のうち「Support Repository」を展開します。
その下に「Google Repository」というのがありますので、これをアップデートしてください。
<img width="640" alt="googleservice01.png" src="https://qiita-image-store.s3.amazonaws.com/0/67520/4999bea4-aafc-6150-6b39-ce6b97409680.png">

# APIの追加
app/build.gradleのdependenciesにビルドルールを追加します。
[公式](https://developers.google.com/android/guides/setup#add_google_play_services_to_your_project)にGoogleサービスごとにdependenciesに追加すべき内容がリストされていますので、必要な記述を追加してください。
本稿ではFirebase Cloud Messagingを使いますので、以下の記述を追加しています。

```Groovy:build.gradle
implementation 'com.google.firebase:firebase-messaging:18.0.0'
```

# バージョンを検証する
バージョンを検証するためには[GoogleApiAvailability](https://developers.google.com/android/reference/com/google/android/gms/common/GoogleApiAvailability)を使います。
以前は GoogleApiClient も使えたのですが、[非推奨](https://developers.google.com/android/guides/google-api-client)になっていました。

GoogleApiAvailability クラスのメソッド isGooglePlayServicesAvailable を使います。
「is〜」で始まるメソッドですが、返ってくるのは Boolean でなく状態を示す Int 値です。この Int 値は、[ConnectionResult](https://developers.google.com/android/reference/com/google/android/gms/common/ConnectionResult)クラスの定数に対応します。

```Kotlin
// 1. Google APIの使用可否を判定
val errorCode = GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(this)

// 2. 1の戻り値を調べて、何が起こったのかログに吐いてみる
Log.i("GOOGLE-SERVICE", when (errorCode) {
    ConnectionResult.SUCCESS -> "The connection was successful."
    ConnectionResult.SERVICE_MISSING -> "Google Play services is missing on this device."
    ConnectionResult.SERVICE_UPDATING -> "Google Play service is currently being updated on this device."
    ConnectionResult.SERVICE_VERSION_UPDATE_REQUIRED -> "The installed version of Google Play services is out of date."
    ConnectionResult.SERVICE_DISABLED -> "The installed version of Google Play services has been disabled on this device."
    ConnectionResult.SERVICE_INVALID -> "The version of the Google Play services installed on this device is not authentic."
    else -> "Unknown."
})
```

# バージョンを検証したあとの対応
端末に適当なバージョンにGoogle Play Serviceが入っていなければ、ダイアログを出してPlayストアで更新するように勧めます。
GoogleApiAvailability#isGooglePlayServicesAvailable で得られるエラーコードを使えば、いくつかの方法でユーザーに更新を促すことができます。
ここでは、ダイアログを出す方法と通知を出す方法を書いておきます。

## ダイアログを出す
Playストアを起動させるダイアログを表示します。リクエストコードを使って、Playストアから戻ってきたタイミングをonActivityResultで捕捉することもできます。

```Kotlin
val requestCode = 10001
GoogleApiAvailability.getInstance().showErrorDialogFragment(this, errorCode, requestCode)
```

ダイアログです。『更新』を押すと、PlayストアのGoogle Play開発者サービスのページが開きます。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/67520/bf986bc5-8757-dd72-fe17-b727808e560b.png" width="320" />

## 通知を出す
Playストアを起動させる通知を表示します。

```Kotlin
googleapiavailability.getinstance().showerrornotification(this, errorcode)
```

1番上がその通知です。タップすると、PlayストアのGoogle Play開発者サービスのページが開きます。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/67520/6ded9804-476f-d04c-8287-cbc079e7849e.png" width="320" />

# バージョンを検証するタイミング
これらの検証は、onCreateやonResumeで行うことを推奨されています。

> メインアクティビティの onCreate() メソッドと onResume() メソッドの 2 か所で行うことをおすすめします。onCreate() では、チェックにパスしないとアプリを使用できないようにします。onResume() では、ユーザーが [戻る] ボタンなどの他の手段を使って実行中のアプリに戻った場合にもチェックされるようにします。

# Google Play開発者サービスの初期化について
これらをテストするためにGoogle Play開発者サービスをダウングレードする必要があるかも知れません。
初期化したい場合は、Android7（Nexus5x）なら設定画面から**セキュリティ > 端末管理アプリと遷移して、『Androidデバイスマネージャー』のチェックを外す**と、Google Play管理者サービスのアプリ詳細画面で『アップデートのアンインストール』が押せるようになります。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/67520/f5c9190d-b207-9060-3bc1-549bfbda4684.png" width="320" />
Android9（Pixel3a）だと、**セキュリティと現在地情報 > 詳細設定 > 端末管理アプリ**で『デバイスを探す』が変更できます。他のバージョンでも同じような場所にあると思われます。

# まとめ
Google Play Serviceのバージョンを検証する方法についてまとめてみました。
余談ですが、Firebase Cloud MessagingはGoogle Play開発者サービスが適切なバージョンでなくてもメッセージが受信できてしまいます。
この判定要らないのかも…とは思うのですが、Google御大が推奨しているので検証した方がいいのでしょう。

# 改訂履歴

* 2019/05/21
    * サンプルコードをKotlinに変更しました。
    * サンプルコードの動作・検証環境を変更しました。
    * 非推奨となったGoogleApiClient関連の記述を削除しました。
    * Playに遷移するためのトリガーに通知を追加しました。