如何通过StoreKit2与Node.js后端识别iOS订阅取消及用户?
StoreKit2 + Node.js:识别订阅取消与关联用户方案
一、识别订阅取消行为
两种可靠方式覆盖所有取消场景:
1. 苹果服务器端通知(Server-to-Server Notifications)
这是核心依赖方式,用户直接在App Store设置中取消订阅时,App端无法捕获该操作,必须通过此方式接收通知:
- 在App Store Connect配置Webhook URL,勾选三类关键通知:
DID_CHANGE_RENEWAL_STATUS:用户取消自动续费时立即触发(订阅仍处于当前有效期)DID_REVOKE_SUBSCRIPTION:订阅因退款、苹果政策被撤销时触发DID_EXPIRE:订阅到期且未续费(含用户取消后到期)时触发
2. App端本地事件监听
通过StoreKit2的Transaction.updates流监听订阅状态变化,覆盖用户在App内操作取消的场景:
- 当订阅状态变为
.revoked(撤销)或.expired(过期)时,触发后端同步逻辑
二、确定执行操作的用户
核心是将苹果订阅数据与你的用户ID绑定,推荐两种方式:
1. 使用appAccountToken(最优方案)
发起订阅购买时,将你的用户ID作为appAccountToken传入:
// iOS端购买示例 let purchaseOptions = AppStorePurchaseOptions(appAccountToken: UUID(uuidString: "你的用户唯一ID")!) try await AppStore.shared.purchase(targetProduct, options: purchaseOptions)
苹果会将这个token包含在所有交易数据和服务器通知中,后端收到后可直接关联到对应用户。
2. 绑定originalTransactionId
若未使用appAccountToken,则在用户首次购买时,将originalTransactionId与用户ID存入数据库。后续所有订阅状态更新(包括取消通知)都会携带该ID,后端通过它查询关联用户。
三、Node.js后端实现示例
以下是基于Express的Webhook处理代码,包含通知解析与用户关联逻辑:
const express = require('express'); const jwt = require('jsonwebtoken'); const app = express(); app.use(express.json()); // 苹果订阅通知Webhook接口 app.post('/apple-subscription-webhook', async (req, res) => { const { notification_type, data } = req.body; const validNotificationTypes = ['DID_CHANGE_RENEWAL_STATUS', 'DID_REVOKE_SUBSCRIPTION', 'DID_EXPIRE']; // 忽略无关通知类型 if (!validNotificationTypes.includes(notification_type)) { return res.sendStatus(200); } // 必须实现:验证苹果通知的JWT签名(防止伪造) // 步骤:从苹果官方获取公钥,使用jsonwebtoken库验证签名,此处省略具体代码 // 解析交易信息JWT const decodedTx = jwt.decode(data.signedTransactionInfo, { complete: true }); const txPayload = decodedTx.payload; // 通过appAccountToken获取用户ID const userId = txPayload.appAccountToken; // 或通过originalTransactionId查询用户 // const originalTxId = txPayload.originalTransactionId; // const user = await UserModel.findOne({ where: { originalTransactionId: originalTxId } }); // 更新用户订阅状态 await UserModel.update( { subscriptionStatus: 'cancelled' }, { where: { id: userId } } ); res.sendStatus(200); }); app.listen(3000, () => console.log('Webhook服务运行于3000端口'));
关键注意事项
- 必须验证苹果服务器通知的JWT签名,否则存在伪造通知的安全风险
- 区分「取消自动续费」与「订阅到期」:前者订阅仍处于有效期,后者才是真正失效
- 处理退款撤销场景:用户申请退款后,苹果会发送撤销通知,需立即终止用户订阅权限
内容的提问来源于stack exchange,提问作者Chris Hansen
相关产品推荐
相关产品推荐

