Apple App 内购买项目的新功能
What’s new in Apple In-App Purchase
2026年6月10日
一句话判断
✅ 年度订阅终于能官方“分期付款”了,这是提升订阅转化率最实用的商业武器,比任何 StoreKit 代码层面的更新都值钱。
这场 Session 讲了什么
做订阅的开发者一直面临一个死结:推年度订阅,用户看到总价直接跑路;推月度订阅,用户用两个月就取消,LTV(生命周期价值)根本算不过账。Apple 这次直接给出了官方解法:12个月承诺期的月度订阅(Monthly subscriptions with a 12-month commitment)。用户按月扣费降低决策门槛,但合约锁定 12 个月。StoreKit 新增了 PricingTerms 和 billingPlanType 来区分买断和按月承诺,Server API 也同步下发了 commitmentInfo 让你追踪履约进度。
除了这个商业大杀器,IAP(App 内购买项目)的审核提交流程终于和 App 本体、In-App Events(App 内活动)统一了。以前 IAP 单独提交、状态不同步导致的“App 上了但 IAP 没审过”的惨剧,现在可以通过打包成一个 Submission 彻底解决。
值得深挖的点
12个月承诺期按月订阅:转化与留存的完美平衡
Apple 做这个功能的动机很明显:帮开发者搞钱,同时减少用户因为“被坑”产生的客诉。以前开发者为了锁定用户,经常搞“首月 1 元,次月恢复原价且强绑一年”的套路,不仅 UI 实现复杂,还极易被 App Review 拒审。现在 Apple 提供了原生的“分期”方案。
从设计上看,这是一个精妙的 Trade-off。Apple 承担了用户中途违约(比如信用卡扣款失败)的催收风险,开发者拿到的是确定的 12 个月 LTV 预期。在 StoreKit 中,你通过 billingPlanType == .monthly 筛选出承诺方案,用 commitmentInfo.price 展示总价。坑在于服务端处理:当收到 App Store Server Notifications V2 时,你必须解析 JWSTransaction 里的 commitmentInfo。如果 billingPeriodNumber 小于 totalBillingPeriods,说明用户还在承诺期内,此时即使用户在系统设置里点了取消,Apple 依然会按月扣费,你的服务端绝不能提前剥夺用户权益。
IAP 审核提交流程统一:告别“异步发版”的折磨
这绝对是基础设施层面的巨大进步。以前 IAP 审核和 App 审核是两条平行线,自动化发版脚本(比如 Fastlane)处理起来极其痛苦。现在 App Store Connect 的增强版提交体验(Enhanced submission experience)允许你把 IAP、订阅组、CPP(自定义产品页面)和 App 二进制文件打包在一起提交。
更关键的是 App Store Connect API 的更新。reviewSubmissions 接口现在支持 IAP 资源,旧的 IAP 专属提交 API 被直接废弃。这意味着你的 CI/CD 流水线必须重构。好处是状态完全同步,App 和 IAP 要么一起过审,一起被拒,不会再出现用户下载了新版 App 却买不到新 IAP 的尴尬。
代码片段
1. 在 StoreKit 视图中展示按月承诺方案
场景:使用原生的 SubscriptionStoreView 时,优先向用户展示 12 个月承诺期的按月付款选项,降低首屏价格锚点。
import StoreKit
import SwiftUI
struct SubscriptionStore: View {
var body: some View {
SubscriptionStoreView(groupID: "3F19ED53") {
// 自定义营销文案
}
// 筛选出按月承诺的计费方案
.preferredSubscriptionPricingTerms { _, subscriptionInfo in
subscriptionInfo.pricingTerms.first {
$0.billingPlanType == .monthly
}
}
}
}
坑:pricingTerms 数组里可能同时有 .upFront(一次性买断)和 .monthly,如果没做筛选,系统默认会展示 .upFront,你的“分期”低价优势就白做了。
2. 服务端解析承诺期进度
场景:在 App Store Server API 返回的 JWSTransaction 中,判断用户当前处于 12 个月承诺期的第几个月。
// 解析 JWSTransaction 中的承诺期信息
struct CommitmentInfo: Decodable {
let billingPeriodNumber: Int // 当前是第几个月
let totalBillingPeriods: Int // 总承诺月数(通常是 12)
let commitmentExpiresDate: Date // 整个承诺期结束的时间
}
// 在处理 Server Notification 时检查
if let commitment = transaction.commitmentInfo {
if commitment.billingPeriodNumber < commitment.totalBillingPeriods {
// 用户仍在承诺期内,即使他们取消了自动续订,Apple 也会继续扣费
// 保持用户的 Pro 权益,不要降级
}
}
坑:commitmentInfo 只有在 billingPlanType 为 .monthly 时才有值。如果是普通的年度预付订阅,这个字段是 nil,直接解包会导致服务端崩溃。
最佳实践
- 已有项目的迁移策略:立刻检查你的 CI/CD 脚本。如果你在用 Fastlane 的
deliver提交 IAP,准备迎接 App Store Connect API 的变更,将旧的 IAP 提交逻辑迁移到reviewSubmissions集合中。同时,全局搜索presentOfferCodeRedeemSheet,把旧的优惠码兑换逻辑替换为带RedeemOption和VerificationResult回调的新 API,现在你终于能准确知道用户兑换成功了没。 - 新项目的采用建议:所有订阅类 App,无脑加上“12个月承诺期按月订阅”选项,并和普通的“年度预付”做 A/B 测试。在 UI 上,用
billingDisplayPrice展示月供,用commitmentInfo.price展示总价,一定要在付款按钮上方清晰写明“承诺 12 个月”,避免客诉。 - 实战中容易踩的坑:在 Xcode 27 的 StoreKit Testing 中配置好 Billing Plan 后,别忘了在 Transaction Inspector 里手动模拟“用户中途取消”和“扣款失败”的场景,确保你的服务端状态机能正确处理
commitmentInfo的变化。
还有什么值得关注
- Bundles and Suites(订阅捆绑和套件):支持跨 App 的订阅打包销售,目前只能在 Xcode 27 里测试 API,具体商业化细节 Apple 卖了个关子,下半年再公布。
- Offer Code Redemption(优惠码兑换)API 升级:兑换接口现在返回
VerificationResult,不用再靠监听Transaction.updates去盲猜兑换结果了。 - Retention Messaging API 支持新订阅:服务器到服务器的留存消息 API 现在能识别 12 个月承诺期用户,方便你在他们快到期时精准推送挽留优惠。