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

iOS应用内购(IAP)促销优惠报错:该优惠仅面向当前/过往订阅用户

应用内购促销优惠初始化SKPaymentDiscount时报错:"This offer is available only to current or previous subscribers of this app"

问题背景

已在App Store Connect完成应用内购(IAP)促销优惠配置,通过后端生成签名(signature)、随机数(nonce)和时间戳(timestamp)后,初始化SKPaymentDiscount方法时触发如下错误:

This offer is available only to current or previous subscribers of this app.
[Environment: Xcode]

开发参考Apple官方文档实现,相关代码如下:

PrepareForOffer 代码

func prepareOffer(usernameHash: String, productIdentifier: String, offerIdentifier: String, completion: @escaping (SKPaymentDiscount) -> Void) {

    let applicationUserName = UUID().uuidString.lowercased()
    let param:[String:Any] = ["productIdentifier": productIdentifier,
                              "applicationUsername": applicationUserName,
                              "offerID": offerIdentifier]
    param.printJson()
    APIManager.sharedInstance.usersAPIManager.GetSignatureData(params: param, success: { (responseObject) in
        self.purchase = Mapper<IAPModel>().map(JSON: responseObject as [String: Any])
        
        // Create offer
        var uuid = UUID(uuidString: self.purchase?.nonce ?? "")
        let discountOffer = SKPaymentDiscount(identifier: offerIdentifier, keyIdentifier: "5WWL777LG5", nonce: uuid ?? UUID(), signature: self.purchase?.signature ?? "", timestamp: (self.purchase?.timestamp ?? 0) as NSNumber)

        // Pass offer in completion block
        completion(discountOffer)
    }) { (error) in
        print(error)
    }
}

BuyProduct 代码

func buyProduct(product: SKProduct, forApplicationUsername usernameHash: String, withOffer offer: SKPaymentDiscount) {

    print("buyProduct", offer.debugDescription.description)
  // Create payment object
  let payment = SKMutablePayment(product: product)

  // Apply username and offer to the payment
  payment.applicationUsername = usernameHash
  payment.paymentDiscount = offer

  // Add payment to paymentQueue
  InAppPurchaseManager.shared.paymentQueue.add(payment)
}

App Store Connect 优惠配置截图

排查与解决步骤

1. 确认优惠的受众配置

先检查App Store Connect里的优惠类型:

  • 如果配置的是挽留优惠或订阅升级/降级优惠,这类优惠仅对现有/曾订阅过的用户开放,测试时必须用有订阅记录的沙盒账号(可以先订阅基础套餐,再测试优惠);
  • 如果是给新用户的优惠,要选择“新订阅用户”类型(比如介绍优惠、新用户定向促销优惠)。

2. 修复applicationUsername不一致问题

代码里存在关键参数不匹配的问题:

  • prepareOffer中生成了新的UUID作为applicationUsername传给后端生成签名;
  • 但buyProduct里却用了外部传入的usernameHash赋值给payment.applicationUsername。

Apple要求生成签名时的applicationUsername必须和发起支付时的完全一致,否则会触发权限校验错误。修改方案:
把prepareOffer里的applicationUserName换成传入的usernameHash,保证前后参数统一,修改后的代码片段:

func prepareOffer(usernameHash: String, productIdentifier: String, offerIdentifier: String, completion: @escaping (SKPaymentDiscount) -> Void) {

    // 直接使用传入的usernameHash,避免前后参数不一致
    let applicationUserName = usernameHash
    let param:[String:Any] = ["productIdentifier": productIdentifier,
                              "applicationUsername": applicationUserName,
                              "offerID": offerIdentifier]
    param.printJson()
    APIManager.sharedInstance.usersAPIManager.GetSignatureData(params: param, success: { (responseObject) in
        self.purchase = Mapper<IAPModel>().map(JSON: responseObject as [String: Any])
        
        // 增加nonce有效性校验,不要直接用默认UUID
        guard let nonceStr = self.purchase?.nonce, let uuid = UUID(uuidString: nonceStr) else {
            print("后端返回的nonce无效")
            return
        }
        let discountOffer = SKPaymentDiscount(identifier: offerIdentifier, keyIdentifier: "5WWL777LG5", nonce: uuid, signature: self.purchase?.signature ?? "", timestamp: (self.purchase?.timestamp ?? 0) as NSNumber)

        completion(discountOffer)
    }) { (error) in
        print(error)
    }
}

3. 验证后端签名逻辑

  • 确认后端生成签名时使用的applicationUsername、productIdentifier、offerIdentifier和客户端传入的完全一致;
  • 检查后端用的签名密钥(Key ID和私钥)是否和App Store Connect中配置的优惠密钥匹配;
  • 确保时间戳是秒级UNIX时间戳,且和客户端初始化SKPaymentDiscount的时间差不超过5分钟。

4. 检查沙盒账号状态

如果用沙盒账号测试:

  • 若优惠面向老用户,确认账号之前订阅过该产品(即使已过期);
  • 可以在测试设备的「设置」->「Apple ID」->「媒体与购买项目」->「查看账户」->「订阅」里确认账号的订阅记录。

内容的提问来源于stack exchange,提问作者Imran

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 17:57:33