公司动态
StoreKit 订阅换档:收据里的 productId 对不上,我们怎么查
最近和不少出海同事聊发现一个高频坑用户明明在 App 里从周订阅升到了月订阅客户端也弹了成功但你拿最新一笔交易 / 收据里的productId一对还是旧档。权益发错、后台对账对不上、客户说「我买的是月卡」——基本都从这儿开始。这篇文章只讲怎么查。1. 先分清你在看的是「哪一个」productId换档后至少会出现三类 ID很多人混在一块来源大致含义能不能当「当前档位」某笔 Transaction 的productId这一笔交易买的是什么不一定。它描述的是这笔单不是「此刻订阅应该是什么」renewalInfo.productIdApple 认为的当前订阅商品多数情况下应优先信这个renewalInfo.autoRenewProductId下一计费周期会续到的商品降级延期生效时它往往是新档当前周期仍是旧档一句话收据 / 最新 Transaction 上的 productId ≠ 当前应发放权益的商品。尤其是同组升级、降级「当前周期不变、下周期再生效」时三者可以同时不一致而且都「合理」。2. 常见现象对号入座现象 A刚升级成功Transaction 仍是旧 SKU沙盒里更明显。客户端purchase(新 SKU)走完了但你立刻用本地 Transaction 或只验「刚到手的那张票」productId还停在旧档。过一会儿再查 Subscription Status才会对齐。现象 B降级后「收据还是高级档」用户选了更便宜的档Apple 常常是本周期继续用贵的下周期才切到便宜的。于是当前权益仍应对高级档autoRenewProductId已是低级档若你只看「用户点的那个新 SKU」去改权益会提前降权客诉直接来现象 C服务端落库的是请求里的 product_id和 Apple 权威档不一致客户端带着「我想买的 SKU」去 verify服务端如果无条件以请求 body 为准换档瞬间就会和 Apple 真相打架。正确做法是以 Apple 订阅状态解析出的权威 SKU 入账请求里的 ID 只作参考。3. 排查清单按这个顺序查Step 1不要只盯「最新一笔购买」把这条链拉出来originalTransactionId同组订阅的根当前这笔transactionId该订阅组下的Subscription StatusGet All Subscription Statuses只 decode 最新一张 JWS Transaction在换档场景里信息量不够。Step 2同时看三个字段对 Status API 返回里匹配到的那条订阅解码signedTransactionInfo→productId这笔交易商品signedRenewalInfo→productId当前订阅商品signedRenewalInfo→autoRenewProductId下周期商品对照表Step 3定一条「权威 SKU」规则落地原则实现细节可各异原则尽量统一有renewalInfo.productId→ 优先用它作为当前应授予的商店 SKU订阅已非活跃时再回退到 transaction 上的productId活跃但暂时没有renewal.productId时再考虑autoRenewProductId/ transaction权益标识entitlement按「档位能力」设计同组多档共用同一 entitlement id换档只换 product不换「有没有会员」这条线过渡期才不会漏判/误判Step 4ASN 也要同一套逻辑DID_CHANGE_RENEWAL_PREF、续费类通知进来时不要只信通知里顺带的旧快照。和客户端验单一样能打 Status API 就再确认一次权威 SKU再写购买记录 / 推 Webhook。Step 5客户端怎么测升级App 内直接purchase(新 SKU)以服务端返回的当前权益对应商品为准不要本地用「我刚点的那个 ID」覆盖 UI降级看清是立即生效还是下周期生效UI 文案要写「本期仍为 xx下期变为 yy」Restore解决不了「刚在 App 内升级」的同步问题别把 restore 当换档的主路径4. 一个最小自检脚本思路snapshot GetSubscriptionStatus(originalTransactionId or transactionId) authSku renewal.productId ?? (active ? autoRenewProductId : null) ?? transaction.productId grantEntitlement(mapStoreSkuToEntitlement(authSku)) // 不要: grantEntitlement(mapStoreSkuToEntitlement(clientRequestedProductId))若authSku ! clientRequestedProductId打日志即可——很多「对不上」其实是预期行为不是 Apple 坏了。5. 小结换档后 productId「对不上」多半不是收据坏了而是你把「某一笔交易的商品」当成了「当前订阅商品」降级延期时当前档和下周期档本来就该不同沙盒 / 通知延迟下Transaction 会短时间滞后于 Renewal Info先把三个字段拆开看再定权威 SKU权益就会稳很多。我们后来把「以 Apple Subscription Status 纠正当前 SKU、权益层与商品层分离」写进了自己的订阅基建SubHub里换档验单和 ASN 走同一套规则。若你也在啃 StoreKit 2 服务端验单欢迎评论区交换踩坑纯技术问题我尽量回。