处理流程与付费墙事件 - React Native

Important

本指南涵盖购买、恢复、产品选择和流程渲染的事件处理。你也可以设置按钮处理(关闭流程、打开链接、自定义操作等)。详情请参阅按钮操作处理指南

流程和使用 Flow Builder 构建的付费墙无需额外代码即可完成购买和恢复购买操作。但它们会生成一些事件,你的应用可以对这些事件做出响应。这些事件包括按钮点击(关闭按钮、URL、产品选择等)以及流程中与购买相关操作的通知。请参阅以下内容了解如何响应这些事件。

要在移动应用中控制或监控流程页面上发生的操作,请实现事件处理器:

事件示例(点击展开)
// onCloseButtonPress
{
  //Record the event
}

// onAndroidSystemBack
{
  //Record the event
}

// onUrlPress
{
  "url": "https://example.com/terms"
}

// onCustomAction
{
  "actionId": "login"
}

// onProductSelected
{
  "productId": "premium_monthly"
}

// onPurchaseStarted
{
  "product": {
    "vendorProductId": "premium_monthly",
    "localizedTitle": "Premium Monthly",
    "localizedDescription": "Premium subscription for 1 month",
    "price": {
      "amount": 9.99,
      "currencyCode": "USD",
      "currencySymbol": "$",
      "localizedString": "$9.99"
    }
  }
}

// onPurchaseCompleted - Success
{
  "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",
    "price": {
      "amount": 9.99,
      "currencyCode": "USD",
      "currencySymbol": "$",
      "localizedString": "$9.99"
    }
  }
}

// onPurchaseCompleted - Cancelled
{
  "purchaseResult": {
    "type": "user_cancelled"
  },
  "product": {
    "vendorProductId": "premium_monthly",
    "localizedTitle": "Premium Monthly",
    "localizedDescription": "Premium subscription for 1 month",
    "price": {
      "amount": 9.99,
      "currencyCode": "USD",
      "currencySymbol": "$",
      "localizedString": "$9.99"
    }
  }
}

// onPurchaseFailed
{
  "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",
    "price": {
      "amount": 9.99,
      "currencyCode": "USD",
      "currencySymbol": "$",
      "localizedString": "$9.99"
    }
  }
}

// onRestoreCompleted
{
  "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"
      }
    ]
  }
}

// onRestoreFailed
{
  "error": {
    "code": "restore_failed",
    "message": "Purchase restoration failed",
    "details": {
      "underlyingError": "No previous purchases found"
    }
  }
}

// onError
{
  "error": {
    "code": "rendering_failed",
    "message": "Failed to render flow interface",
    "details": {
      "underlyingError": "Invalid flow configuration"
    }
  }
}

// onLoadingProductsFailed
{
  "error": {
    "code": "products_loading_failed",
    "message": "Failed to load products from the server",
    "details": {
      "underlyingError": "Network timeout"
    }
  }
}

// onAppeared
{
  "view": {
    "id": "3f8a1c7e-9b24-4d51-8e30-6c5b2a9f1d47",
    "placementId": "onboarding_paywall",
    "variationId": "d21c4b6a-57e8-4f39-b0a2-8c7e13f5d94b",
    "locale": "es"
  }
}

// onDisappeared
{
  //Record the event
}

// onWebPaymentNavigationFinished
{
  //Record the event
}

您可以只注册需要的事件处理器,忽略不需要的。这样就不会创建多余的事件监听器。所有事件处理器均为可选项。

事件处理器返回一个布尔值。若返回 true,则视为展示流程已完成,流程页面随即关闭,并移除该视图的所有事件监听器。 某些事件处理器有默认行为,你可以按需覆盖:

  • onCloseButtonPress:按下关闭按钮时关闭流程。
  • onUrlPress:打开点击的 URL 并保持流程开启。
  • onAndroidSystemBack(仅适用于模态展示):按下 Back 键时保持流程开启。返回 true 可关闭流程。
  • onRestoreCompleted:恢复购买成功后保持流程开启。返回 true 可关闭流程。
  • onPurchaseCompleted:购买完成后保持流程开启。返回 true 可关闭流程。
  • onError:流程渲染失败时关闭流程。

