前语

内购这种跟实践收益有联络的内容,一般都是每个公司关怀的重中之重,也是我们开发者所需求关怀的重中之重,所以今天就内购方面的内容,从一个最简略的内购流程通过各个特别场景的处理结束一步步完善。觉得太长可以直接看完毕部分

基础内购

在文章的最初步,我们仿照一个最基础的内购处理场景,即能确保正常流程到账的情况,再根据不同场景做后续优化。

基础的内购的处理流程为:

客户端流程:

graph LR
用户充值 --> 下单传递userId --> 下单成功 --> 充值 --> 苹果回来成功 --> 上报凭证传递userId --> 收到成功回调 --> 关闭生意事务

服务端流程:

下单:

graph LR
接收客户端下单信息 --> 订单信息入库 --> 回来订单号

上报凭证:

graph LR
接收客户端上报凭证 --> 找苹果校验成功 --> 回来客户端成功 --> 客户端关闭生意事务
找苹果校验成功 --> 通过userId查找对应的订单 --> 充值到账并写入凭证的transactionId 

成功交互图:

交互图由于内容过多,暂时只显示成功流程的交互进程

sequenceDiagram
用户->>客户端: 点击充值
客户端->>服务端: 下单(带userId)
服务端->>服务端: 订单入库
服务端-->>客户端: 下单成功
客户端->>苹果: 调用充值接口
苹果-->>用户: 充值操作
用户->>苹果: 充值结束
苹果-->>客户端: 回调充值成功
客户端->>服务端: 上报凭证(带userId)
服务端->>苹果: 调用凭证验证接口
苹果-->>服务端: 凭证验证合法
服务端-->>客户端: 上报成功
客户端-->>用户: 提示充值成功
服务端->>服务端: 通过userId查询订单信息
服务端->>服务端: 充值到账并写入凭证的transactionId 

问题与分析处理

在运用基础内购的流程下,最简略遇到的问题就是账号切换导致的失常问题

场景一: 充值间切换账号

场景环境

一台设备,两个登录账号 A 与 B。

失常流程:

A 账号下单充值,充值结束且在苹果未回来的情况下,切换到 B 账号,此时凭证变成由B上报。

实际情况:

游戏中,工会的管理人员需求经常切换帐号,或许切换小号进行不同的操作,在正常充值之后,假设用户没注意到账情况,直接切换帐号,那么就有或许出现该情况

失常体现:

  1. 假设此时查看下单记载。也就是会查询之前该 userId 之前的下单,那么发现之前未下过单,无法到账,导致丢单
  2. 假设此时不查看下单记载,直接验证后到账B账号,就会串单现象

解决方案:

运用设备ID(IDFV)加锁的方案,每个设备,每个商品id在无缺流程中只能存在一笔订单,假设订单未结束那么就不答应再次建议充值,这样即运用户切换到B帐号,上报凭证时则根据设备ID进行订单的检索并结束到账。

解锁场景更新:

解锁场景
苹果回来成功并上报凭证成功
苹果回来充值失利

流程更新:

客户端流程:


graph LR
用户充值 --> 下单传递IDFV --> 下单成功 --> 充值 --> 苹果回来成功 --> 上报凭证传递IDFV --> 收到成功回调 --> 关闭生意事务
充值 --> 苹果回来失利 --> 上报失利信息(传递IDFV) --> 收到接收回调 --> 关闭生意事务

服务端流程:


下单:

graph LR
接收客户端下单信息 --> 查找订单列表中对应设备id是否存在加锁的订单
查找订单列表中对应设备id是否存在加锁的订单 --> 存在加锁订单 --> 回来锁单中
查找订单列表中对应设备id是否存在加锁的订单 --> 不存在加锁订单 --> 创建订单并入库 --> 订单置为锁单情况 -->  回来订单号

上报凭证:

graph LR
接收客户端上报凭证 --> 找苹果校验成功 --> 回来客户端成功 --> 客户端关闭生意事务
找苹果校验成功 --> 通过设备id查找对应的订单 --> 充值到账
通过设备id查找对应的订单 --> 订单解锁并写入凭证的transactionId 

上报失利:

graph LR
接收客户端上报失利信息 --> 通过设备id查找对应的订单 --> 订单解锁 --> 回来接受成功
接收客户端上报失利信息 --> 失利信息写入日志

