iOS消耗型内购退款处理:如何获取product_id?
解答:消耗型内购的Product ID获取与退款检测方案
Hey there, let's walk through your questions step by step—this is a common pain point for non-subscription in-app purchases, so you're not alone!
首先:如何获取Product ID?
你其实不需要等到事后解析收据来拿product_id,最佳时机是用户完成内购的瞬间:
- 在客户端(比如iOS的StoreKit框架)处理
SKPaymentTransaction时,这个对象本身就包含payment.product.productIdentifier(也就是你要的product_id)。 - 这个阶段你应该把
product_id和对应的transaction_id、购买日期、收据数据一起上传到你的服务器,直接存储到数据库里。这样后续不管是验证交易还是处理退款,都能直接关联到对应的商品,完全不用再从收据里逆向查找。
如果因为某些原因你没在交易时存储product_id,也可以尝试解析本地收据:
- 你提到本地验证需要
identifierForVendorId,但如果只是解析收据内容(不是做完整的验证),可以用一些轻量的工具或者自己解析PKCS7格式的收据文件,里面的交易明细字段里是包含product_id的。不过这种方式比交易时直接存储麻烦得多,还是优先推荐前者。
然后:非订阅产品的退款实现方案
你说得对,Apple的verifyReceipt端点确实不会返回非订阅的退款交易记录,所以得换其他方式:
1. 优先用Apple服务器通知(Server Notifications)
这是最实时、最可靠的方式:
- 登录App Store Connect,找到你的应用,进入「App信息」>「通知」,配置你的服务器接收端点,开启Refund类型的通知。
- 当用户的退款申请被Apple批准后,Apple会主动给你的服务器发送POST请求,里面包含退款的
transaction_id、product_id、退款日期、退款金额等关键信息。你可以直接用这些数据更新你的订单状态。 - 注意:这个通知不仅支持订阅,消耗型、非消耗型内购的退款都会触发,很多开发者容易忽略这一点!
2. 定期对比收据与本地交易记录
如果没法配置服务器通知,可以用这种兜底方案:
- 让客户端定期(比如用户打开App时)上传最新的收据到你的服务器。
- 服务器解析收据里的所有有效交易记录,和你数据库里存储的历史交易对比:如果某条之前存在的
transaction_id不在最新收据里了,基本可以判定该交易已被退款(Apple会把退款的交易从收据中移除)。 - 缺点是有延迟,而且要处理用户重装App后本地收据丢失的情况,所以最好结合客户端本地存储的交易记录一起验证。
3. 调用App Store Connect API批量查询
适合需要批量处理或者补全历史退款记录的场景:
- 你可以申请App Store Connect的API密钥,调用「Transactions」相关的接口,定期拉取你的应用所有交易的状态。
- 对比你服务器的订单记录,找出标记为「退款」状态的交易,更新对应的订单信息。
- 这个方式需要维护API密钥和签名逻辑,实时性不如服务器通知,但适合做批量对账。
最后小提醒
不管用哪种方案,核心都是在交易发生时记录好所有关键字段:transaction_id、product_id、购买日期、用户标识,这些数据是后续处理退款的基础。
内容的提问来源于stack exchange,提问作者Nikunj Banka




