rc-purchase-flow について
rc-purchase-flow は、RevenueCat SDK を使う Android 開発者向けに、購入、権限の確認、例外処理を案内するスキルです。取引データの確認や、再インストール・端末変更後の購入復元も扱います。
主な機能
- 01オファリングから購入パッケージを取得
- 02購入を実行し権限に基づいてアクセス制御
- 03キャンセルと購入例外を処理
- 04取引単位のデータを確認
- 05購入を復元して権限を確認
活用シーン
- 01ペイウォールから定期購入または買い切り商品を購入
- 02CustomerInfo を使ってプレミアム機能へのアクセスを制御
- 03ログや独自バックエンドで取引データを利用
- 04再インストールや端末変更後に購入を復元
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ revenuecat/ ai-toolkit --skill rc-purchase-flowインストール後、Claude Code で/rc-purchase-flowを入力して読み込まれたか確認します。
詳細
購入フロー
Android で RevenueCat を通じて購入するには、コードは 2 行で済みます。SDK が課金パラメーター、Play の購入シート、購入トークンの往復、サーバー側での検証、および承認を処理します。渡すパッケージと、返されたエンタイトルメントの処理方法は自分で決めます。
フェーズ 1:awaitPurchase() の動作を理解する
Purchases.sharedInstance.awaitPurchase(params) を 1 回呼び出すと、内部で 6 つのステップが実行されます。これらの処理を自分で記述する必要はありません。
| ステップ | 処理内容 |
|---|---|
| 1 | Package から正しい ProductDetailsParams を使用して BillingFlowParams を構築します |
| 2 | 渡したアクティビティに対して BillingClient.launchBillingFlow() を呼び出します |
| 3 | PurchasesUpdatedListener の結果が届くまで一時停止します |
| 4 | 結果が OK の場合、Play の購入トークンを RevenueCat バックエンドに送信します |
| 5 | バックエンドが purchases.subscriptionsv2.get または purchases.products.get を使って検証します |
| 6 | SDK が Google の 3 日間の期限内に承認(サブスクリプションまたは非消耗型商品)または消費(消耗型商品)を行います |
呼び出しは PurchaseResult(storeTransaction, customerInfo) を返します。再試行可能なエラーは自動的に再試行されます。
6 ステップの図と全体像については、revenuecat.com の購入フローの章をご覧ください。
フェーズ 2:パッケージを準備する
購入するには、事前にオファリングから Package を取得する必要があります。オファリングを取得し、UI で 1 つ選択して、アクティビティを保持します。
val offerings = Purchases.sharedInstance.awaitOfferings()
val pkg = offerings.current?.monthly ?: return
デフォルトではなく特定のオファーが必要な場合は、SubscriptionOption を解決し、パッケージの代わりにそれを PurchaseParams.Builder に渡します。
val option = pkg.product.subscriptionOptions
?.firstOrNull { it.tags.contains("promo_50_off") }
?: pkg.product.defaultOption
?: return
EU 向けのパーソナライズ価格を表示するには、ビルダーに .isPersonalizedPrice(true) をチェーンして、Play にカスタマイズ価格に関する通知を表示させます。
フェーズ 3:購入を実行する
パラメーターを構築し、購入を待機して、customerInfo を参照してアクセスを制御し、想定される 2 つのエラーブランチを処理します。
try {
val result = Purchases.sharedInstance.awaitPurchase(
PurchaseParams.Builder(activity, pkg).build()
)
val customerInfo = result.customerInfo
if (customerInfo.entitlements["pro"]?.isActive == true) {
navigateToApp()
}
} catch (e: PurchasesTransactionException) {
when {
e.userCancelled -> { /* backed out, do nothing */ }
e.error.code == PurchasesErrorCode.ProductAlreadyPurchasedError ->
showMessage("You already have this subscription")
else -> showError(e.error.message)
}
}
このコードブロックのルール:
PurchaseResultは@Pokoです。フィールドにはresult.customerInfoおよびresult.storeTransactionとしてアクセスします。val (transaction, customerInfo) = resultのように分割代入しないでください。customerInfo.entitlements["<id>"]?.isActive == trueがアクセスを許可する条件です。アクセスを判断するためにstoreTransactionを確認しないでください。awaitPurchaseがスローする例外型はPurchasesTransactionExceptionのみです。これをキャッチし、最初にuserCancelledを確認してから、e.error.codeを確認します。- ユーザーによるキャンセルは、エラーとして表示するものではありません。無視してください。
コルーチンよりコールバックを使いたい場合は、purchaseWith(params, onError, onSuccess) が同等のエントリーポイントです。
フェーズ 4:必要な場合のみ StoreTransaction を確認する
result.storeTransaction は利用できますが、通常は使いません。エンタイトルメントの正しい情報源は customerInfo です。ログ記録や独自のバックエンドのためにトランザクションレベルのデータが必要な場合は、次を参照してください。
| フィールド | 型 | 説明 |
|---|---|---|
orderId | String? | 復元された購入では null です |
purchaseToken | String | Play の生の購入トークン |
productIds | List<String> | トランザクション内の商品 ID |
purchaseTime | Long | エポックからのミリ秒数 |
type | ProductType | SUBS または INAPP |
フェーズ 5:再インストール時または端末切り替え時に復元する
復元では queryPurchasesAsync() を実行し、見つかったすべての購入情報を RevenueCat に送信して、新しい CustomerInfo を返します。購入後と同じ方法でアクセスを制御します。
try {
val customerInfo = Purchases.sharedInstance.awaitRestore()
if (customerInfo.entitlements["pro"]?.isActive == true) {
navigateToApp()
} else {
showMessage("No active purchases found")
}
} catch (e: PurchasesException) {
showError(e.error.message)
}
例外型に注意してください。awaitRestore() がスローするのは PurchasesTransactionException ではなく PurchasesException です。課金シートは表示されないため、確認する userCancelled フラグはありません。
例外型の概要
| 呼び出し | スローされる例外 | userCancelled を持つか |
|---|---|---|
awaitPurchase(params) | PurchasesTransactionException | はい |
awaitRestore() | PurchasesException | いいえ |