背景简介
In-App Purchase(以下简称IAP)是苹果为开发者提供的应用内购服务。开课吧客户端也接入了IAP服务用于充值虚拟币。最近收到客服小姐姐反馈有学员在APP上充了钱,但是没到账。于是就有了这篇关于IAP掉单问题优化的方案。
掉单问题分析
首先根据源码重新梳理之前的支付流程:
流程总的来说主要分为3步:
- 客户端调用Kaikeba Server创建订单
- iTunes store支付完成,Apple Server通知客户端
- 客户端调用Kaikeba Server验证订单
从流程上来看,导致掉单有以下几种可能:
- 用户支付成功,Apple Server回调客户端通信失败。
- Apple Server回调客户端后,客户端与Kaikeba Server通信失败。
- Kaikeba Server验证成功后,Kaikeba Server与客户端通信失败。
所以防止掉单就要从这几个方面入手。
解决方案
新的支付流程如下:
新的流程通过以下几种方式解决掉单问题:
- 网络异常重试,减少掉单
- 利用苹果事务机制保存交易,重启APP后自动补单
- 在使用applicationUsername传递OrderNo时,同时Keychain保存OrderNo,防止OrderNo丢失
- 对于丢失了OrderNo的订单,Kaikeba Server根据用户之前创建的订单获取
网络异常重试
网络异常重试:主要是为了避免在付款成功后,用户网络状况发生变化(如,乘坐地铁进入隧道)导致与Kaikeba Server通信失败或者Kaikeba Server服务器挂掉自动重启导致通信异常。
同时为了避免频繁的重试,设置5次重试间隔分别是:1,5,10,100,600
苹果事务机制
IAP中每一次支付行为都被抽象成一个事务(SKPaymentTransaction),只有事务被正常完结(调用finishTransaction:)本次支付行为才算完成。在每一次app启动时,通过调用addTransactionObserver:就会触发之前所有未完结的事务。详见:支付队列观察者。所以,由于事务机制的存在,我们只需做到以下两点就可以避免掉单:
- 对于每一个支付事务,在确保服务端处理完后再结束(finishTransaction:)该事务。
- App启动时,注册支付队列观察者(addTransactionObserver:)并添加相应补单逻辑。
业务OrderNo丢失
开课吧IAP中创建订单生成的OrderNo是通过SKMutablePayment的applicationUsername来传递的,但是Apple提供applicationUsername,是为了防止用户作弊而不是用于透传业务信息的。如果用户不停的卸载APP,OrderNo就会有可能丢失。
为了防止OrderNo丢失后导致掉单,所以我们把校验接口的OrderNo改为了非必传参数,如果OrderNo丢失,那么Kaikeba Server根据用户之前创建的订单重新获取。
注意事项
1、 [NSBundle mainBundle].appStoreReceiptURL
只是一个URL,在用户付款成功后,系统会把receipt写入到这个位置。取receipt的时候要判空,如果文件不存在,就要从苹果服务器重新刷新下载receipt了。SKReceiptRefreshRequest刷新的时候,需要用户输入Apple ID,同时需要网络状态良好
NSURL *receiptURL = [NSBundle mainBundle].appStoreReceiptURL;
if(![[NSFileManager defaultManager] fileExistsAtPath:receiptURL.path])
{
SKReceiptRefreshRequest *receiptRefreshRequest = [[SKReceiptRefreshRequest alloc] initWithReceiptProperties:nil];
receiptRefreshRequest.delegate = self;
[receiptRefreshRequest start];
return;
}
NSData *receiptData = [NSData dataWithContentsOfURL:receiptURL];
2、 程序加入支付队列使用的SKMutablePayment属性具有读写权限,
SKPayment属性只读,如果你要使用
applicationUsername透传字段,那么就一定要使用
SKMutablePayment`加入支付队列
3、 透传字段applicationUsername
可能返回的是nil
4、 updatedTransactions:
在App
整个生命周期只会走一次
5、 transactionReceiptData
可以无限验证通过,也就是说一个凭证可以被校验多次,需要防止有人通过这个刷单
优化后的特性
- 即使用户删除卸载开课吧APP 重新安装登录以后 也可以找回订单 并且实现自动补单
- 如果用户购买完成之后,网络条件不好,APP会按照斐波那契数列来做为每一次重试的间隔,总共重试10次(2分半钟),10次后如果还是不行,就联系客服,如果中间中断了(用户退出APP)APP重启后会自动补单
结果
埋点数据统计出来了再补上。。。
能否把这个源码或者文档之类的资料 关于 iap的发给我一下呀