You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift集成Superwall与RevenueCat:订阅状态判断异常问题

Swift集成Superwall与RevenueCat:付费墙仅对未订阅用户展示的问题

我在Swift项目中集成Superwall和RevenueCat,因Superwall配置便捷选择了该工具,但目前无法实现仅向未订阅用户展示付费墙的逻辑。在PaywallDelegate扩展的isUserSubscribed方法中判断用户订阅状态时,首次运行始终返回false,导致用户一直看到付费墙,寻求解决方法。

相关代码

extension PaywallService: PaywallDelegate {
   
  // 1 处理购买逻辑
  func purchase(product: SKProduct) {
    Task {
      do {
        let result = try await Purchases.shared.purchase(product: StoreProduct(sk1Product: product))
        // 处理购买结果
        print(result)
      } catch {
        // 处理购买错误
      }
    }
  }

  // 2 恢复购买
  func restorePurchases(completion: @escaping (Bool) -> Void) {
    Task {
      do {
        let purchaserInfo = try await Purchases.shared.restorePurchases()
        // 检查"subPlan"权益是否激活
        let restored = purchaserInfo.entitlements.all["subPlan"]?.isActive == true
        completion(restored)
      } catch {
        completion(false)
      }
    }
  }

  // 3 判断用户是否订阅(问题所在)
  func isUserSubscribed() -> Bool {
    // 问题:首次运行始终返回false,用户一直看到付费墙
    var isSub: Bool = false
    Purchases.shared.getCustomerInfo { purchaserInfo, error in
      // 异步获取用户订阅信息
      isSub = purchaserInfo?.entitlements.all["subPlan"]?.isActive == true
    }
    return isSub
  }
}

问题根源

isUserSubscribed是同步方法,但你在里面调用了RevenueCat的异步方法getCustomerInfo。方法执行时会直接返回初始值false,此时异步回调还没完成,订阅状态的更新根本没生效,所以首次运行必然返回false。

解决方法

1. 缓存订阅状态,避免异步回调延迟

在PaywallService中维护一个缓存变量存储订阅状态,提前预加载并在状态变化时更新:

步骤1:添加缓存变量

class PaywallService {
  // 缓存订阅状态,默认未订阅
  private var cachedIsSubscribed: Bool = false
  // 其他属性...
}

步骤2:预加载订阅状态

在App启动或PaywallService初始化时,异步加载用户订阅状态并更新缓存:

func loadSubscriptionStatus() async {
  do {
    let purchaserInfo = try await Purchases.shared.customerInfo()
    cachedIsSubscribed = purchaserInfo.entitlements.all["subPlan"]?.isActive == true
  } catch {
    cachedIsSubscribed = false
  }
}

步骤3:修改isUserSubscribed方法

直接返回缓存的状态,避免异步等待:

func isUserSubscribed() -> Bool {
  return cachedIsSubscribed
}

步骤4:订阅状态变化时更新缓存

  • 购买成功后更新:
func purchase(product: SKProduct) {
  Task {
    do {
      let result = try await Purchases.shared.purchase(product: StoreProduct(sk1Product: product))
      // 购买成功后更新缓存
      if let purchaserInfo = result.customerInfo {
        cachedIsSubscribed = purchaserInfo.entitlements.all["subPlan"]?.isActive == true
      }
    } catch {
      // 处理错误
    }
  }
}
  • 恢复购买后更新:
func restorePurchases(completion: @escaping (Bool) -> Void) {
  Task {
    do {
      let purchaserInfo = try await Purchases.shared.restorePurchases()
      let restored = purchaserInfo.entitlements.all["subPlan"]?.isActive == true
      cachedIsSubscribed = restored
      completion(restored)
    } catch {
      cachedIsSubscribed = false
      completion(false)
    }
  }
}
  • 监听RevenueCat的状态更新通知,实时同步:
// 在PaywallService初始化时添加监听
NotificationCenter.default.addObserver(forName: .PurchasesCustomerInfoUpdated, object: nil, queue: .main) { [weak self] notification in
  guard let purchaserInfo = notification.object as? PurchaserInfo else { return }
  self?.cachedIsSubscribed = purchaserInfo.entitlements.all["subPlan"]?.isActive == true
}

2. 异步触发付费墙(替代方案)

如果Superwall允许,也可以在触发付费墙前先异步确认订阅状态,再决定是否展示:

func showPaywallIfNeeded() async {
  do {
    let purchaserInfo = try await Purchases.shared.customerInfo()
    let isSubscribed = purchaserInfo.entitlements.all["subPlan"]?.isActive == true
    if !isSubscribed {
      // 仅向未订阅用户展示付费墙
      Superwall.shared.showPaywall()
    }
  } catch {
    // 网络错误时,默认展示付费墙(或根据需求调整)
    Superwall.shared.showPaywall()
  }
}

注意事项

  • 确保RevenueCat已正确初始化用户ID,避免匿名用户的状态混乱
  • 离线时依赖缓存状态,保证逻辑正常运行
  • 确认"subPlan"权益ID与RevenueCat后台配置完全一致

内容的提问来源于stack exchange,提问作者Carles - PLAVED

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 06:10:33