zoukankan      html  css  js  c++  java
  • iOS-IAP内购的那些事(iOS内购漏单的问题)

    前言

    说起内购,其实挺令开发者厌烦的,原因呢,先不说漏单的问题,首先苹果要扣除30%的销售额哦,可恨不?(我觉得可恨),有些想办法先隐藏掉第三方支付(支付宝、微信等),等项目上线了,再跳过内购使用第三方支付,emmmm.......这个方法确实不错,但是如果被苹果发现了,APP内虚拟产品调用第三方支付,那好吧,直接下架吧(或许没这么惨,但会惨不忍睹),不要说发现不了,会有人举报哦(别问我怎么知道的);其次就是漏单问题的处理,这一直是个问题,我的项目里虽然做了处理,但是还是会避免不了漏单的,只是把漏单的几率降到了很小,以确保我们维护,给大家分享下内购及漏单的处理。

    内购集成

    内购集成并不难,这里我用了一个Git上封装好的(IAPHelper),自己封装也简单(不想造那么多轮子了),封装的话,建议结合单例封装,充值验证都在单例里面进行;当然也可以不封装直接就用的,这里不多说了;建议最好根据服务器的验证方式与逻辑自己写个单利工具。

    支付逻辑

    1.临时单号

    首先根据内购商品ID(此商品ID是在苹果后台建好的内购商品)、用户信息(后台要求),传给服务器获取一个临时单号,然后先将该临时单号保存到一个变量里。在此之前,需要用数据持久化,对用户最后一次选择的内功商品ID进行永久储存,就算用户付款成功却充值失败了,即使App卸载了,也可以拿到最后一次请求的内购商品ID 。

    ///获取充值临时单号
    - (void)iapGetTemOrderIdWithProductId:(NSString *)productId{
        self.productId = productId;
        [SVProgressHUD showWithStatus:@"请稍后..." ];
        NSString *urlString = @"";
        [HttpTools getHttpRequestURL:urlString RequestSuccess:^(id repoes, NSURLSessionDataTask *task) {
            [SVProgressHUD dismiss];
            NSDictionary *dicTem = [HttpTools respoesToDic:repoes];
            if ([dicTem[@"code"] integerValue] == 1) {
                ///保存临时单号
                 self.temporaryOrderId = dicTem[@"data"];
                 ///发起内购支付
                 [self iapStartRecharge];
                
            }
            else{
                [SVProgressHUD showErrorWithStatus:dicTem[@"errmsg"]];
                [self errorPost:nil];
            }
            
        } RequestFaile:^(NSError *error) {
            [SVProgressHUD showErrorWithStatus:[HttpTools error:error]];
            [self errorPost:nil];
        }];
    }

    2.苹果充值

    通过商品ID调取苹果内购支付,苹果充值成功后,在返回成功的方法里,首先将上一步中的临时单号、用户信息(这里我取userId)、苹果充值成功返回的data,三个参数一起存入本地(我采用数据库存储)后,然后验证服务器充值(如果苹果充值验证失败,不必做任何操作)。

    ///发起内购支付
    - (void)iapStartRecharge{
        [SVProgressHUD showWithStatus:@"请稍后..."];
        NSSet* dataSet = [[NSSet alloc] initWithObjects:self.productId, nil];
        [IAPShare sharedHelper].iap = [[IAPHelper alloc] initWithProductIdentifiers:dataSet];
        // 请求商品信息
        [[IAPShare sharedHelper].iap requestProductsWithCompletion:^(SKProductsRequest* request,SKProductsResponse* response){
            
            if(response.products.count > 0 ) {
                SKProduct *product = response.products[0];
                [[IAPShare sharedHelper].iap buyProduct:product onCompletion:^(SKPaymentTransaction* trans){
                    if(trans.error){
                        [SVProgressHUD showErrorWithStatus:trans.error.userInfo.allValues[0]];
                        [self errorPost:nil];
                    }
                    else if(trans.transactionState == SKPaymentTransactionStatePurchased) {
                        NSLog(@"*********内部支付成功*********");
                        
                        ///将临时单号存在本地【此处做返回信息保存(临时单号、用户信息、返回的data)】
                        
                        ///去服务器验证充值

    /// 备注:这里要做两个判断,一是直接支付成功后回调的,二是App打开后,对上次验证失败回调到这里的
    } else if(trans.transactionState == SKPaymentTransactionStateFailed) { NSLog(@"*********支付失败*********"); if (trans.error.code == SKErrorPaymentCancelled) { } else if (trans.error.code == SKErrorClientInvalid) { } else if (trans.error.code == SKErrorPaymentInvalid) { } else if (trans.error.code == SKErrorPaymentNotAllowed) { } else if (trans.error.code == SKErrorStoreProductNotAvailable) { } else{ } [SVProgressHUD showErrorWithStatus:trans.error.userInfo.allValues[0]]; [self errorPost:nil]; } }]; }else{ // ..未获取到商品 [SVProgressHUD showErrorWithStatus:@"暂未获取到商品"]; [self errorPost:nil]; } }]; }

    3.服务器验证充值(上一步成功后验证)

    在苹果充值成功后,根据充值成功返回的数据data、临时单号、用户信息(后台要求)去服务器验证充值,如果验证成功,将上一步存在本地数据库的数据(临时单号、用户信息(这里我取userId)、苹果充值成功返回的data)删除;如果充值失败,即为漏单,但是已经将验证服务器充值的数据存在了本地数据库,可再次尝试,或者稍候尝试,根据自己的提示操作而定。

    ///向服务器验证进行充值
    - (void)iapPayOValidData:(NSString *)strReceipt temOrder:(NSString *)temOrder{
        ///验证充值
        [SVProgressHUD showWithStatus:@"正在为您充值..."];
        NSString *urlSting = @"";
        ///post data【验证参数】
        NSMutableDictionary *dicPost = [NSMutableDictionary dictionary];
        [HttpTools postHttpRequestURL:urlSting RequestPram:dicPost RequestSuccess:^(id respoes) {
            [SVProgressHUD dismiss];
            NSDictionary *dicValid = [HttpTools respoesToDic:respoes];
            if ([dicValid[@"code"] integerValue] == 1) {
    ///删除本地存的验证信息【临时单号、用户信息、苹果支付成功返回的data】 } else{ [self errorPost:dicValid[@"errmsg"]]; } } RequestFaile:^(NSError *erro) { [SVProgressHUD dismiss]; [self errorPost:[HttpTools error:erro]]; }]; }

     

    结束

    至此,整个内购充值流程已完毕,以上传递的参数、存储的参数,是根据服务器后台要求,可根据自己服务器后台商量,怎么做更好,如果大家有更好的方案,希望能借鉴!谢谢!

    最后还是要说说,不管怎么做漏单处理,总会有几个漏单的,但是几率很小,而且还想说,什么时候可以有办法躲过这30%的抽成.......

  • 相关阅读:
    Oracle NULL值
    关于微服务架构的权限控制初步设计
    .Net Core优化策略
    Winform如何不阻塞主进程UI的同时操作其他控件的输出
    数据结构与算法绪论学习 Day5_队列
    数据结构与算法绪论学习 Day4_栈
    数据结构与算法绪论学习 Day3_线性表
    数据结构与算法绪论学习 Day2 _算法效率的度量方法
    数据结构与算法绪论学习 Day1_基础概念
    数据结构与算法绪论学习 Day2 _线性表
  • 原文地址:https://www.cnblogs.com/wangkejia/p/9586172.html
Copyright © 2011-2022 走看看