Play Billing LibraryでAndroidの課金実装してみた

# はじめに
こんにちは。
昨年に引き続きLivesense Advent Calendarで記事を書かせていただくことになりました。
今回は「Play Billing Library」を使ったAndroidの定期購入課金実装の話をしようと思います。

# Play Billing Library
2017年ごろにリリースされた、アプリ内課金を実現するためのライブラリです。
課金サービスとの接続の管理や通信処理、課金を行うためのモーダル表示をすることができます。

このライブラリは2年ごろにバージョンアップが行われ、その度に古いバージョンの足切りがあり課金ができなくなるため、バージョン管理には気をつけましょう。

https://developer.android.com/google/play/billing/integrate?hl=ja

# 課金処理の流れ
1. アプリで課金サービスへの接続を行う
1. 接続完了後、ユーザー操作による購入のタイミングで課金モーダルを表示する
1. モーダル内の「定期購入」をタップする
1. Google Play側へ支払いが行われ、レシート情報を取得する
1. アプリからサーバー側へレシート情報を送信する
1. サーバー側でレシート検証を行い、購入情報を登録する
1. サーバー側でレシート情報を元にGoogle Playへ課金承認リクエストを行う
1. 承認結果を受け取り、アプリ側へ購入結果を返す
1. アプリで購入成功・失敗を表示する 

詳細な内容や図解についてはDroidKaigiで説明されている方がいらっしゃったので、こちらを参考にしてみてください。

https://speakerdeck.com/syarihu/re-zero-starting-uses-of-play-billing-library

# 課金の承認について
Androidでは課金ごとに必ず承認（acknowledge）を行う必要があります。
承認が行われない場合は、課金したことにはならず数日以内に課金した分の料金が返却されます。

承認はサーバー側で行うことを推奨しますが、状況に応じてアプリ側でPlay Billing Libraryを使って行うこともできます。

# 実装について
## 前提
Google Play Consoleに定期購入アイテムを登録する必要があります。
アプリのConsoleを開いたら、左メニューの「収益化」セクションの「商品 > 定期購入」を開き、定期購入アイテムを登録してください。

なお、定期購入アイテムは一度登録すると削除できないようなので、アイテムIDを設定する際はご注意ください（アイテム名や価格は後から変更できます）。

ちなみにアプリ内アイテムも同様に登録する必要があります。

## Billing Clientの初期化
ここから実装について説明します。
まずは課金サービスへ接続し購入処理まで行うための `BillingClient` を準備します。

ここで `setListener` をしていますが、リスナーについては後述します。

```kotlin
private val billingClient = BillingClient.newBuilder(context)
  .enablePendingPurchases()
  .setListener(this)
  .build()
```

## 課金サービスへの接続
例えば課金をさせたい画面を表示した際に、課金サービスへ接続しておきます。
課金サービスへ接続する前に購入処理を行っても購入できないので、事前に接続が必要です。

```kotlin
billingClient.startConnection(object : BillingClientStateListener {
  override fun onSetupFinished(result: BillingResult) {
    // resultから接続が完了したか、失敗したかを判定する
  }

  override fun onBillingServiceDisconnected() {
    // 課金サービスへの接続が切れたときに呼ばれる
  }
})
```

## 課金モーダルの表示
Google Play Consoleで登録した課金アイテムIDを指定して、課金モーダルを表示し、ユーザーに購入を促します。

```kotlin
val params = SkuDetailParams.newBuilder()
  .setSkusList(listOf(/* 課金アイテムID */))
  .setType(BillingClient.SkuType.SUBS)
  .build()

billingClient.querySkuDetailsAsync(params) { result, skuDetails ->
  // resultが BillingClient.BillingResponseCode.OK で、skuDetailsが取得できていたら表示する
  billingClient.launchBillingFlow(activity, BillingFlowParams.newBuilder().setSkuDetails(skuDetails[0]))
}
```

## 購入完了とキャンセル
購入が完了するか、キャンセルを行うと `PurchasesUpdatedListener` の `onPurchasesUpdated()` がコールされる。
購入が完了した場合は、レシート情報が返ってくるのでサーバー側へ送信して、レシート検証と承認処理を行います。

先に話した `BillingClient` でセットするリスナーは `PurchasesUpdatedListener` のことです。

```kotlin
override fun onPurchasesUpdated(result: BillingResult, purchases: MutableList<Purchase>?) {
  // resultが BillingClient.BillingResponseCode.OK で、purchesesがnullでないなら、サーバー側へレシート情報を送信
}
```

# サーバー側での処理について
この記事はアプリ側の実装紹介のため、サーバー側の処理は簡単に紹介します。
レシート検証と承認にはGoogle Play Developer APIを叩く必要があり、そのためには以下の手順で設定します。

1. Google Cloud Platformでアカウントを作成
2. 作成したアカウントのキー（JSON）を発行
1. Google Play Consoleにアカウントキーを紐づける
1. サーバーからレシート検証APIや承認APIを叩いて正常系が返ってきたら成功 
    1. レシート検証API　https://developers.google.com/android-publisher/api-ref/rest/v3/purchases.products/get
    - 購入承認API　https://developers.google.com/android-publisher/api-ref/rest/v3/purchases.products/acknowledge

詳細な設定方法についてはこちらをご参照ください。

https://documentation.qonversion.io/docs/service-account-key-android

# おわりに
ということで、Androidの課金実装について紹介しました。
自分なりの解釈があり説明力に不安があるのですが、これを見て実装の手助けになれば幸いです。

いよいよ明日で最終日ですが、Livesense Advent Calendar 2021を引き続きお楽しみください。