事件处理器

事件处理器描述
onCustomAction当用户执行自定义操作时触发,例如点击自定义按钮
onUrlPress当用户点击流程中的 URL 时触发。
onAndroidSystemBack仅限模态展示:当用户点击 Android 系统 Back 按钮时触发。
onCloseButtonPress当关闭按钮可见且用户点击时触发。建议在此处理器中关闭流程页面。
onPurchaseCompleted购买完成时触发,无论是购买成功、用户取消还是待审批。购买成功时会提供更新后的 AdaptyProfile。用户取消和待支付(如需家长批准)也会触发此事件,而非 onPurchaseFailed
onPurchaseStarted当用户点击”Purchase”操作按钮开始购买流程时触发。
onPurchaseFailed因错误导致购买失败时触发(如支付限制、无效产品、网络故障、交易验证失败)。用户取消或待支付不会触发此事件,而是触发 onPurchaseCompleted
onRestoreStarted当用户开始恢复购买流程时触发。
onRestoreCompleted购买恢复成功时触发,并提供更新后的 AdaptyProfile。如果用户已拥有所需的 accessLevel,建议关闭页面。请参阅订阅状态了解如何检查。
onRestoreFailed恢复流程失败时触发,并提供 AdaptyError
onProductSelected当用户在流程视图中选择任意产品时触发,可用于监控用户在购买前的选择。
onError视图渲染过程中发生错误时触发,并提供 AdaptyError。此类错误通常不应出现,如果遇到请告知我们。
onLoadingProductsFailed产品加载失败时触发,并提供 AdaptyError。如果在创建视图时未设置 prefetchProducts: true,AdaptyUI 将自动从服务器获取所需对象。
onAppeared当流程展示给用户时触发,并提供已显示的 view——参见 view 参数。在 iOS 上,当用户点击流程中的网页付费墙按钮并在应用内浏览器中打开网页付费墙时,也会触发此事件。
onDisappeared仅限模态展示:当用户关闭流程时触发。在 iOS 上,从流程中打开的网页付费墙在应用内浏览器中消失时,也会触发此事件。
onWebPaymentNavigationFinished尝试打开网页付费墙进行购买后触发,无论成功或失败。
onAnalytics当流程上报分析事件(如页面浏览)时触发。详见下方分析事件
onRequestAppReview预留给流程中的应用评价请求。流程目前尚未触发应用评价请求,无需实现。
onRequestPermission预留给流程中的系统权限请求(如推送通知或相机访问)。流程目前尚未触发权限请求,无需实现。
onObserverPurchaseInitiated仅限观察者模式:当用户点击流程中的购买按钮时触发。Adapty 不会发起购买——请使用您自己的购买代码完成购买,然后将交易上报给 Adapty。详见下方在观察者模式中处理购买
onObserverRestoreInitiated仅限观察者模式:当用户点击流程中的恢复按钮时触发。Adapty 不会执行恢复——请自行完成恢复,然后上报所有已恢复的交易。详见下方在观察者模式中处理购买

view 参数

view 参数需要 React Native SDK 4.0.3 或更高版本。在所有流程事件处理器中,只有 onAppeared 会接收视图自身的描述——一个包含以下字段的 FlowEventView 对象:

字段说明
id该视图实例的标识符,仅供 SDK 内部使用,与 Adapty 看板中的任何内容无关。
placementId获取此流程所对应的版位
variationId流程解析后对应的实验变体,用于将您自己的分析数据归因到 A/B 测试
locale构建该视图时所使用的流程本地化配置。若流程不包含您所请求的语言,该值可能与请求的语言不同。请读取此值,以便将页面其余部分的语言与流程实际渲染的语言保持一致。详见使用本地化及语言代码

分析事件

const unsubscribe = view.setEventHandlers({
  onAnalytics(name, params) {
    return false; // keep the flow open
  },
});

