フローとペイウォールのイベント処理 - Android

このガイドでは、購入・復元・プロダクト選択・フロー表示に関するイベント処理について説明します。ボタンの処理(フローを閉じる、リンクを開くなど)も別途実装する必要があります。詳しくはボタンアクションの処理に関するガイドをご覧ください。

Flow BuilderPaywall Builderで設定したフローやペイウォールは、購入や復元のための追加コードは不要です。ただし、アプリが応答できるイベントが発生します。これらのイベントには、ボタン押下(閉じるボタン、URL、プロダクト選択など)や購入関連アクションの通知が含まれます。これらのイベントへの応答方法については、以下をご覧ください。

Adapty SDK がモバイルアプリにどのように統合されているか、実際の例を見てみませんか?ペイウォールの表示、購入処理、その他の基本機能を含む完全なセットアップを実演しているサンプルアプリをご覧ください。

購入画面で行われるプロセスを制御・監視する必要がある場合は、AdaptyFlowEventListener のメソッドを実装してください。 デフォルトの動作をそのまま使いたい場合は、AdaptyFlowDefaultEventListener を継承して、変更したいメソッドのみをオーバーライドできます。

以下は AdaptyFlowDefaultEventListener のデフォルト動作です。

ユーザー生成イベント

プロダクトの選択

プロダクトが(ユーザーまたはシステムによって)購入のために選択されると、このメソッドが呼び出されます:

public override fun onProductSelected(
    product: AdaptyPaywallProduct,
    context: Context,
) {}
イベントの例(クリックして展開)
{
  "product": {
    "vendorProductId": "premium_monthly",
    "localizedTitle": "Premium Monthly",
    "localizedDescription": "Premium subscription for 1 month",
    "localizedPrice": "$9.99",
    "price": 9.99,
    "currencyCode": "USD"
  }
}

購入開始

ユーザーが購入プロセスを開始すると、このメソッドが呼び出されます:

public override fun onPurchaseStarted(
    product: AdaptyPaywallProduct,
    context: Context,
) {}
イベントの例(クリックして展開)
{
  "product": {
    "vendorProductId": "premium_monthly",
    "localizedTitle": "Premium Monthly",
    "localizedDescription": "Premium subscription for 1 month",
    "localizedPrice": "$9.99",
    "price": 9.99,
    "currencyCode": "USD"
  }
}

このメソッドはObserverモードでは呼び出されません。詳細は Android - ObserverモードでペイウォールビルダーのペイウォールをPresent する を参照してください。

購入成功、キャンセル、または保留中

購入が成功すると、このメソッドが呼び出されます:

public override fun onPurchaseFinished(
    purchaseResult: AdaptyPurchaseResult,
    product: AdaptyPaywallProduct,
    context: Context,
) {
    if (purchaseResult !is AdaptyPurchaseResult.UserCanceled)
        context.getActivityOrNull()?.onBackPressed()
}
イベント例(クリックして展開)
// Successful purchase
{
  "purchaseResult": {
    "type": "Success",
    "profile": {
      "accessLevels": {
        "premium": {
          "id": "premium",
          "isActive": true,
          "expiresAt": "2024-02-15T10:30:00Z"
        }
      }
    }
  },
  "product": {
    "vendorProductId": "premium_monthly",
    "localizedTitle": "Premium Monthly",
    "localizedDescription": "Premium subscription for 1 month",
    "localizedPrice": "$9.99",
    "price": 9.99,
    "currencyCode": "USD"
  }
}

// Cancelled purchase
{
  "purchaseResult": {
    "type": "UserCanceled"
  },
  "product": {
    "vendorProductId": "premium_monthly",
    "localizedTitle": "Premium Monthly",
    "localizedDescription": "Premium subscription for 1 month",
    "localizedPrice": "$9.99",
    "price": 9.99,
    "currencyCode": "USD"
  }
}

