フローとペイウォールのイベントを処理する - iOS

このガイドでは、購入・復元・プロダクト選択・ペイウォール表示に関するイベント処理について説明します。また、ボタン操作(ペイウォールを閉じる、リンクを開くなど)の実装も必要です。詳しくはボタン操作の処理に関するガイドをご覧ください。

フローとペイウォールは、購入や購入の復元に追加のコードは不要です。ただし、アプリが反応できるイベントをいくつか生成します。これらのイベントには、ボタン操作(閉じるボタン、URL、プロダクト選択など)や購入関連アクションの通知が含まれます。以下で、これらのイベントへの対応方法を説明します。

Adapty SDK をモバイルアプリに組み込む実際の例を見たいですか?ペイウォールの表示、購入、その他の基本的な機能を含む完全なセットアップを示すサンプルアプリをぜひご確認ください。

SwiftUI でのイベント処理

モバイルアプリ内のフローまたはペイウォール画面で発生するプロセスを制御・監視するには、SwiftUI の .flow モディファイアを使用します。

@State var flowPresented = false

var body: some View {
    Text("Hello, AdaptyUI!")
        .flow(
            isPresented: $flowPresented,
            flowConfiguration: flowConfiguration,
            didPerformAction: { action in
                switch action {
                    case .close:
                        flowPresented = false
                    case let .openURL(url):
                        // handle opening the URL (incl. for terms and privacy)
                    default:
                        // handle other actions
                }
            },
            didSelectProduct: { product in /* Handle the event */ },
            didStartPurchase: { product in /* Handle the event */ },
            didFailPurchase: { product, error in /* handle the error */ },
            didStartRestore: { /* Handle the event */ },
            didFinishRestore: { profile in /* check access level and dismiss */ },
            didFailRestore: { error in /* handle the error */ },
            didReceiveError: { error in
                flowPresented = false
            },
            didFailLoadingProducts: { error in
                // Return `true` to retry loading
                return false
            }
        )
}

クロージャのパラメーターは必要なものだけ登録すれば、不要なものは省略できます。

パラメータ必須説明
isPresented必須フローまたはペイウォール画面の表示を管理するバインディング。
flowConfiguration必須フローまたはペイウォールの視覚的な詳細を含む AdaptyUI.FlowConfiguration オブジェクト。詳細はフローとペイウォールの取得を参照してください。
didFailPurchase必須Adapty.makePurchase() が失敗したときに呼び出されます。
didFinishRestore必須Adapty.restorePurchases() が正常に完了したときに呼び出されます。
didFailRestore必須Adapty.restorePurchases() が失敗したときに呼び出されます。
didReceiveError必須フローでレンダリングエラーまたはフロースクリプトの実行時エラー(例:JavaScript例外、AdaptyUIError コード 4105)が発生したときに呼び出されます。レンダリングエラーの場合はAdapty サポートにお問い合わせください。
placeholderBuilder任意フローまたはペイウォールの読み込み中にプレースホルダービューをレンダリングする関数。デフォルトは ProgressView
fullScreen任意フローまたはペイウォールをフルスクリーンモードで表示するか、シートとして表示するかを決定します。デフォルトは true
didAppear任意フローまたはペイウォールのビューが画面に表示されたときに呼び出されます。
didDisappear任意フローまたはペイウォールのビューが閉じられたときに呼び出されます。
didPerformAction任意ユーザーがボタンをクリックしたときに呼び出されます。アクション ID として closeopenURL が事前定義されており、その他はビルダーで設定できるカスタムIDです。
didSelectProduct任意ユーザーまたはシステムによってプロダクトが購入対象として選択されたときに呼び出されます。
didStartPurchase任意ユーザーが購入プロセスを開始したときに呼び出されます。
didFinishPurchase任意Adapty.makePurchase() が正常に完了したときに呼び出されます。
didFinishWebPaymentNavigation任意ウェブ決済のナビゲーションが完了したときに呼び出されます。
didStartRestore任意ユーザーが復元プロセスを開始したときに呼び出されます。
didFailLoadingProducts任意プロダクトの読み込み中にエラーが発生したときに呼び出されます。true を返すと再読み込みを試みます。
didPartiallyLoadProducts任意プロダクトが部分的に読み込まれたときに呼び出されます。
showAlertItem任意フローまたはペイウォールの上にアラートアイテムの表示を管理するバインディング。
showAlertBuilder任意アラートビューをレンダリングする関数。

UIKitでのイベント処理