每当用户打开某个流程中的屏幕时,该流程就会上报 flow_screen_showed 事件。Adapty 会在其自身的流程分析中统计这些事件,同时也会将其传递给您的应用,以便您在自己的分析系统中构建相同的漏斗。

参数说明
instanceId用户打开的屏幕 ID。
screen_order该屏幕在流程中的位置顺序。
is_last_screen当该屏幕没有后续跳转时为 true。分支流程可能有多个结束屏幕,每个结束屏幕都会上报 true

此事件的 isBackendEventisCustomerEvent 均为 true:Adapty 会持续统计该事件,同时您的应用也会收到它。

请参阅追踪流程屏幕浏览,了解如何处理这些数据。

在观察者模式下处理购买

如果你以观察者模式observerMode: true)激活了 SDK 并展示了 Adapty 渲染的流程,SDK 不会自动为你发起购买。当用户点击购买或恢复按钮时,SDK 会调用 onObserverPurchaseInitiatedonObserverRestoreInitiated。请用你自己的代码执行购买或恢复操作,通过提供的回调驱动流程的加载指示器,并在完成后向 Adapty 上报交易

const unsubscribe = view.setEventHandlers({
  onObserverPurchaseInitiated(product, onStartPurchase, onFinishPurchase) {
    onStartPurchase(); // show the flow's loading indicator
    myPurchaseApi(product.vendorProductId)
      .then((transactionId) => adapty.reportTransaction(transactionId))
      .finally(() => onFinishPurchase()); // hide the loading indicator
    return false; // keep the flow open; dismiss it yourself after success
  },
  onObserverRestoreInitiated(onStartRestore, onFinishRestore) {
    onStartRestore();
    myRestoreApi()
      .finally(() => onFinishRestore());
    return false;
  },
});
Important

本指南介绍购买、恢复、产品选择和付费墙渲染的事件处理方式。你还需要实现按钮处理功能(关闭付费墙、打开链接等)。详情请参阅按钮操作处理指南

通过付费墙编辑工具配置的付费墙无需额外代码即可完成购买和恢复购买操作。不过,这些付费墙会生成一些事件供应用响应,包括按钮点击(关闭按钮、URL、产品选择等)以及付费墙上购买相关操作的通知。请参阅下文了解如何响应这些事件。

Warning

本指南仅适用于新版付费墙编辑工具付费墙,需要 Adapty SDK v3.0 或更高版本。

要控制或监控移动应用中付费墙屏幕上发生的流程,请实现以下事件处理器:

事件示例(点击展开)
// onCloseButtonPress
{
  //Record the event
}

// onAndroidSystemBack
{
  //Record the event
}

// onUrlPress
{
  "url": "https://example.com/terms"
}

// onCustomAction
{
  "actionId": "login"
}

// onProductSelected
{
  "productId": "premium_monthly"
}

// onPurchaseStarted
{
  "product": {
    "vendorProductId": "premium_monthly",
    "localizedTitle": "Premium Monthly",
    "localizedDescription": "Premium subscription for 1 month",
    "price": {
      "amount": 9.99,
      "currencyCode": "USD",
      "currencySymbol": "$",
      "localizedString": "$9.99"
    }
  }
}

// onPurchaseCompleted - Success
{
  "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",
    "price": {
      "amount": 9.99,
      "currencyCode": "USD",
      "currencySymbol": "$",
      "localizedString": "$9.99"
    }
  }
}

// onPurchaseCompleted - Cancelled
{
  "purchaseResult": {
    "type": "user_cancelled"
  },
  "product": {
    "vendorProductId": "premium_monthly",
    "localizedTitle": "Premium Monthly",
    "localizedDescription": "Premium subscription for 1 month",
    "price": {
      "amount": 9.99,
      "currencyCode": "USD",
      "currencySymbol": "$",
      "localizedString": "$9.99"
    }
  }
}

// onPurchaseFailed
{
  "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",
    "price": {
      "amount": 9.99,
      "currencyCode": "USD",
      "currencySymbol": "$",
      "localizedString": "$9.99"
    }
  }
}