// Pending purchase
{
  "purchaseResult": {
    "type": "Pending"
  },
  "product": {
    "vendorProductId": "premium_monthly",
    "localizedTitle": "Premium Monthly",
    "localizedDescription": "Premium subscription for 1 month",
    "localizedPrice": "$9.99",
    "price": 9.99,
    "currencyCode": "USD"
  }
}

このケースではスクリーンを閉じることをお勧めします。

このメソッドはオブザーバーモードでは呼び出されません。詳細は Android - オブザーバーモードでペイウォールビルダーのペイウォールを表示する をご参照ください。

購入失敗

購入がエラーにより失敗した場合、このメソッドが呼び出されます。Google Play Billing のエラー(支払い制限、無効なプロダクト、ネットワーク障害)、トランザクション検証の失敗、およびシステムエラーが対象です。なお、ユーザーによるキャンセルはキャンセル結果を伴う onPurchaseFinished をトリガーし、保留中の支払いはこのメソッドをトリガーしません。

public override fun onPurchaseFailure(
    error: AdaptyError,
    product: AdaptyPaywallProduct,
    context: Context,
) {}
イベント例(クリックして展開)
{
  "error": {
    "code": "purchase_failed",
    "message": "Purchase failed due to insufficient funds",
    "details": {
      "underlyingError": "Insufficient funds in account"
    }
  },
  "product": {
    "vendorProductId": "premium_monthly",
    "localizedTitle": "Premium Monthly",
    "localizedDescription": "Premium subscription for 1 month",
    "localizedPrice": "$9.99",
    "price": 9.99,
    "currencyCode": "USD"
  }
}

このメソッドはオブザーバーモードでは呼び出されません。詳細については、Android - オブザーバーモードでペイウォールビルダーのペイウォールを表示するトピックを参照してください。

ウェブ決済ナビゲーションの完了

このメソッドは、特定のプロダクトのウェブペイウォールを開こうとした後に呼び出されます。ナビゲーションの成功・失敗にかかわらず呼び出されます。

public override fun onFinishWebPaymentNavigation(
    product: AdaptyPaywallProduct?,
    error: AdaptyError?,
    context: Context,
) {}

パラメーター:

パラメーター説明
productウェブペイウォールが開かれた AdaptyPaywallProductnull の場合があります。
errorウェブペイウォールのナビゲーションに失敗した場合は AdaptyError オブジェクト、成功した場合は null
イベントの例(クリックして展開)
// Successful navigation
{
  "product": {
    "vendorProductId": "premium_monthly",
    "localizedTitle": "Premium Monthly",
    "localizedDescription": "Premium subscription for 1 month",
    "localizedPrice": "$9.99",
    "price": 9.99,
    "currencyCode": "USD"
  },
  "error": null
}

// Failed navigation
{
  "product": {
    "vendorProductId": "premium_monthly",
    "localizedTitle": "Premium Monthly",
    "localizedDescription": "Premium subscription for 1 month",
    "localizedPrice": "$9.99",
    "price": 9.99,
    "currencyCode": "USD"
  },
  "error": {
    "code": "web_navigation_failed",
    "message": "Failed to open web paywall",
    "details": {
      "underlyingError": "Browser unavailable"
    }
  }
}

購入の復元成功

購入の復元が成功すると、このメソッドが呼び出されます:

public override fun onRestoreSuccess(
    profile: AdaptyProfile,
    context: Context,
) {}
イベントの例(クリックして展開)
{
  "profile": {
    "accessLevels": {
      "premium": {
        "id": "premium",
        "isActive": true,
        "expiresAt": "2024-02-15T10:30:00Z"
      }
    },
    "subscriptions": [
      {
        "vendorProductId": "premium_monthly",
        "isActive": true,
        "expiresAt": "2024-02-15T10:30:00Z"
      }
    ]
  }
}

ユーザーが必要な accessLevel を持っている場合は、画面を閉じることを推奨します。確認方法については、サブスクリプションの状態 を参照してください。

復元の失敗

