mcpField
R
rc-error-handling

rc-error-handling

github.com/revenuecat開発76643 回インストール1 日前に更新
リポジトリ

rc-error-handling について

Android 開発者向けに、RevenueCat SDK の購入関連エラー処理を説明するスキルです。例外の選択、エラーコード別の対応、ユーザー向けメッセージ、SDK 内部の再試行動作を扱います。

主な機能

  1. 01SDK 呼び出しに応じた例外型の選択
  2. 02安定したエラーコードによる処理
  3. 03ユーザーキャンセルと購入失敗の区別
  4. 04技術エラーからユーザー向け文言への変換
  5. 05重複する再試行ループの回避

活用シーン

  1. 01キャンセルまたは保留中の購入への対応
  2. 02ネットワークやストアのエラーへの対応
  3. 03技術ログを見せずに変換済みメッセージを表示

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/revenuecat/ai-toolkit --skill rc-error-handling

インストール後、Claude Code で/rc-error-handlingを入力して読み込まれたか確認します。

詳細

エラー処理

フェーズ 1:理解する

Google Play Billing をそのまま使う場合は、すべての BillingResponseCode を列挙し、再試行可能なグループと再試行不可能なグループに分けて、バックオフ再試行のロジックを構築します。RevenueCat では、扱う型が PurchasesError ひとつにまとめられています。

public class PurchasesError(
    val code: PurchasesErrorCode,
    val underlyingErrorMessage: String? = null,
) {
    val message: String // technical description, for logs
}

把握しておくべき重要な点:

  • PurchasesErrorCode は、安定した読みやすいコードを持つクロスプラットフォームの列挙型です。
  • error.message は技術的な文字列です。UI ではなく、ログに記録してください。
  • awaitPurchase() は PurchasesTransactionException をスローします。この例外には userCancelled: Boolean フラグが追加されています。
  • それ以外のすべての await* 呼び出し(awaitOfferings、awaitGetProducts、awaitCustomerInfo、awaitRestore)は PurchasesException をスローします。
  • SDK は一時的な課金エラーやネットワークエラーを内部ですでに再試行します。エラーが呼び出し元に届いた時点で、SDK の再試行回数は上限に達しています。独自のバックオフループを追加する必要はありません。実装する再試行は、ユーザーが操作する「もう一度試す」ボタンだけです。

フェーズ 2:計画する

catch ブロックを書く前に、次の 3 点を決めます。

  1. どの await* 呼び出しをラップしますか?これによって例外の型が決まります。
  2. どのコードを個別に処理しますか?それ以外はすべて汎用の分岐に入ります。
  3. 処理する各コードに、どのユーザー向けメッセージを割り当てますか?

この表を使って PurchasesErrorCode の値を分類し、UX での対応を選びます。

コード意味対応
PurchaseCancelledErrorユーザーがフローを中断しました何もしません。userCancelled も true です。
ProductAlreadyPurchasedErrorユーザーはすでにこの商品を利用中ですCustomerInfo を更新し、エンタイトルメントを確認します。
PaymentPendingError購入が保留状態になりました保留中のメッセージを表示します。UpdatedCustomerInfoListener を待ちます。
NetworkError接続の問題によりリクエストが失敗しました再試行するようユーザーに促します。
StoreProblemErrorGoogle Play の問題です再試行するか、Play ストアを更新するよう促します。
PurchaseNotAllowedErrorデバイスまたはアカウントでは購入できません理由を説明するメッセージを表示します。
IneligibleErrorユーザーはこのオファーの対象ではありません基本プランを表示します。

例外型の判断:

呼び出しキャッチする例外userCancelled を利用できますか?
awaitPurchase()PurchasesTransactionExceptionはい
awaitRestore()PurchasesExceptionいいえ
awaitOfferings()PurchasesExceptionいいえ
awaitGetProducts()PurchasesExceptionいいえ
awaitCustomerInfo()PurchasesExceptionいいえ

フェーズ 3:実行する

購入エラー

まず userCancelled を確認し、該当する場合は何もせずに戻ります。その後、error.code に応じて分岐します。

try {
    val result = Purchases.sharedInstance.awaitPurchase(params)
    handleSuccess(result.customerInfo)
} catch (e: PurchasesTransactionException) {
    if (e.userCancelled) return
    when (e.error.code) {
        PurchasesErrorCode.PaymentPendingError -> showPendingMessage()
        PurchasesErrorCode.ProductAlreadyPurchasedError -> {
            val info = Purchases.sharedInstance.awaitCustomerInfo()
            handleSuccess(info)
        }
        PurchasesErrorCode.NetworkError -> showRetryDialog()
        else -> showGenericError(userFacingMessage(e.error))
    }
}
購入以外のエラー

PurchasesException をキャッチし、コードに応じて分岐します。利用できる場合は、オフライン時やキャッシュ済みの代替手段を使います。

try {
    val offerings = Purchases.sharedInstance.awaitOfferings()
    displayOfferings(offerings)
} catch (e: PurchasesException) {
    when (e.error.code) {
        PurchasesErrorCode.NetworkError -> showOfflineFallback()
        else -> logError(e.error)
    }
}
コードをユーザー向けメッセージにマッピングする

マッピング関数はひとつにまとめてください。e.error.message を UI に渡してはいけません。

fun userFacingMessage(error: PurchasesError): String = when (error.code) {
    PurchasesErrorCode.PurchaseCancelledError -> ""
    PurchasesErrorCode.NetworkError ->
        "Please check your internet connection and try again."
    PurchasesErrorCode.StoreProblemError ->
        "There was a problem with Google Play. Please try again."
    PurchasesErrorCode.ProductAlreadyPurchasedError ->
        "You already have this subscription."
    PurchasesErrorCode.PaymentPendingError ->
        "Your payment is being processed. We'll notify you when it completes."
    else -> "Something went wrong. Please try again."
}

チェックリスト

  • awaitPurchase には PurchasesTransactionException を、それ以外には PurchasesException を選びました。
  • error.code による分岐の前に userCancelled を確認しました。
  • PaymentPendingError、ProductAlreadyPurchasedError、NetworkError をそれぞれ固有のフローで処理しました。
  • error.message をログに記録し、ユーザーには userFacingMessage から取得したメッセージを表示しました。
  • SDK の呼び出しを囲む再試行ループは追加していません。再試行はユーザー操作によってのみ行われます。

参考資料

コメント