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

因内购问题遭Apple审核拒绝,寻求技术排查协助

内购审核拒绝问题解决方案

一、"Remove Ads"按钮无响应/审核无购买提示问题

沙箱测试正常但审核翻车,大概率是这几个点出问题:

  • 按钮交互未生效:用SKSpriteNode做按钮时,必须把isUserInteractionEnabled设为true,还要确认该节点没被其他图层遮挡。给按钮设个更高的zPosition,或者在点击事件里加个打印日志,验证点击是否真的触发。
  • 内购产品状态异常:去App Store Connect检查对应的内购项目,是否处于「Ready to Submit」或「Approved」状态,有没有设置地域限制——审核账号所在地区必须能访问该内购。另外,调用requestPurchase()前,得确保产品已加载完成,且产品ID和后台完全匹配。
  • 未处理旧交易:审核环境中可能存在未完成的旧交易,导致新购买请求被阻塞。按钮点击时先执行try await AppStore.current.restoreTransactions(),处理完未完成交易再发起购买。
  • 异步调用线程错误:StoreKit2的API是异步的,requestPurchase()必须在主线程调用。如果按钮点击事件在SpriteKit后台线程触发,要切换到主线程执行:
    DispatchQueue.main.async {
        Task {
            do {
                try await AppStore.current.requestPurchase(product)
            } catch {
                print("购买请求失败: \(error)")
            }
        }
    }
    

二、收据验证问题(无服务器场景)

StoreKit2确实支持设备端验证,无需服务器,但要符合审核要求:

  • 设备端验证实现:可以用AppStoreReceipt或直接调用Apple的验证端点,审核时用production端点,沙箱测试用sandbox。示例代码:
    func validateReceipt() async throws {
        guard let receiptURL = Bundle.main.appStoreReceiptURL,
              FileManager.default.fileExists(atPath: receiptURL.path) else {
            throw NSError(domain: "ReceiptError", code: 1, userInfo: [NSLocalizedDescriptionKey: "找不到收据"])
        }
        
        let receiptData = try Data(contentsOf: receiptURL)
        let base64Receipt = receiptData.base64EncodedString()
        
        let url = URL(string: "https://buy.itunes.apple.com/verifyReceipt")!
        var request = URLRequest(url: url)
        request.httpMethod = "POST"
        request.httpBody = try JSONSerialization.data(withJSONObject: ["receipt-data": base64Receipt])
        
        let (data, response) = try await URLSession.shared.data(for: request)
        guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else {
            throw NSError(domain: "ReceiptError", code: 2, userInfo: [NSLocalizedDescriptionKey: "验证请求失败"])
        }
        
        let result = try JSONSerialization.jsonObject(with: data) as? [String: Any]
        guard let status = result?["status"] as? Int, status == 0 else {
            throw NSError(domain: "ReceiptError", code: 3, userInfo: [NSLocalizedDescriptionKey: "收据无效"])
        }
        
        // 验证通过,存储本地标记
        UserDefaults.standard.set(true, forKey: "AdsRemoved")
    }
    
  • 审核要求核心:Apple要求服务器处理,可能是因为你直接信任本地的「已购买」标记,未做收据验证。必须保证每次启动App、购买完成后都重新验证收据,不能仅依赖本地存储的状态。

三、InAppPurchaseManager代码通用排查点

不管代码具体实现如何,先检查这几个关键:

  1. 产品加载逻辑:products数组是否正确加载到目标产品,产品ID与App Store Connect完全一致?
  2. 交易监听:App启动时是否立即设置AppStore.current.transactionListener = self,且TransactionListener的所有方法都已实现?购买成功、失败、待处理的情况都要处理到位。
  3. 错误捕获:调用requestPurchase()时的错误是否被捕获?比如用户取消购买、网络问题等场景,要给出明确反馈,避免按钮点击后无响应。
  4. 权限配置:确认App的内购权限已在App Store Connect开启,Info.plist中无缺失的必要配置。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 08:54:59