Adapty.restorePurchases() が失敗した場合、このメソッドが呼び出されます:

public override fun onRestoreFailure(
    error: AdaptyError,
    context: Context,
) {}
イベントの例(クリックして展開)
{
  "error": {
    "code": "restore_failed",
    "message": "Purchase restoration failed",
    "details": {
      "underlyingError": "No previous purchases found"
    }
  }
}

サブスクリプションのアップグレード

ユーザーが既存のサブスクリプションがアクティブな状態で新しいサブスクリプションを購入しようとした場合、このメソッドをオーバーライドして新しい購入の処理方法を制御できます。次の2つのオプションがあります:

  1. 現在のサブスクリプションを新しいものに置き換える:
public override fun onAwaitingPurchaseParams(
    product: AdaptyPaywallProduct,
    context: Context,
    onPurchaseParamsReceived: AdaptyFlowEventListener.PurchaseParamsCallback,
): AdaptyFlowEventListener.PurchaseParamsCallback.IveBeenInvoked {
    onPurchaseParamsReceived(
        AdaptyPurchaseParameters.Builder()
            .withSubscriptionUpdateParams(AdaptySubscriptionUpdateParameters(...))
            .build()
    )
    return AdaptyFlowEventListener.PurchaseParamsCallback.IveBeenInvoked
}
  1. 両方のサブスクリプションを維持する(新しいものを別途追加する):
public override fun onAwaitingPurchaseParams(
    product: AdaptyPaywallProduct,
    context: Context,
    onPurchaseParamsReceived: AdaptyFlowEventListener.PurchaseParamsCallback,
): AdaptyFlowEventListener.PurchaseParamsCallback.IveBeenInvoked {
    onPurchaseParamsReceived(AdaptyPurchaseParameters.Empty)
    return AdaptyFlowEventListener.PurchaseParamsCallback.IveBeenInvoked
}

このメソッドをオーバーライドしない場合、デフォルトの動作では両方のサブスクリプションがアクティブな状態を維持します(AdaptyPurchaseParameters.Emptyを使用した場合と同じ動作です)。

必要に応じて、追加の購入パラメーターを設定することもできます:

AdaptyPurchaseParameters.Builder()
    .withSubscriptionUpdateParams(AdaptySubscriptionUpdateParameters(...)) // optional - for replacing current subscription
    .withOfferPersonalized(true) // optional - if using personalized pricing
    .build()
イベントの例(クリックして展開)
{
  "product": {
    "vendorProductId": "premium_yearly",
    "localizedTitle": "Premium Yearly",
    "localizedDescription": "Premium subscription for 1 year",
    "localizedPrice": "$99.99",
    "price": 99.99,
    "currencyCode": "USD"
  },
  "subscriptionUpdateParams": {
    "replacementMode": "with_time_proration"
  }
}

データ取得とレンダリング

プロダクト読み込みエラー

初期化時にプロダクトを渡さない場合、AdaptyUI は必要なオブジェクトをサーバーから自動的に取得します。この操作が失敗した場合、AdaptyUI は次のメソッドを呼び出してエラーを報告します。

public override fun onLoadingProductsFailure(
    error: AdaptyError,
    context: Context,
): Boolean = false
イベントの例(クリックして展開)
{
  "error": {
    "code": "products_loading_failed",
    "message": "Failed to load products from the server",
    "details": {
      "underlyingError": "Network timeout"
    }
  }
}

true を返すと、AdaptyUI は 2 秒後にリクエストを再試行します。

レンダリングエラー

インターフェースのレンダリング中にエラーが発生した場合、次のメソッドを呼び出して報告されます:

public override fun onError(
    error: AdaptyError,
    context: Context,
) {}
イベント例(クリックして展開)
{
  "error": {
    "code": "rendering_failed",
    "message": "Failed to render flow interface",
    "details": {
      "underlyingError": "Invalid flow configuration"
    }
  }
}

