在 iOS SDK 中处理用户引导事件

从 SDK v4(测试版)开始,你可以将流程作为用户引导的更强大替代方案。与在 WebView 中运行的用户引导不同,流程直接在设备上原生渲染——动画更流畅、iOS 视觉风格更统一、加载更快,也不依赖 WebView 运行时。请参阅获取流程和付费墙展示流程和付费墙了解如何开始。

开始之前,请确保:

  1. 已安装 Adapty iOS SDK 3.8.0 或更高版本。
  2. 创建用户引导
  3. 已将用户引导添加到版位

通过编辑工具配置的用户引导会生成各种事件,你的应用可以对这些事件作出响应。请参阅以下内容了解如何处理这些事件。

如需控制或监听移动应用中用户引导界面上发生的流程,请实现 AdaptyOnboardingControllerDelegate 方法。

自定义操作

在付费墙编辑工具中,你可以为按钮添加自定义操作并为其分配一个 ID。

ios-events-1.webp

然后,您可以在代码中使用这个 ID,并将其作为自定义操作来处理。例如,当用户点击自定义按钮(如 LoginAllow notifications)时,代理方法 onboardingController 将以 .custom(id:) case 被触发,其中 actionId 参数即为编辑工具中设置的 Action ID。您可以自定义 ID,例如 “allowNotifications”。

func onboardingController(_ controller: AdaptyOnboardingController, onCustomAction action: AdaptyOnboardingsCustomAction) {
    if action.actionId == "allowNotifications" {
        // Request notification permissions
    }
}
    
func onboardingController(_ controller: AdaptyOnboardingController, didFailWithError error: AdaptyUIError) {
    // Handle errors
}
事件示例(点击展开)
{
  "actionId": "allowNotifications",
  "meta": {
    "onboardingId": "onboarding_123",
    "screenClientId": "profile_screen",
    "screenIndex": 0,
    "screensTotal": 3
  }
}

关闭用户引导

当用户点击分配了 Close 动作的按钮时,用户引导即视为已关闭。

ios-events-2.webp

请注意,你需要自行处理用户关闭用户引导后的逻辑,例如停止显示用户引导界面。

示例如下:

func onboardingController(_ controller: AdaptyOnboardingController, onCloseAction action: AdaptyOnboardingsCloseAction) {
    controller.dismiss(animated: true)
}
事件示例(点击展开)
{
  "action_id": "close_button",
  "meta": {
    "onboarding_id": "onboarding_123",
    "screen_cid": "final_screen",
    "screen_index": 3,
    "total_screens": 4
  }
}

打开付费墙

如果你希望在用户引导内部打开付费墙,请处理此事件。如果你想在付费墙关闭后再打开另一个付费墙,有一种更直接的方式——处理 AdaptyOnboardingsCloseAction 事件,无需依赖事件数据即可打开付费墙。

在用户引导中使用付费墙的最流畅方式,是将 action ID 设置为付费墙版位 ID。这样,在收到 AdaptyOnboardingsOpenPaywallAction 后,你可以直接用该版位 ID 获取并打开对应的付费墙。 请注意,同一时间屏幕上只能显示一个视图(付费墙或用户引导)。如果在用户引导上方展示付费墙,则无法通过代码控制后台的用户引导。此时尝试关闭用户引导,实际上会关闭付费墙,导致用户引导仍然可见。为避免此问题,请始终在展示付费墙之前先关闭用户引导视图。

func onboardingController(_ controller: AdaptyOnboardingController, onPaywallAction action: AdaptyOnboardingsOpenPaywallAction) {
    // 在展示流程前关闭用户引导
    controller.dismiss(animated: true) {
        Task {
            do {
                // 使用 action 中的版位 ID 获取流程
                let flow = try await Adapty.getFlow(placementId: action.actionId)

                // 获取流程配置
                let flowConfiguration = try await AdaptyUI.getFlowConfiguration(
                    forFlow: flow
                )

                // 创建并展示流程控制器
                let flowController = try AdaptyUI.flowController(
                    with: flowConfiguration,
                    delegate: self
                )

                // 从根视图控制器展示流程
                if let rootVC = UIApplication.shared.windows.first?.rootViewController {
                    rootVC.present(flowController, animated: true)
                }
            } catch {
                // 处理流程加载期间发生的任何错误
                print("Failed to present flow: \(error)")
            }
        }
    }
}
事件示例(点击展开)
{
    "action_id": "premium_offer_1",
    "meta": {
        "onboarding_id": "onboarding_123",
        "screen_cid": "pricing_screen",
        "screen_index": 2,
        "total_screens": 4
    }
}