// onRestoreCompleted
{
  "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"
      }
    ]
  }
}

// onRestoreFailed
{
  "error": {
    "code": "restore_failed",
    "message": "Purchase restoration failed",
    "details": {
      "underlyingError": "No previous purchases found"
    }
  }
}

// onRenderingFailed
{
  "error": {
    "code": "rendering_failed",
    "message": "Failed to render paywall interface",
    "details": {
      "underlyingError": "Invalid paywall configuration"
    }
  }
}

// onLoadingProductsFailed
{
  "error": {
    "code": "products_loading_failed",
    "message": "Failed to load products from the server",
    "details": {
      "underlyingError": "Network timeout"
    }
  }
}

// onPaywallShown
{
  //Record the event
}

// onPaywallClosed
{
  //Record the event
}

// onWebPaymentNavigationFinished
{
  //Record the event
}

您可以只注册所需的事件处理器,忽略不需要的。这样就不会创建未使用的事件监听器。所有事件处理器均为可选。

事件处理器返回一个布尔值。若返回 true,则视为展示流程已完成,付费墙界面随即关闭,该视图的事件监听器也会被移除。 某些事件处理程序具有默认行为,您可以根据需要覆盖它们:

  • onCloseButtonPress:点击关闭按钮时关闭付费墙。
  • onUrlPress:打开点击的 URL 并保持付费墙不关闭。
  • onAndroidSystemBack(仅适用于模态展示):按下 Back 按钮时关闭付费墙。
  • onRestoreCompleted:恢复成功后关闭付费墙。
  • onPurchaseCompleted:除非用户取消,否则关闭付费墙。
  • onRenderingFailed:付费墙渲染失败时关闭付费墙。

事件处理程序

事件处理器描述
onCustomAction当用户执行自定义操作时触发,例如点击自定义按钮
onUrlPress当用户点击付费墙中的 URL 时触发。
onAndroidSystemBack仅限模态展示:当用户点击 Android 系统的 Back 按钮时触发。
onCloseButtonPress当关闭按钮可见且用户点击它时触发。建议在此处理器中关闭付费墙页面。
onPurchaseCompleted当购买完成时触发,无论是成功、被用户取消还是待审批。购买成功时会提供更新后的 AdaptyProfile。用户取消和待处理的付款(例如需要家长批准)会触发此事件,而非 onPurchaseFailed
onPurchaseStarted当用户点击”购买”操作按钮以启动购买流程时触发。
onPurchaseFailed当购买因错误失败时触发(例如付款限制、无效产品、网络故障、交易验证失败)。用户取消或待处理付款不会触发此事件,那些情况会触发 onPurchaseCompleted
onRestoreStarted当用户开始购买恢复流程时触发。
onRestoreCompleted当购买恢复成功时触发,并提供更新后的 AdaptyProfile。如果用户已获得所需的 accessLevel,建议关闭页面。请参阅订阅状态主题了解如何检查。
onRestoreFailed当恢复流程失败时触发,并提供 AdaptyError
onProductSelected当付费墙视图中的任意产品被选中时触发,可让你监控用户在购买前选择的内容。
onRenderingFailed当视图渲染过程中发生错误时触发,并提供 AdaptyError。此类错误通常不应发生,如果遇到,请告知我们。
onLoadingProductsFailed当产品加载失败时触发,并提供 AdaptyError。如果你在创建视图时未设置 prefetchProducts: true,AdaptyUI 将自行从服务器获取所需对象。
onPaywallShown当付费墙展示给用户时触发。在 iOS 上,当用户点击付费墙内的网页付费墙按钮并在应用内浏览器中打开网页付费墙时,也会触发此事件。
onPaywallClosed仅限模态展示:当用户关闭付费墙时触发。在 iOS 上,当从付费墙在应用内浏览器中打开的网页付费墙从屏幕上消失时,也会触发此事件。
onWebPaymentNavigationFinished在尝试打开网页付费墙进行购买后触发,无论成功或失败。