通常、このようなエラーは発生しないはずです。もし遭遇した場合は、ぜひご連絡ください。

システムの戻るボタン

デフォルトでは、フローはシステムの戻るボタンやバックジェスチャーでは閉じられません。ユーザーは、ビルダーで設定した Close ボタンや on_device_back アクションなど、あなたが定義したパスを通じてフローを離れます。システムの戻るボタンでフローを閉じられるようにしたい場合は、onBackPressed をオーバーライドして false を返し、ホストのアクティビティまたはフラグメントがその押下を処理できるようにしてください:

public override fun onBackPressed(context: Context): Boolean {
    return false // let the host handle the back press (e.g. finish the activity or pop the fragment)
}

このコールバックは、現在の画面に on_device_back アクションが設定されていない場合にのみ呼び出されます。アクションが設定されている場合は、そちらが優先されて内部で処理されます。true を返すとそのプレスを消費し(デフォルトの動作)、false を返すとホスト側の戻る処理が実行されます。

予約済みイベント

AdaptyFlowEventListener には、フローがまだ使用していない機能向けにいくつかのコールバックが宣言されています。これらを実装する必要はありません。AdaptyFlowDefaultEventListener がすでにno-opのデフォルト実装を提供しています。

メソッド説明
onAnalyticEventフローからのカスタム分析イベント用に予約されています。フローはまだこれらをコードに送信しないため、実装は不要です。
onShowAppRateフローからのアプリレビューリクエスト用に予約されています。フローはまだアプリレビューリクエストをトリガーしないため、実装は不要です。
onShowRequestPermissionフローからのシステム権限リクエスト(プッシュ通知やカメラアクセスなど)用に予約されています。フローはまだ権限リクエストをトリガーしないため、実装は不要です。

このガイドでは、購入・復元・プロダクト選択・ペイウォールレンダリングのイベント処理について説明します。ボタン操作(ペイウォールを閉じる、リンクを開くなど)の処理も実装する必要があります。詳細はボタンアクションの処理に関するガイドを参照してください。

ペイウォールビルダーで設定したペイウォールは、購入や復元のために追加のコードを書く必要はありません。ただし、アプリが対応できるイベントをいくつか生成します。これらのイベントには、ボタン操作(閉じるボタン、URL、プロダクト選択など)や、ペイウォール上で行われた購入関連アクションの通知が含まれます。これらのイベントへの対応方法については、以下をご覧ください。

このガイドは、Adapty SDK v3.0以降が必要な新しいペイウォールビルダーのペイウォール専用です。

Adapty SDK がモバイルアプリにどのように統合されているか、実際の例を見てみませんか?ペイウォールの表示、購入処理、その他の基本機能を含む完全なセットアップを実演しているサンプルアプリをご覧ください。

購入画面で発生するプロセスを制御・監視したい場合は、AdaptyUiEventListener のメソッドを実装してください。

一部のケースでデフォルトの動作をそのまま使いたい場合は、AdaptyUiDefaultEventListener を継承し、変更したいメソッドだけをオーバーライドできます。

以下は AdaptyUiDefaultEventListener のデフォルト実装です。

ユーザーが生成するイベント

プロダクトの選択

ユーザーまたはシステムによってプロダクトが購入のために選択されると、次のメソッドが呼び出されます:

public override fun onProductSelected(
    product: AdaptyPaywallProduct,
    context: Context,
) {}
イベントの例(クリックして展開)
{
  "product": {
    "vendorProductId": "premium_monthly",
    "localizedTitle": "Premium Monthly",
    "localizedDescription": "Premium subscription for 1 month",
    "localizedPrice": "$9.99",
    "price": 9.99,
    "currencyCode": "USD"
  }
}

購入の開始

ユーザーが購入プロセスを開始すると、このメソッドが呼び出されます:

