说说IOS内购那些事


1.支付类和协议

Store Kit框架下提供用来处理应用内购大致的类可以分为两部分:1.请求商品,2.购买商品。具体如下:
  • SKMutablePayment:该类为App Store定义了用户的付费请求功能,通过封装特定产品名称和购买数量,用来处理应用程序内购。

  • SKPayment:该类为App Store定义了用户的付费请求功能,通过封装特定产品名称和购买数量,用来处理应用程序内购。

  • SKPaymentQueue:该类为App Store交易支付提供了一个队列,用户可以通过它来校验支付。

  • SKPaymentTransaction:该类定义了支付队列对象。每当一个付款被添加到支付队列时就会创建一个该支付交易对象。当App Store已处理完支付交易时,该对象被回传到应用程序。完成的支付交易对象提供了收据,应用程序可以用它作为支付标识符,用来保存处理后支付的交易记录。

  • SKProduct:该类是作为SKProductsResponse的返回对象的一部分。每个产品对象提供有关您先前在iTunes Connect注册的产品信息。

  • SKProductsRequest:该类对象用于检索从App Store的产品列表本地化的信息。应用程序使用此请求提出局部价格等信息给用户,而无需维护该列表本身。

  • SKProductsResponse:该类对象是App Store在响应有关的产品的列表信息的请求时被返回。

  • SKReceiptRefreshRequest:该类允许应用程序刷新其收据。如果收据是无效或丢失,应用程序可以通过该类申请一个新的收据。在沙箱环境,您可以要求收据性质的任意组合进行测试与批量购买计划收益的状态转换。

  • SKRequest:该类是App Store的请求的抽象类。 SKRequest的子类代表不同类型的请求。

  • SKStoreProductViewController:该类对象提供了一个商店,允许用户从App Store购买其他媒体。

  • SKCloudServiceController:主要是针对Apple Music购买.

  • SKDownload:主要是针对Tunes购买.

Store Kit框架下提供以下协议用来处理请求事件
  • SKPaymentTransactionObserver:该协议为一个SKPaymentQueue对象的观察者提供方法。
  • SKProductsRequestDelegate:该协议声明由一个SKProductsRequest对象的委托实现的方法。委托收到该产品的信息请求是感兴趣的东西。
  • SKRequestDelegate:该协议声明了一个由SKRequest抽象类的任何子类实现的常用方法。
  • SKStoreProductViewControllerDelegate:当用户退出商店屏幕实现该协议的对象称为。通常情况下,这个协议是由您的应用程序最初显示的屏幕专卖店视图控制器实现的。

2.一般的内购流程

2.1 场景

用户点击进入一个内购页面,页面刷新当前版本支持的内购商品列表,用户点击商品列表中的一个商品,弹出app strore帐号校验,完成校验后,弹出提示框询问用户是否购买,点击购买或是取消。

2.2 流程

  1. 获取商品列表:这里获取商品列表,分两步,首先是从自己的服务器获取,其次是从app store获取。最终都是以app store获取为准。具体过程有以下几步:

  2. 每次进入商品列表界面都会直接去自己的服务器拉取。

  3. 拉取列表成功后,查询本地是否缓存了商品列表中的每一个商品id,

  4. 如果所有商品都已经缓存了,则直接返回商品列表,

  5. 如果校验发现有商品没有缓存(商品更新),此时,清空当前缓存,

  6. 并且直接去app store拉取商品列表,拉取成功后缓存再返回。

  7. 购买商品:点击某个商品进程购买,具体流程有以下几步:

  8. 检验当前是否支持内购(网络环境,权限等)

  9. 根据当前点击的商品,向自己的服务器去申请订单,如果申请订单成功

  10. 向app store发起支付请求,如果申请订单失败,直接返回提示信息

  11. 监听并等待app store返回支付交易信息。

  12. 如果交易完成,向自己的服务器更新订单状态,并结束完成app store交易。

  13. 如果交易失败,并结束完成app store交易。

  14. 如果交易取消,向自己的服务器取消订单,并结束完成app store交易。

2.3 状态处理

整个内购流程里面可分为两种类型的状态,一种是支付行为状态,就是从想苹果发起支付请求开始,中间包括支付校验的取消,确定两种行为状态,最后返回的支付交易完成和失败。一种是针对自己服务器的订单校验的状态,主要是开始校验,成功,失败,已校验,无法校验几种。

  1. 支付行为状态:该状态是通过监听app store回调来做区别处理。
  • 交易完成:获取交易凭证,如果苹果返回了交易凭证,需要更具该交易凭证去和本地服务器做校验,校验成功,说明本次交易成功了,如果校验失败了,(验证找不到订单号)需要更具本次交易重新向服务器申请订单,并校验该订单凭证。
  • 交易失败:如果是用户取消交易,直接向服务器取消本次订单。如果是交易失败,更新当前订单凭证到缓存中,用于下次校验。
  • 已购买过:更新当前订单凭证到缓存中,标致成功。
  • 交易加入队列:无处理。
  1. 本地订单校验凭证状态:该状态是根据支付行为状态用来对服务器的订单凭证进行管理。
  • 校验成功:交易完成后,通过app store返回的凭证信息,去向服务器进行校验,校验成功后,更新当前订单凭证到缓存中,标致成功。
  • 校验失败:尝试多次校验。