用户引导加载完成

当用户引导加载完成时,将调用此方法:

func onboardingController(_ controller: AdaptyOnboardingController, didFinishLoading action: OnboardingsDidFinishLoadingAction) {
    // Handle loading completion
}
事件示例(点击展开)
{
    "meta": {
        "onboarding_id": "onboarding_123",
        "screen_cid": "welcome_screen",
        "screen_index": 0,
        "total_screens": 4
    }
}

跟踪导航

onAnalyticsEvent 方法会在用户引导流程中发生各种分析事件时被调用。 event 对象可以是以下类型之一:

类型描述
onboardingStarted用户引导加载完成时触发
screenPresented任意屏幕显示时触发
screenCompleted屏幕完成时触发。包含可选的 elementId(已完成元素的标识符)和可选的 reply(用户的回复)。当用户执行任意操作退出该屏幕时触发。
secondScreenPresented第二个屏幕显示时触发
userEmailCollected通过输入框收集到用户邮箱时触发
onboardingCompleted当用户到达 ID 为 final 的屏幕时触发。如需使用此事件,请final ID 分配给最后一个屏幕
unknown用于任何无法识别的事件类型。包含 name(未知事件的名称)和 meta(附加元数据)
每个事件都包含 meta 信息,其中含有以下字段:
字段描述
onboardingId用户引导流程的唯一标识符
screenClientId当前屏幕的标识符
screenIndex当前屏幕在流程中的位置
screensTotal流程中的屏幕总数

以下是如何使用分析事件进行追踪的示例:

func onboardingController(_ controller: AdaptyOnboardingController, onAnalyticsEvent event: AdaptyOnboardingsAnalyticsEvent) {
    switch event {
    case .onboardingStarted(let meta):
        // Track onboarding start
        trackEvent("onboarding_started", meta: meta)
    case .screenPresented(let meta):
        // Track screen presentation
        trackEvent("screen_presented", meta: meta)
    case .screenCompleted(let meta, let elementId, let reply):
        // Track screen completion with user response
        trackEvent("screen_completed", meta: meta, elementId: elementId, reply: reply)
    case .onboardingCompleted(let meta):
        // Track successful onboarding completion
        trackEvent("onboarding_completed", meta: meta)
    case .unknown(let meta, let name):
        // Handle unknown events
        trackEvent(name, meta: meta)
    // Handle other cases as needed
    }
}
事件示例(点击展开)
// onboardingStarted
{
  "name": "onboarding_started",
  "meta": {
    "onboarding_id": "onboarding_123",
    "screen_cid": "welcome_screen",
    "screen_index": 0,
    "total_screens": 4
  }
}

// screenPresented

{
    "name": "screen_presented",
    "meta": {
        "onboarding_id": "onboarding_123",
        "screen_cid": "interests_screen",
        "screen_index": 2,
        "total_screens": 4
    }
}

// screenCompleted

{
    "name": "screen_completed",
    "meta": {
        "onboarding_id": "onboarding_123",
        "screen_cid": "profile_screen",
        "screen_index": 1,
        "total_screens": 4
    },
    "params": {
        "element_id": "profile_form",
        "reply": "success"
    }
}

// secondScreenPresented

{
    "name": "second_screen_presented",
    "meta": {
        "onboarding_id": "onboarding_123",
        "screen_cid": "profile_screen",
        "screen_index": 1,
        "total_screens": 4
    }
}

// userEmailCollected

{
    "name": "user_email_collected",
    "meta": {
        "onboarding_id": "onboarding_123",
        "screen_cid": "profile_screen",
        "screen_index": 1,
        "total_screens": 4
    }
}

// onboardingCompleted

{
    "name": "onboarding_completed",
    "meta": {
        "onboarding_id": "onboarding_123",
        "screen_cid": "final_screen",
        "screen_index": 3,
        "total_screens": 4
    }
}