public override fun onPurchaseStarted(
    product: AdaptyPaywallProduct,
    context: Context,
) {}
イベントの例(クリックして展開)
{
  "product": {
    "vendorProductId": "premium_monthly",
    "localizedTitle": "Premium Monthly",
    "localizedDescription": "Premium subscription for 1 month",
    "localizedPrice": "$9.99",
    "price": 9.99,
    "currencyCode": "USD"
  }
}

このメソッドはオブザーバーモードでは呼び出されません。詳細は Android - オブザーバーモードでペイウォールビルダーのペイウォールを表示する を参照してください。

購入の成功・キャンセル・保留

購入が成功した場合、このメソッドが呼び出されます:

public override fun onPurchaseFinished(
    purchaseResult: AdaptyPurchaseResult,
    product: AdaptyPaywallProduct,
    context: Context,
) {
    if (purchaseResult !is AdaptyPurchaseResult.UserCanceled)
        context.getActivityOrNull()?.onBackPressed()
}
イベントの例(クリックして展開)
// Successful purchase
{
  "purchaseResult": {
    "type": "Success",
    "profile": {
      "accessLevels": {
        "premium": {
          "id": "premium",
          "isActive": true,
          "expiresAt": "2024-02-15T10:30:00Z"
        }
      }
    }
  },
  "product": {
    "vendorProductId": "premium_monthly",
    "localizedTitle": "Premium Monthly",
    "localizedDescription": "Premium subscription for 1 month",
    "localizedPrice": "$9.99",
    "price": 9.99,
    "currencyCode": "USD"
  }
}

// Cancelled purchase
{
  "purchaseResult": {
    "type": "UserCanceled"
  },
  "product": {
    "vendorProductId": "premium_monthly",
    "localizedTitle": "Premium Monthly",
    "localizedDescription": "Premium subscription for 1 month",
    "localizedPrice": "$9.99",
    "price": 9.99,
    "currencyCode": "USD"
  }
}

// Pending purchase
{
  "purchaseResult": {
    "type": "Pending"
  },
  "product": {
    "vendorProductId": "premium_monthly",
    "localizedTitle": "Premium Monthly",
    "localizedDescription": "Premium subscription for 1 month",
    "localizedPrice": "$9.99",
    "price": 9.99,
    "currencyCode": "USD"
  }
}

その場合はスクリーンを閉じることを推奨します。

このメソッドはObserverモードでは呼び出されません。詳細はAndroid - ObserverモードでのペイウォールビルダーペイウォールをPresentトピックを参照してください。

購入失敗

購入がエラーにより失敗した場合、このメソッドが呼び出されます。これには、Google Play Billing のエラー(支払い制限、無効なプロダクト、ネットワーク障害)、トランザクション検証の失敗、およびシステムエラーが含まれます。なお、ユーザーがキャンセルした場合はキャンセル結果とともに onPurchaseFinished がトリガーされ、保留中の支払いはこのメソッドをトリガーしません。

public override fun onPurchaseFailure(
    error: AdaptyError,
    product: AdaptyPaywallProduct,
    context: Context,
) {}
イベント例(クリックして展開)
{
  "error": {
    "code": "purchase_failed",
    "message": "Purchase failed due to insufficient funds",
    "details": {
      "underlyingError": "Insufficient funds in account"
    }
  },
  "product": {
    "vendorProductId": "premium_monthly",
    "localizedTitle": "Premium Monthly",
    "localizedDescription": "Premium subscription for 1 month",
    "localizedPrice": "$9.99",
    "price": 9.99,
    "currencyCode": "USD"
  }
}

このメソッドはオブザーバーモードでは呼び出されません。詳細については、Android - オブザーバーモードでペイウォールビルダーのペイウォールを表示するを参照してください。

ウェブ決済ナビゲーションの完了

このメソッドは、特定のプロダクトのウェブペイウォールを開こうとした後に呼び出されます。ナビゲーションの成功・失敗に関わらず呼び出されます。

public override fun onFinishWebPaymentNavigation(
    product: AdaptyPaywallProduct?,
    error: AdaptyError?,
    context: Context,
) {}

