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

如何通过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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 10:25:08