UIKitアプリでは、AdaptyFlowControllerDelegateプロトコルを通じてイベントを処理します。AdaptyFlowControllerAdaptyFlowControllerDelegateのセットアップ方法については、フロー&ペイウォールの表示 - iOSを参照してください。

このプロトコルには13のメソッドが定義されています。そのうち3つ(didFailPurchasedidFinishRestoreWithdidFailRestoreWith)はデフォルト実装がなく、プロトコルに準拠する際に必ず実装する必要があります。残りのメソッドはデフォルトで何も行わない実装が提供されており、カスタムの動作が必要な場合にオーバーライドできます。以下ではメソッドを目的別にグループ化して説明します。

ライフサイクル

func flowControllerDidAppear(_ controller: AdaptyFlowController) { }

func flowControllerDidDisappear(_ controller: AdaptyFlowController) { }

これらはフローまたはペイウォールのビューが表示・非表示になったときに呼び出されます。

ユーザーアクション

func flowController(
    _ controller: AdaptyFlowController,
    didPerform action: AdaptyUI.Action
) { }

AdaptyUI.Action のケース:

  • .close — デフォルトの動作はコントローラーを閉じます。コントローラーを画面に残したり、追加のクリーンアップ処理を行う場合はオーバーライドしてください。
  • .openURL(url:) — デフォルトの動作は UIApplication.shared.open(...) でURLを開きます。
  • .custom(id:) — ビルダーでカスタムアクションIDが設定されたボタンがタップされたときに発火します。

プロダクト選択

func flowController(
    _ controller: AdaptyFlowController,
    didSelectProduct product: AdaptyPaywallProduct
) { }

ユーザーまたはシステムによってプロダクトが購入対象として選択されたときに呼び出されます。プロダクトにはオファーの全情報が含まれており(v4 ではエリジビリティが自動で判定されるため、AdaptyPaywallProductWithoutDeterminingOffer という独立した型は存在しません)。

購入イベント

func flowController(
    _ controller: AdaptyFlowController,
    didStartPurchase product: AdaptyPaywallProduct
) { }

func flowController(
    _ controller: AdaptyFlowController,
    didFinishPurchase product: AdaptyPaywallProduct,
    purchaseResult: AdaptyPurchaseResult
) {
    // Default: dismiss the controller unless the purchase was cancelled.
}

func flowController(
    _ controller: AdaptyFlowController,
    didFailPurchase product: AdaptyPaywallProduct,
    error: AdaptyError
) { }

didFailPurchase はデフォルト実装のない唯一の購入イベントです。didFinishPurchase は成功時にコントローラーを閉じるデフォルト実装が用意されています。カスタムの購入後処理が必要な場合のみオーバーライドしてください。

リストアイベント

func flowControllerDidStartRestore(_ controller: AdaptyFlowController) { }

func flowController(
    _ controller: AdaptyFlowController,
    didFinishRestoreWith profile: AdaptyProfile
) { }

func flowController(
    _ controller: AdaptyFlowController,
    didFailRestoreWith error: AdaptyError
) { }

didFinishRestoreWithdidFailRestoreWith にはデフォルト実装がありません。コントローラーを閉じる前に、返された AdaptyProfile に目的のアクセスレベルが含まれているかどうかを確認してください。

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

func flowController(
    _ controller: AdaptyFlowController,
    didReceiveError error: AdaptyUIError
) { }

func flowController(
    _ controller: AdaptyFlowController,
    didFailLoadingProductsWith error: AdaptyError
) -> Bool {
    // Return `true` to retry product loading; default returns `false`.
    return false
}

func flowController(
    _ controller: AdaptyFlowController,
    didPartiallyLoadProducts failedIds: [String]
) { }

didReceiveError は、レンダリングエラーおよびフロースクリプトのランタイムエラー(JavaScript例外、AdaptyUIError コード 4105)で発生します。レンダリングエラーが発生した場合は、Adapty サポートにお問い合わせください。読み込みエラーの場合は、didFailLoadingProductsWith から true を返すことでリトライできます。一時的なネットワーク障害に有効です。

Web支払いナビゲーション

func flowController(
    _ controller: AdaptyFlowController,
    didFinishWebPaymentNavigation product: AdaptyPaywallProduct?,
    error: AdaptyError?
) { }

Webの支払いナビゲーションが完了した際(成功・失敗を問わず)に呼び出されます。

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

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

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

Adapty SDK がモバイルアプリにどのように統合されるか、実際の例を見てみたいですか?サンプルアプリでは、ペイウォールの表示、購入処理、その他の基本機能を含む完全なセットアップを確認できます。

SwiftUI でのイベント処理

