Google Play 課金実装

公式マニュアル含め、情報はいろいろ落ちているのですが、細かいコードまで書き出すと複雑化して理解しづらいので、簡素化した形で実装の流れを整理しました。

1. Billing Clientの初期化
private lateinit var billingClient: BillingClient
billingClient = BillingClient
    .newBuilder(this)
    .enablePendingPurchases()
    .setListener(purchaseUpdateListener)
    .build()
2. BillingClientStateListener定義 (Billing Client接続/切断時に動作)
val clientStateListener = object : BillingClientStateListener {
    override fun onBillingSetupFinished(billingResult: BillingResult) {
        // Billing Service接続(startConnection)後の処理
        // ユーザ課金実績の課金情報を取得してアプリの動作を変えるなど
    }
    override fun onBillingServiceDisconnected() {
        // Billing Service切断(endConnection)完了後の処理
    }
3. PurchasesUpdateListener定義 (購入処理後に動作)
val purchaseUpdateListener = object : PurchasesUpdatedListener {
    override fun onPurchasesUpdated(
        billingResult: BillingResult?,
        purchases: MutableList<Purchase>?
    ) {
        purchases?.forEach { purchase ->
            // 購入の事後処理
            // アプリ側で課金情報を保持するなら、その登録可否次第で承認可否を制御するなど
            handlePurchase(purchase)
        }
    }
}
4. Billing Serviceへの接続
billingClient.startConnection(clientStateListener)
5. 購入処理後の承認処理 (onPurchaseUpdateから呼び出し)

fun handlePurchase(purchase: Purchase) {
    if (purchase.purchaseState == Purchase.PurchaseState.PURCHASED) {
        val acknowledgePurchaseResponseListener = AcknowledgePurchaseResponseListener { }

        if (!purchase.isAcknowledged) {
            val acknowledgePurchaseParams = AcknowledgePurchaseParams.newBuilder()
                .setPurchaseToken(purchase.purchaseToken)
                .build()
            billingClient.acknowledgePurchase(acknowledgePurchaseParams, 
                acknowledgePurchaseResponseListener)
        }
    }
}

6. 課金アイテムの購入ダイアログ呼び出し

// 課金アイテムの詳細情報を取得
suspend fun querySku(skus: List<String>) = suspendCoroutine<List<SkuDetails>?> { continuation ->
    val params = SkuDetailsParams.newBuilder()
    params.setSkusList(skus).setType(BillingClient.SkuType.SUBS)
    this.billingClient.querySkuDetailsAsync(params.build()) { retCode, skuDetailsList ->
        continuation.resume(skuDetailsList)
    }
}

// 課金対象の購入ダイアログを表示
fun showBillingDialog(sku: Skus, scope: CoroutineScope, activity: Activity) {
    scope.launch(Dispatchers.IO) {
        val skuDetails = runBlocking { querySku(listOf(sku.id)) } ?: return@launch
        if (skuDetails.isEmpty()) return@launch
        val params = BillingFlowParams.newBuilder().setSkuDetails(skuDetails.get(0)).build()
        withContext(Dispatchers.Main) {
            billingClient.launchBillingFlow(activity, params)
        }
    }
}

ここまで定義できれいれば、何かしらのActivityよりshowBillingDialog()を呼び出せば購入処理および購入完了までの手続きが流れていきます。

ステータス管理しつつ、下記ステップをきちんと踏めれば(非同期処理の入れ違いに注意)実装は思ったよりも簡単にできると思います。

  1. billingClient.startConnection
  2. onBillingSetupFinished
  3. billingClient.launchBillingFlow
  4. onPurchaseUpdate
  5. billingClient.acknowledgePurchase

シェアする

  • このエントリーをはてなブックマークに追加

フォローする