充值成功交互图:


sequenceDiagram
用户->>客户端: 点击充值
客户端->>服务端: 下单(带IDFV)
服务端->>服务端: 订单入库并加锁
服务端-->>客户端: 下单成功
客户端->>苹果: 调用充值接口
苹果-->>用户: 充值操作
用户->>苹果: 充值结束
苹果-->>客户端: 回调充值成功
客户端->>服务端: 上报凭证(带IDFV)
服务端->>苹果: 调用凭证验证接口
苹果-->>服务端: 凭证验证合法
服务端-->>客户端: 上报成功
客户端-->>用户: 提示充值成功
服务端->>服务端: 通过IDFV查询订单信息
服务端->>服务端: 订单解锁并写入凭证的transactionId 
服务端->>服务端: 充值到账

场景二:解锁失常

场景环境:

充值进程中,关闭运用并吊销支付

失常流程:

用户下单充值进程之后,关闭运用并吊销支付。此时苹果不再回来任何支付信息。

失常体现:

由于苹果未回来任何信息,导致服务端一向未解锁订单,然后在卸载重装之前无法充值。

实际情况:

用户或许只是误点击充值,为了避免充值成功,则或许会直接关闭运用,并吊销充值,此时就会出现该情况

解决方案:

在引发充值之后,假设未回来过充值成功,则在下次服务端回来充值失利时,可以假定用户充值失利,则直接进行解锁操作。

解锁场景更新:

解锁场景
苹果回来成功并上报凭证成功
苹果回来充值失利
重启运用后的初度下单回来确定,且苹果未回来充值信息

流程更新:

客户端流程:


graph LR
用户充值 --> 下单传递IDFV --> 下单成功 --> 充值 --> 苹果回来成功 --> 上报凭证传递IDFV --> 收到成功回调 --> 关闭生意事务
充值 --> 苹果回来失利 --> 上报失利信息(传递IDFV) --> 收到接收回调 --> 关闭生意事务
下单传递IDFV --> 回来锁单中 --> 判别为翻开运用后初度下单 --> 上报苹果未回来  --> 收到上报回调 --> 下单传递IDFV

其他流程无需更新

场景三:卸载重装无法到账

场景环境:

一台设备,充值进程中卸载重装运用

失常流程:

账号下单充值,充值结束且在苹果未回来的情况下,卸载重装运用,此时凭证上报时分的设备id产生了改动,导致无法找到设备ID对应的订单。(假设运用保存在 keychain 中的 idfv,则康复出厂设置时也将无法获取到之前保存的 idfv)

实际场景:

用户在充值之后,或许由于网络问题,暂时无法到账,瞬间弃坑删除运用,再过一段时间的镇定期后,又从头继续下载运用,此时就会出现该情况

解决方案:

上报凭证时分有两种地方获取,一个是旧的直接通过 transactionData 获取, 一种是官方推荐的 NSBundle 中获取。我们需求优化的点在于两处内容一起上报,解析 transactionData 时,可以获取到 UniqueVendorIdentifier ,这个与建议充值时分的 IDFV 的值是相同的,我们就可以针对这点来做订单的相关,并运用bundle中的凭证信息做安全相关的查验。(实践上,直接运用 transactionData 中的数据也是可以的,现在通过苹果验证后的暂未发现失常情况)

流程更新:

服务端流程:


上报凭证:

graph LR
接收客户端上报凭证 --> 找苹果校验成功 --> 回来客户端成功 --> 客户端关闭生意事务
找苹果校验成功 --> 提取凭证中的UniqueVendorIdentifier --> 查找对应的订单 --> 充值到账并写入凭证的transactionId 
查找对应的订单 --> 订单解锁

其他流程无需更新

场景四:充值成功但是到账慢

情况有多种,但是体现相似,就放一起谈论
环境场景:

  1. 设备自身网络较慢
  2. 服务器与苹果链接慢
  3. 服务端失常导致入库失利

失常流程:

  1. 玩家自身网络慢,导致苹果回来充值成功之后,上报凭证服务端超时,依照正常流程则需求苹果再次下发充值成功才会再次上报,间隔时间长。
  2. 服务器找苹果校验凭证信息,接口调用时间过长导致超时,回来客户端失利,然后等候下次上报
  3. 服务器自身出现失常(内存满了、发布中等)导致入库失常,回来客户端失利等候从头上报

