在 iOS SDK 中优化付费墙加载

在 iOS 上可靠地获取付费墙需要做到三点:快速渲染、返回面向目标受众的付费墙,以及在网络较慢时优雅地回退到备用方案。以下规则涵盖了实现这些目标所需的时机、缓存与备用方案。

Tip

以下规则假设 Adapty.activate()Adapty.identify() 已经执行完毕。请参阅 iOS SDK 中的调用顺序

规则与注意事项

做这些不要这样做原因
获取即将展示的版位,或使用 preloadFlows(SDK 4.1+)预热缓存。在启动时自行发起多个并发的 getFlow 调用。手动并发预取会阻塞主线程并导致黑屏。preloadFlows 专为此设计,整批共享同一个超时预算。
在归因数据有机会解析之后再调用 getPaywall,例如 activate 之后等待 1–2 秒,或等 onProfileUpdate 触发后再调用。App.init() 时调用 getPaywall此时归因数据尚未落地。付费墙会按默认目标受众解析,悄无声息地跳过市场细分和 ASA 个性化。
为每个版位设置 loadTimeout 并配置备用付费墙无限等待 getPaywall 返回。没有超时限制时,网络较差的用户会看到空白屏幕,直到网络恢复——或者直接退出应用。

请参阅获取付费墙和产品了解 fetchPolicyloadTimeout 参数说明,以及版位了解如何选择合适的版位。

预加载版位

Info

这些方法从 SDK 4.1 版本开始支持。

preloadFlowspreloadOnboardings 会提前将版位数据拉取到 SDK 缓存中。后续对同一版位调用 getFlowgetOnboarding 时,将直接从缓存返回结果,而无需发起网络请求,因此付费墙可以即时渲染,无需等待。

当你知道本次会话需要用到哪些版位,但暂时还不想展示时,可以使用这些方法——例如,在 activateidentify 完成后立即调用,为用户尚未点击的按钮背后的付费墙提前做好准备。

参数:

  • placementIds(必填):需要预加载的版位。空白和重复的 ID 会被忽略。
  • locale(可选,仅限 preloadOnboardings):要缓存的用户引导语言。
  • loadTimeout(可选):整批次的超时时间(秒),而非每个版位单独计时。默认为 5 秒,低于 1 秒的值会被自动提升至 1 秒。

注意事项:

  • 这些方法会在尝试所有版位后才抛出异常,错误信息会汇总每个版位的失败详情。某个版位的失败不会影响其他版位的处理。
  • 如果某个版位请求超时或发生网络错误,SDK 会回退到该版位的默认目标受众变体。其他类型的失败则按原样上报。
  • 如果超时在面向目标受众的请求完成前触发,SDK 仍会在剩余时间内尝试获取默认目标受众变体。
  • 预加载仅用于预热缓存,不会返回内容——你仍需调用 getFlowgetOnboarding 来展示内容。

找出哪个版位失败了

抛出的错误是一个 AdaptyError,涵盖整批请求,错误码为 networkFailed(2002)。要查看各版位的具体失败信息,请读取其 preloadErrors 属性——这是一个以版位 ID 为键的字典:

do {
    try await Adapty.preloadFlows(placementIds: ["onboarding", "main_paywall"])
} catch {
    for (placementId, placementError) in error.preloadErrors ?? [:] {
        // log or retry the individual placement
    }
}

preloadErrors 对于所有非预加载调用产生的错误均为 nil,因此应将 nil 值理解为”非预加载失败”,而非”无失败”。

如需在不等待目标受众分组的情况下预热缓存,可使用默认受众变体:

try await Adapty.preloadFlowsForDefaultAudience(placementIds: ["main_paywall"])
try await Adapty.preloadOnboardingsForDefaultAudience(placementIds: ["intro"])

针对网络状况较差的情况进行调优

针对网络连接持续不稳定的市场(如农村地区、交通途中、受路由影响的地区):

  • 除首次请求外,所有获取操作均设置 fetchPolicy: .returnCacheDataElseLoad
  • 在 Adapty 看板中为每个版位配置备用付费墙
  • loadTimeout 设置为 3–5 秒,超时后直接使用备用付费墙。
  • 不要将付费墙的显示依赖于 getProfile() 的结果。独立调用 getPaywall,避免因 profile 响应慢而阻塞 UI。