モバイルアプリ内のペイウォール画面で発生するプロセスを制御・監視するには、SwiftUI の .paywall モディファイアを使用してください:

@State var paywallPresented = false

var body: some View {
	Text("Hello, AdaptyUI!")
			.paywall(
          isPresented: $paywallPresented,
          paywall: paywall,
          viewConfiguration: viewConfig,
          didPerformAction: { action in
              switch action {
                  case .close:
                      paywallPresented = false
                  case let .openURL(url):
                      // handle opening the URL (incl. for terms and privacy)
                  default:
                      // handle other actions
              }
          },
          didSelectProduct: { /* Handle the event */  },
          didStartPurchase: { /* Handle the event */ },
          didFinishPurchase: { product, info in /* Handle the event */ },
          didFailPurchase: { product, error in /* Handle the event */ },
          didStartRestore: { /* Handle the event */ },
          didFinishRestore: { /* Handle the event */ },
          didFailRestore: { /* Handle the event */ },
          didFailRendering: { error in
              paywallPresented = false
          },
          didFailLoadingProducts: { error in
              return false
          }
      )
}

必要なクロージャパラメータだけを登録し、不要なものは省略できます。この場合、未使用のクロージャパラメータは作成されません。

パラメータ必須説明
isPresented必須ペイウォール画面の表示を管理するバインディング。
paywallConfiguration必須ペイウォールのビジュアル詳細を含む AdaptyUI.PaywallConfiguration オブジェクト。AdaptyUI.paywallConfiguration(for:products:viewConfiguration:observerModeResolver:tagResolver:timerResolver:) メソッドを使用してください。詳細は ペイウォールビルダーのペイウォールと設定の取得 を参照してください。
didFailPurchase必須エラー(支払い不可、ネットワークエラー、無効なプロダクトなど)によって購入が失敗した場合に呼び出されます。ユーザーによるキャンセルや保留中の支払いでは呼び出されません。
didFinishRestore必須購入が正常に完了したときに呼び出されます。
didFailRestore必須購入の復元に失敗したときに呼び出されます。
didFailRendering必須インターフェースのレンダリング中にエラーが発生した場合に呼び出されます。この場合は Adapty サポートにお問い合わせください
fullScreen任意ペイウォールをフルスクリーンモードで表示するか、モーダルとして表示するかを指定します。デフォルトは true です。
didAppear任意ペイウォールビューが画面に表示されたときに呼び出されます。また、ユーザーがペイウォール内の ウェブペイウォールボタン をタップしてインアプリブラウザでウェブペイウォールが開いたときにも呼び出されます。
didDisappear任意ペイウォールビューが閉じられたときに呼び出されます。また、ペイウォールからインアプリブラウザで開いた ウェブペイウォール が画面から消えたときにも呼び出されます。
didPerformAction任意ユーザーがボタンをクリックしたときに呼び出されます。ボタンごとにアクション ID が異なります。closeopenURL の 2 つのアクション ID は事前定義されており、その他はビルダーで設定できるカスタムのものです。
didSelectProduct任意プロダクトが(ユーザーまたはシステムによって)購入のために選択された場合に呼び出されます。
didStartPurchase任意ユーザーが購入プロセスを開始したときに呼び出されます。
didFinishPurchase任意購入が正常に完了したときに呼び出されます。
didFinishWebPaymentNavigation任意購入のために ウェブペイウォール を開こうとした後(成功・失敗を問わず)に呼び出されます。
didStartRestore任意ユーザーが復元プロセスを開始したときに呼び出されます。
didFailLoadingProducts任意プロダクトの読み込み中にエラーが発生したときに呼び出されます。読み込みを再試行する場合は true を返してください。
didPartiallyLoadProducts任意プロダクトが部分的に読み込まれたときに呼び出されます。
showAlertItem任意ペイウォールの上部にアラートアイテムの表示を管理するバインディング。
showAlertBuilder任意アラートビューをレンダリングするための関数。
placeholderBuilder任意ペイウォールの読み込み中にプレースホルダービューをレンダリングするための関数。

UIKit でのイベント処理

モバイルアプリのペイウォール画面で発生するプロセスを制御・監視するには、AdaptyPaywallControllerDelegate のメソッドを実装してください。

ユーザー生成イベント

プロダクトの選択

ユーザーが購入するプロダクトを選択すると、このメソッドが呼び出されます:

    func paywallController(
        _ controller: AdaptyPaywallController,
        didSelectProduct product: AdaptyPaywallProductWithoutDeterminingOffer
    ) { }