细节处理

1.缓存

主要缓存:商品列表信息,支付凭证信息。

  1. 商品列表信息:每次进入内购界面时,根据从服务器拉取的商品信息与本地缓存做比较后,如果保持一直,则直接返回,如果存在差异,则还需要从app store拉取商品信息,再更新本地缓存后返回。

  2. 支付凭证信息:缓存每次交易支付凭证,用来与服务器订单进行校验。针对校验失败的凭证,会采取多次校验。每次进入商品购买时,需要对上次缓存的未成功的支付凭证进行再次校验。以确保服务器订单状态正确。

2.流程顺序

具体流程以伪代码

  1. 获取商品列表

      - (void)fetchProducts:(xxxCompletBlock)complete {
          if (![netWork isAvalabel]) {
          if (complete)
            complete(....);
        }
    
          [[ProductsOrderModel shareInstance] fetchProductsFromServer:xxxx complete:^(BOOL success, NSArry* products,.....) {
          if (success) {
          // 检验本地缓存
          NSArry* cacheProducts = [[ProductOrderCache shareInstance] cacheProducte];
          ......
    
        //缓存与服务器一直
        if (complete) 
          complete(....);
    
        //如果不一致,再去app store拉取
        [ProductOrderCache shareInstance] cleanCacheProducte];
        [[ProductsOrderModel shareInstance] fetchProductsFromApple:xxxx     complete:^(BOOL success, NSArry* products,.....) {
            if (complete) 
              complete(....);
              ...
            }]; 
          } else {
          .....
        }
      }]; 
    }
    
  2. 支付

  - (void)orderProduct:(NSString*)id complete:(xxxCompletBlock)complete {
     //先去服务器获取订单
    [[ProductsOrderModel shareInstance] fetchOrderFromServer:id  complete:^(BOOL success, ...) {
        if (success) {
       //发起苹果支付

       SKPayment * payment = [SKPayment paymentWithProduct:product];
       [[SKPaymentQueue defaultQueue] addPayment:payment];
     } else {
         ....
     }
   }];
 }

 //苹果支付回调
 - (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions {

 for (SKPaymentTransaction *transaction in transactions)
 {
     switch (transaction.transactionState)
     {
         case SKPaymentTransactionStatePurchased:
             [self completeTransaction:transaction state:xxx_Succeed];
             break;
         case SKPaymentTransactionStateFailed:
             [self completeTransaction:transaction state:xxx_Failed];
             break;
         case SKPaymentTransactionStateRestored:
             [self completeTransaction:transaction state:xxx_Succeed];
             break;
         case SKPaymentTransactionStatePurchasing:
             break;
         default:
             break;
     }
   }
 }

 - (void)completeTransaction:transaction state:(xxx_State)state {
   switch(state) {
     case xxx_Succeed:
     {
     //拿到苹果返回的凭证去和服务进行校验
     [ProductsOrderModel shareInstance] verifyTransactionReceipt:xxx orderId:xxx complete:^(BOOL success, xxxx) {
     if (success) {
     // 更新缓存状态
          [[ProductOrderCache shareInstance] updateOrderState:xxxid state:YES];
           ...
          } else {
         // 再次校验
          ...
         }
       }];
       }
     break;

   case xxx_Failed:
   {
   // 更新缓存状态
     [[ProductOrderCache shareInstance] updateOrderState:xxxid state:NO];
    }
   break;
   default:
       break;
     }
   }

3.其他

  1. 每次进行购买时,需要对本地缓存的上一次失败凭证进行再次校验。
  2. 商品列表信息,支付凭证信息需要做文件缓存。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,390评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,821评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,632评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,170评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,033评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,098评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,511评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,204评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,479评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,572评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,341评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,893评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,171评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,486评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,676评论 2 335

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,050评论 25 707
  • 优化点 优化购买流程 使用新的api获取购买凭证 优化跟服务器的二次验证时机 原来支付购买流程 获取产品信息 用户...
    ios小菜阅读 1,552评论 0 1
  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 11,943评论 4 60
  • “全身心的投入工作,才是真正的强者。因为全身心工作的人,不管遇到任何事都不会忧疑、慌张、退缩、动摇、不安、怯弱。借...
    徐杨_杨言絮语阅读 184评论 0 1
  • 昨晚受邀出席朋友的开始吧众筹平台&M大生活(成都本土生活类公众号粉丝10W+)的周年庆。 居然不知道大成都的餐饮、...
    丁芸与茶阅读 667评论 0 1