实际情况:

电梯中或许高铁上玩手机进行充值,时常会有信号欠好的时分,此时即为该情况

解决方案:

  1. 客户端收到苹果下发的充值成功信息后,保存凭证到内存中再进行上报凭证到服务端的操作,上报成功后移除对应凭证信息,上报失利则进行延迟重试处理
  2. 服务端收到上报的凭证时,入库成功后则直接回来成功给客户端,然后再调用苹果接口校验凭证是否合法,假设产生超时情况,则拖延进行重试。

更新的流程放在完毕处

完毕

以上为旧版 storekit 所运用的方案,在现在已知情况下除了苹果自身多次扣款,其他情况都能确保充值的正常到账。新版的 storeKit 可以直接运用 appAccountToken 进行相关。假设有其他情况,欢迎一起谈论

无缺解锁场景

解锁场景
苹果回来成功并上报凭证成功
苹果回来充值失利
重启运用后的初度下单回来确定,且苹果未回来充值信息

无缺流程

客户端流程:


graph LR
用户充值 --> 下单传递IDFV --> 下单成功 --> 充值 --> 苹果回来成功 --> 保存凭证信息 --> 上报凭证 --> 收到成功回调 --> 关闭生意事务 --> 移除保存的凭证
上报凭证 --> 收到失常回调 --> 延时30s --> 上报凭证
充值 --> 苹果回来失利 --> 上报失利信息(传递IDFV) --> 收到接收回调 --> 关闭生意事务
下单传递IDFV --> 回来锁单中 --> 判别为翻开运用后初度下单 --> 上报苹果未回来  --> 收到上报回调 --> 下单传递IDFV

服务端流程:


下单:

graph LR
接收客户端下单信息 --> 查找订单列表中对应设备id是否存在加锁的订单
查找订单列表中对应设备id是否存在加锁的订单 --> 存在加锁订单 --> 回来锁单中
查找订单列表中对应设备id是否存在加锁的订单 --> 不存在加锁订单 --> 创建订单并入库 --> 订单置为锁单情况 -->  回来订单号

上报凭证:

graph LR
接收客户端上报凭证 --> 央求苹果凭证校验接口 --> 苹果校验回来成功 --> 回来客户端成功 --> 客户端关闭生意事务
苹果校验回来成功 --> 提取凭证中的UniqueVendorIdentifier --> 查找对应的订单 --> 充值到账并写入凭证的transactionId 
查找对应的订单 --> 订单解锁
央求苹果凭证校验接口 --> 找苹果校验超时 --> 延时30s --> 央求苹果凭证校验接口

上报失利:

graph LR
接收客户端上报失利信息 --> 通过设备id查找对应的订单 --> 订单解锁 --> 回来接受成功
接收客户端上报失利信息 --> 失利信息写入日志

充值成功交互图:


sequenceDiagram
用户->>客户端: 点击充值
客户端->>服务端: 下单(带 IDFV)
服务端->>服务端: 订单入库并加锁
服务端-->>客户端: 下单成功
客户端->>苹果: 调用充值接口
苹果-->>用户: 充值操作
用户->>苹果: 充值结束
苹果-->>客户端: 回调充值成功
客户端->>服务端: 上报凭证
服务端->>苹果: 调用凭证验证接口
苹果-->>服务端: 凭证验证合法
服务端-->>客户端: 上报成功
客户端-->>用户: 提示充值成功
服务端->>服务端: 通过凭证获取的UniqueVendorIdentifier查询订单信息
服务端->>服务端: 订单解锁并写入凭证的transactionId 
服务端->>服务端: 充值到账

FAQ

  1. 多次扣款时怎样补发给用户?

这种情况由于是极少数情况,只能定位到多次扣款的那个订单信息,并定位供认最近的订单,并跟用户供认后手动补发

  1. 怎样验证重复上报凭证

上报凭证时分,先判别凭证的 transactionId 是否已存在,假设已存在则说明已上报过,直接回来成功即可

  1. 是否要做其他的限制

凭证验证成功后,查询订单时,查询凭证充值时间前的订单即可,并供认解析后的包名是否正确,假设需求的话,可以考虑查询到过早的订单时,不进行到账处理并预警该订单


  • 我正在参与技能社区创作者签约方案招募活动,点击链接报名投稿。