イベントの例(クリックして展開)
{
  "product": {
    "vendorProductId": "premium_monthly",
    "localizedTitle": "Premium Monthly",
    "localizedDescription": "Premium subscription for 1 month",
    "localizedPrice": "$9.99",
    "price": 9.99,
    "currencyCode": "USD"
  }
}

購入開始

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

func paywallController(_ controller: AdaptyPaywallController,
                       didStartPurchase product: AdaptyPaywallProduct) {
}
イベントの例(クリックして展開)
{
  "product": {
    "vendorProductId": "premium_monthly",
    "localizedTitle": "Premium Monthly",
    "localizedDescription": "Premium subscription for 1 month",
    "localizedPrice": "$9.99",
    "price": 9.99,
    "currencyCode": "USD"
  }
}

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

ウェブペイウォールを使用して購入を開始した

ユーザーがウェブペイウォールを使って購入プロセスを開始すると、このメソッドが呼び出されます:

func paywallController(
        _ controller: AdaptyPaywallController,
        shouldContinueWebPaymentNavigation product: AdaptyPaywallProduct
    ) {
    }
イベントの例(クリックして展開)
{
  "product": {
    "vendorProductId": "premium_monthly",
    "localizedTitle": "Premium Monthly",
    "localizedDescription": "Premium subscription for 1 month",
    "localizedPrice": "$9.99",
    "price": 9.99,
    "currencyCode": "USD"
  }
}

購入成功またはキャンセル

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

func paywallController(
    _ controller: AdaptyPaywallController,
    didFinishPurchase product: AdaptyPaywallProductWithoutDeterminingOffer,
    purchaseResult: AdaptyPurchaseResult
) { }
}
イベントの例(クリックして展開)
// Successful purchase
{
  "product": {
    "vendorProductId": "premium_monthly",
    "localizedTitle": "Premium Monthly",
    "localizedDescription": "Premium subscription for 1 month",
    "localizedPrice": "$9.99",
    "price": 9.99,
    "currencyCode": "USD"
  },
  "purchaseResult": {
    "type": "success",
    "profile": {
      "accessLevels": {
        "premium": {
          "id": "premium",
          "isActive": true,
          "expiresAt": "2024-02-15T10:30:00Z"
        }
      }
    }
  }
}

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

この場合は、ペイウォール画面を閉じることをお勧めします。

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

購入失敗

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

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

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

Webペイウォールによる購入の失敗

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

func paywallController(
        _ controller: AdaptyPaywallController,
        didFailWebPaymentNavigation product: AdaptyPaywallProduct,
        error: AdaptyError
    ) { }
イベント例(クリックして展開)
{
  "product": {
    "vendorProductId": "premium_monthly",
    "localizedTitle": "Premium Monthly",
    "localizedDescription": "Premium subscription for 1 month",
    "localizedPrice": "$9.99",
    "price": 9.99,
    "currencyCode": "USD"
  },
  "error": {
    "code": "web_payment_failed",
    "message": "Web payment navigation failed",
    "details": {
      "underlyingError": "Network connection error"
    }
  }
}

購入の復元に成功した場合

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

func paywallController(
    _ controller: AdaptyPaywallController, 
    didFinishRestoreWith profile: AdaptyProfile
) { }
イベントの例(クリックして展開)
{
  "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 がある場合にスクリーンを閉じることです。確認方法については、サブスクリプションのステータスをご参照ください。

復元の失敗

購入の復元に失敗した場合、このメソッドが呼び出されます:

public func paywallController(
    _ controller: AdaptyPaywallController, 
    didFailRestoreWith error: AdaptyError
) { }
イベント例(クリックして展開)
{
  "error": {
    "code": "restore_failed",
    "message": "Purchase restoration failed",
    "details": {
      "underlyingError": "No previous purchases found"
    }
  }
}

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

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

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

public func paywallController(
    _ controller: AdaptyPaywallController,
    didFailLoadingProductsWith error: AdaptyError
) -> Bool {
    return true
}
イベント例(クリックして展開)
{
  "error": {
    "code": "products_loading_failed",
    "message": "Failed to load products from the server",
    "details": {
      "underlyingError": "Network timeout"
    }
  }
}

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

レンダリングエラー

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

public func paywallController(
    _ controller: AdaptyPaywallController,
    didFailRenderingWith error: AdaptyError
) { }
イベント例(クリックして展開)
{
  "error": {
    "code": "rendering_failed",
    "message": "Failed to render paywall interface",
    "details": {
      "underlyingError": "Invalid paywall configuration"
    }
  }
}

通常、このようなエラーは発生しないはずですので、もし見かけた場合はお知らせください。