一、介绍
iOS 的 App 内购类型主要分为四种:
-
消耗型商品:只可使用一次的产品,使用后即失效,需再次购买。
示例:钓鱼 App 中的鱼食。 -
非消耗型商品:只需购买一次,不会过期或随着使用而减少的产品。
示例:游戏 App 的赛道。 -
自动续期订阅:允许用户在固定时间段内购买动态内容的产品。除非用户选择取消,否则此类订阅会自动续期。
示例:每月订阅提供流媒体服务的 App。 -
非续期订阅:允许用户购买有时限性服务的产品,此类订阅不会自动续期。
示例:为期一年的已归档文章目录订阅。
在完成这个项目的过程中,我发现自动续期订阅类型是最复杂的。其他几类内购都是一次性的,而自动续期订阅涉及到免费试用期、促销期等概念,用户还可以选择取消续订或恢复续订。后台需要处理许多相应的逻辑操作。以下是我在实现自动续订订阅类型过程中遇到的一些问题和经验,希望能对大家有所帮助。
二、创建自动续订类型时需要注意的地方
1. App 专用共享密钥
需要创建一个 “App 专用共享密钥”,用于接收此 App 自动续订订阅收据的唯一代码。该秘钥用于向苹果服务器校验票据 receipt,不仅需要传递 receipt,还需传递此秘钥。如果需要将此 App 转让给其他开发人员,或将主共享密钥设置为专用,可能需要使用 App 专用共享密钥。
2. 订阅群组
创建自动续订类型时,如果还不存在订阅群组,就需要创建一个,以向用户提供一系列内容供应、服务等级或时限。名字可以随意起,只要有代表意义即可。一个群组下可以有多个自动续订订阅。如果要进行促销优惠,每个顾客可以享受每个订阅群组的一个推介促销优惠一次。
一个订阅群组中的订阅是 互斥 的,意味着用户只能一次订阅一个群组中的一个选项。如果希望用户能够一次购买多个订阅,可以将这些 App 内购买项目放在不同的订阅群组中。
3. 订阅状态 URL
自动续订订阅还需要填写订阅状态 URL。在 App 信息 中配置后,后台就能收到 server to server 的通知。文章最后将详细讲解后台的相关操作。
4. 推介促销优惠
推介促销优惠可以设置各种优惠,例如前七天免费试用,或前两个月半价等。
推介促销优惠的三种类型:
| 属性 | 描述 |
|————–|——————————————————————————————|
| 随用随付 | 顾客按选定时限的每个结算周期支付折扣价格(例如,标准价格为 9.99 美元,折扣价为前 3 个月每月 1.99 美元)。 |
| 提前支付 | 顾客一次性支付选定时限的折扣价格(例如,标准价格为 9.99 美元,折扣价为前 2 个月 1.99 美元)。 |
| 免费 | 顾客在选定的时限内免费访问订阅。时限可以是 3 天、1 周、2 周、1 个月、2 个月、3 个月、6 个月或 1 年。 |
⚠️ 注意:此价格面向新顾客。推介促销优惠可用于吸引新顾客。用户享受过七天免费试用后,下次将无法再享受。
三、内购流程
1. 流程简述
iOS内购的通用流程如下:
- 用户向苹果服务器发起购买请求,收到购买完成的回调(购买完成后会将款项打入申请内购的银行卡)。
- 购买成功后,向服务器发起验证凭证(app端也可以自行验证)。
- 自己的服务器工作分为 4 步:
- 接收 iOS 端发过来的购买凭证。
- 判断凭证是否已经存在或验证过,然后存储该凭证。
- 将凭证发送到苹果的服务器(区分沙盒环境和正式环境)验证,并将验证结果返回给客户端。
- 修改用户相应的会员权限或发放虚拟物品。
简单来说,将购买凭证用 Base64 编码,然后 POST 给苹果的验证服务器,苹果将验证结果以 JSON 形式返回。
2. 具体实现
自动订阅类型需要注意:
- app开始运行时,一定要添加监听:
objc
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
因为自动订阅类型,除了第一次购买行为是用户主动触发的,后续续费都是 Apple 自动完成的。一般在到期前 24 小时开始,苹果会尝试扣费,扣费成功后会在 APP 下次启动时主动推送给 APP。因此,APP 启动时一定要添加上述代码。
⚠️ 订单结束后一定要执行 finishTransaction 操作:
objc
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
以下是重要的几个代理方法的实现:
首先引入苹果内购必须的库 StoreKit:
objc
import
(1) 开始调起支付流程,请求商品信息
objc
– (void)payWithAppleProductID:(NSString )productId {
if ([SKPaymentQueue canMakePayments]) {
NSArray productIdentifiers = @[productId];
NSSet set = [NSSet setWithArray:productIdentifiers];
SKProductsRequest request = [[SKProductsRequest alloc] initWithProductIdentifiers:set];
request.delegate = self;
[request start];
} else {
// 用户手机禁止应用内付费购买
}
}
(2) 判断购买结果
objc
– (void)paymentQueue:(SKPaymentQueue )queue updatedTransactions:(NSArray )transactions {
for (SKPaymentTransaction *tran in transactions) {
switch (tran.transactionState) {
case SKPaymentTransactionStatePurchased:
NSLog(@”交易完成”);
// 处理交易
break;
case SKPaymentTransactionStatePurchasing:
NSLog(@”商品添加进列表”);
break;
case SKPaymentTransactionStateRestored:
NSLog(@”已经购买过商品”);
[[SKPaymentQueue defaultQueue] finishTransaction:tran];
break;
case SKPaymentTransactionStateFailed:
NSLog(@”交易失败”);
[[SKPaymentQueue defaultQueue] finishTransaction:tran];
break;
default:
break;
}
}
}
四、各种情况
1. 升级和计划变更
用户可以在 App Store 或应用的帐户设置中管理他们的订阅。对于每个订阅,App Store 会显示所有续订选项,用户可以随时选择升级、降级或交叉评级。
2. 到期和续订
订阅续订过程在到期日期前十天开始。App Store 会检查可能会延迟或阻止订阅自动续订的任何结算问题,例如客户的付款方式不再有效等。
3. 取消
用户只能通过联系 Apple 客户服务获得退款。客户可以在订阅期间取消订阅,但订阅仍在同一时期结束时支付。
五、服务端验证
为了安全起见,大部分公司都会选择让服务器端去验证订单的有效性。首先要在 itunes connection 上配置自动续期订阅,具体可参考苹果官方文档。
如果配置了 server to server 的通知,后台将收到几种状态更新通知类型:
| NOTIFICATION_TYPE | 描述 |
|—————————|——————————————————————————————|
| INITIAL_BUY | 初次购买订阅。通过在App Store中验证,可以随时将您的服务器存储在服务器上以验证用户的订阅状态。 |
| CANCEL | Apple客户支持取消了订阅。检查Cancellation Date以了解订阅取消的日期和时间。 |
| RENEWAL | 已过期订阅的自动续订成功。检查Subscription Expiration Date以确定下一个续订日期和时间。 |
| INTERACTIVE_RENEWAL | 客户通过应用程序界面或在App Store中以交互方式续订订阅。服务立即可用。 |
| DID_CHANGE_RENEWAL_PREF | 客户更改了在下次续订时生效的计划。当前的有效计划不受影响。 |
六、沙盒测试
在测试自动续期订阅时,时限会缩短,测试订阅最多仅能自动续期 6 次。
| 实际时限 | 测试时限 |
|———-|———-|
| 1 周 | 3 分钟 |
| 1 个月 | 5 分钟 |
| 2 个月 | 10 分钟 |
| 3 个月 | 15 分钟 |
| 6 个月 | 30 分钟 |
| 1 年 | 1 小时 |
⚠️ 注意:如果通过 TestFlight 安装的,则需要使用真实的账号进行购买。
七、关于审核
1. 自动续订订阅的说明
自动续订订阅必须在 app 中有详细的说明。
2. 不允许强制用户必须登录才能购买
苹果规定所有内购绑定的账号都应该是 apple 账号,因此未登录状态下也应能购买。