文章目錄
  1. 1. 处理概览
  2. 2. App意外结束
  3. 3. 网络连接断开
  4. 4. Demo

之前写的一个iOS应用内购买模块的开发有很多地方需要考虑优化,其中最主要的是App意外结束网络连接断开。应用内购买比较缓慢,再加上购买后需要请求Server更新数据库以及Server进行二次验证,整个过程时间比较长,对于可能发生的意外需要慎重考虑。

接下来以Web调用IAP模块进行虚拟币购买为例说明

处理概览

整个处理过程可分为下图几部分,其中主要关注的是:

  • Client向App Store交易虚拟币购买
  • Client请求Server更新余额
    虚拟币充值总流程图

App意外结束

  • Client向App Store交易虚拟币购买
    这个阶段主要通过Apple提供的StoreKit框架来处理,交易从addPayment开始,至finishTransaction结束。需要注意的是在结束之前,payment一直处于队列中,并且监听器的代理函数`updatedTransactions`会被反复调用。这样就方便我们处理这个阶段中App意外结束的情况了,只要:

    1. finishTransaction之前处理IAP交易成功后的后续工作(更新Server余额等);

      • 待后续工作启动后才会将交易从队列中移除,这能保证后续工作总能启动,可也会带来App重启时重复启动后续工作的问题,这个可以用后面讨论的重传机制规避。
      1
      /// send request to Server
      ...
      
      [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
2. 在App启动之时就添加交易监听器(`SKPaymentTransactionObserver`)
    - 我将添加交易监听器的处理移到了AppDelegate`didFinishLaunchingWithOptions`函数中,使得App启动后就能处理先前意外结束留在队列中的交易。
    - 这里推荐一篇好文[In-App Purchase Best Practices](https://developer.apple.com/library/ios/technotes/tn2387/_index.html),这*Best*可是Apple官方说的。[中文翻译在此](http://mobile.51cto.com/iphone-448610.htm)
    - 为了保证App在重启时能处理意外结束的交易,我重构了代码:

重构前交易处理的依赖
之前的交易处理中,监听器IAPObserver通过Block调用IAPViewController来做IAP交易完成后的处理工作,它们之间是强依赖关系。
这样的问题是:重启时IAPViewController还没有创建,此时监听到的未完成交易无法启动后续处理工作。
考虑到:

1. 后续处理工作主要是与Server的交互,可以独立成新的类;
2. 采用`NSNotification`的方式可以弱化耦合,也可以实现一对多的关联

于是我将代码改成下面的样子:
重构后交易处理的依赖
更新Server的工作封装成单例ServerManager,和IAPViewController一样,都接收来自IAPObserver的消息,完成IAP交易成功后的工作。同时ServerManager会发送通知给IAPViewController,告知工作完成情况,由其来展示UI和通知调用者;当IAPViewController没有创建时,并不会影响Client请求Server更新的操作。

  • Client请求Server更新余额
    这个阶段由Client向Server发更新余额请求。为了应对可能出现的App结束,可以设立重传机制,具体来说:
    1. 先将请求数据本地化存储,再发起请求;
    2. 只有服务器正确返回且返回的是更新成功/更新重复/二次验证失败等情况时才移除本地存储的请求数据;
    3. App启动发起虚拟币充值网络连接恢复 时检查是否存在本地请求数据,如果存在则再次请求。

设立重传机制还可以应对网络连接断开出现的问题。

网络连接断开

网络连接断开处理首要是保证交易的一致性,即请求App Store购买虚拟币成功后也要成功更新Server虚拟币信息。Client分以下几个阶段考虑:

  1. 虚拟币充值发起前
    • 不作特别处理
  2. 与App Store进行虚拟币购买
    • 不作特别处理
  3. 发送更新虚拟币余额请求到Server前
    • 本地存储相关信息,下次再请求,确定成功更新Server的余额后删除
  4. 收到Server的返回信息前
    • 本地存储相关信息,下次再请求,确定成功更新Server的余额后删除

详细处理流程如下图:
Client进行虚拟币充值的处理

至于Server与App Store进行二次验证时发生的网络断开,这里不讨论。

Demo

GitHub上的代码库,有处理不当的地方,欢迎提Issues。

文章目錄
  1. 1. 处理概览
  2. 2. App意外结束
  3. 3. 网络连接断开
  4. 4. Demo