パラメーター:

パラメーター説明
productウェブペイウォールが開かれた AdaptyPaywallProductnull の場合があります。
errorウェブペイウォールのナビゲーションに失敗した場合は AdaptyError オブジェクト、成功した場合は null
イベントの例(クリックして展開)
// Successful navigation
{
  "product": {
    "vendorProductId": "premium_monthly",
    "localizedTitle": "Premium Monthly",
    "localizedDescription": "Premium subscription for 1 month",
    "localizedPrice": "$9.99",
    "price": 9.99,
    "currencyCode": "USD"
  },
  "error": null
}

// Failed navigation
{
  "product": {
    "vendorProductId": "premium_monthly",
    "localizedTitle": "Premium Monthly",
    "localizedDescription": "Premium subscription for 1 month",
    "localizedPrice": "$9.99",
    "price": 9.99,
    "currencyCode": "USD"
  },
  "error": {
    "code": "web_navigation_failed",
    "message": "Failed to open web paywall",
    "details": {
      "underlyingError": "Browser unavailable"
    }
  }
}

購入のリストア成功

購入のリストアが成功した場合、このメソッドが呼び出されます:

public override fun onRestoreSuccess(
    profile: AdaptyProfile,
    context: Context,
) {}
イベントの例(クリックして展開)
{
  "profile": {
    "accessLevels": {
      "premium": {
        "id": "premium",
        "isActive": true,
        "expiresAt": "2024-02-15T10:30:00Z"
      }
    },
    "subscriptions": [
      {
        "vendorProductId": "premium_monthly",
        "isActive": true,
        "expiresAt": "2024-02-15T10:30:00Z"
      }
    ]
  }
}

ユーザーが必要な accessLevel を持っている場合は、画面を閉じることをお勧めします。確認方法については、サブスクリプションのステータス をご覧ください。

復元の失敗

Adapty.restorePurchases() が失敗した場合、このメソッドが呼び出されます:

public override fun onRestoreFailure(
    error: AdaptyError,
    context: Context,
) {}
イベントの例(クリックして展開)
{
  "error": {
    "code": "restore_failed",
    "message": "Purchase restoration failed",
    "details": {
      "underlyingError": "No previous purchases found"
    }
  }
}

サブスクリプションのアップグレード

イベント例(クリックして展開)
{
  "product": {
    "vendorProductId": "premium_yearly",
    "localizedTitle": "Premium Yearly",
    "localizedDescription": "Premium subscription for 1 year",
    "localizedPrice": "$99.99",
    "price": 99.99,
    "currencyCode": "USD"
  },
  "subscriptionUpdateParams": {
    "replacementMode": "with_time_proration"
  }
}

データの取得とレンダリング

プロダクト読み込みエラー

初期化時にプロダクトを渡さない場合、AdaptyUI は必要なオブジェクトをサーバーから自動的に取得します。この操作が失敗した場合、AdaptyUI は以下のメソッドを呼び出してエラーを報告します:

public override fun onLoadingProductsFailure(
    error: AdaptyError,
    context: Context,
): Boolean = false
イベント例(クリックして展開)
{
  "error": {
    "code": "products_loading_failed",
    "message": "Failed to load products from the server",
    "details": {
      "underlyingError": "Network timeout"
    }
  }
}

true を返すと、AdaptyUI は 2 秒後にリクエストを再試行します。

レンダリングエラー

インターフェースのレンダリング中にエラーが発生した場合、このメソッドが呼び出されてエラーが通知されます:

public override fun onRenderingError(
    error: AdaptyError,
    context: Context,
) {}
イベントの例(クリックして展開)
{
  "error": {
    "code": "rendering_failed",
    "message": "Failed to render paywall interface",
    "details": {
      "underlyingError": "Invalid paywall configuration"
    }
  }
}

通常、このようなエラーは発生しないはずです。もし遭遇した場合は、ぜひご連絡ください。