苹果内购零丢单处理

@[TOC](苹果能够的零丢单操作)

# 文章的主要内容

你好!这是我发表的第一段关于苹果技术的博客,如果有说的不对的地方请指教,今天要分享一下自己对于苹果内购的经验。苹果内购的前期准备工作基本相同,关于申请内购项目的时候要注意的是,内购项目和APP是同时审核的,所以先创建的内购得等新版本审核成功后才能正式购买。本片文章主要是关于内购代码级别的分析。

## 内购分析

关于内购这块,我们项目已经经过3个人修改,当时上线的时候没有啥问题,但是随着内购内容越来越多,就出现了问题,丢单问题随之出现,经过我查看了苹果的内购官方文档,要求所有的内购统一管理,[苹果的官方解释](https://developer.apple.com/documentation/storekit/in-app_purchase#//apple_ref/doc/uid/TP40008267),创建一个观察者,然后在软件启动的时候定义观察者;

```javascript

-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{

[[SKPaymentQueue defaultQueue] addTransactionObserver:inPurchasingManage];

}

```

我定义的观察者是appdalagate里的一个属性,所以在其他界面使用时直接调用appdalagate.inPurchasingManage即可,注销该方法放在软件进程杀死状态下:

```javascript

-(void)applicationWillTerminate:(UIApplication *)application

[[SKPaymentQueue defaultQueue] removeTransactionObserver:inPurchasingManage];

}

```

这样不管在哪个界面发起内购的话,都会走观察者里面的代码。

## 观察者代码构建

首先是根据内购产品的ID发起内购,因为这个ID,我是从后台拿过来的,前边不做赘述,

```javascript

#pragma mark - 内购

-(void)requestProductData:(NSString *)type{

    NSArray *product = [[NSArray alloc] initWithObjects:type,nil];

    NSSet *nsset = [NSSet setWithArray:product];

    SKProductsRequest *request = [[SKProductsRequest alloc] initWithProductIdentifiers:nsset];

    request.delegate = self;

    [request start];

}

```

通过这段代码就能成功呼起苹果的内购支付,并且走了

<SKProductsRequestDelegate,SKPaymentTransactionObserver>代理回调方法,这些苹果官方说明都有讲,虽然现在用的是swift语言,但是对于我们还依然用OC的人来说,不在话下:

```javascript

#pragma mark - 实现SKProductsRequest的代理方法

    -(void)productsRequest:(SKProductsRequest *)request            didReceiveResponse:(SKProductsResponse *)response

{

      NSArray *product = response.products;

      if([product count] == 0){

      //如果这个参数没有,证明没有这个产品,也就不需要走下面的代码了

        return;

      }

      SKProduct *p = nil;

      for (SKProduct *pro in product) {

        if([pro.productIdentifier isEqualToString:Singleton.currentProId]){

            p = pro;

        }

      }

      SKMutablePayment *payment = [SKMutablePayment paymentWithProduct:p];

      NSString *userOrderNo = [NSString stringWithFormat:@"%@#%@",userID,orderNo];

      payment.applicationUsername = userOrderNo;

      [[SKPaymentQueue defaultQueue] addPayment:payment];

}

```

如果订单存在的话,就已经呼起内购了,说道这里可能有些人会质疑我存储订单号的方法,因为好多博客不推荐用applicationUsername来存储重要的数据,因为觉得可能会丢失数据,但是没有明确的操作会导致这个属性丢失,因为这里如果存着订单号,就很有可能消失,这样就会出现丢单问题,其实这个问题我也思考了,先不说这个参数容不容易丢,即使丢了怕啥,再给它申请个订单号不就得了。这个是我们厉害的后台想出来的办法,具体的订单号问题往下看,再说说我存的userID,是为了区别用户存的,避免了钱充错人的问题,(这里说一下存在的问题,如果一个用户付完款之后退出的账号,这时又赶巧applicationUsername丢失,如果用户下一次登录的是另一个账号,有可能充错人,但是不会丢单),下面是我重点介绍的逻辑:

```javascript

#pragma mark - 实现SKPaymentQueue的回调方法

/*

队列中的交易发生改变时,就会调用该方法

*/

- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions

{

    /*

    SKPaymentTransactionStatePurchasing,    正在购买

    SKPaymentTransactionStatePurchased,    已经购买(购买成功)

    SKPaymentTransactionStateFailed,        购买失败

    SKPaymentTransactionStateRestored,      恢复购买

    SKPaymentTransactionStateDeferred      未决定

    */

    for (SKPaymentTransaction *transation in transactions) {

        NSString *productIdentifier = transation.payment.productIdentifier;

        switch (transation.transactionState) {

            case SKPaymentTransactionStatePurchasing:

            break;


            case SKPaymentTransactionStatePurchased:{

                NSString *newOrderNo = transation.payment.applicationUsername;

              //这个方法就是用户支付成功后回调方法,这样就可以拿着订单号和用户id去校验了了

                break;


            case SKPaymentTransactionStateFailed:{


                // 用户取消或者支付失败取消订单

                NSString *newOrderNo = transation.payment.applicationUsername;


                break;


            case SKPaymentTransactionStateRestored:

                //如果显示已经购买过该商品,则恢复该商品的购买性 <非消耗型商品>             

                [self restoreCompletedTransactions:transation];           

                break;               

            case SKPaymentTransactionStateDeferred:{

                NSString *newOrderNo = transation.payment.applicationUsername;         

                [queue finishTransaction:transation];

                break;

            default:

                break;

        }

    }

}

```

SKPaymentTransactionStatePurchased 这个方法就是用户支付成功后回调方法,applicationUsernam就是发起内购时,我们赋值的用户id和订单号的拼接,这里讲一下我们的出来,不管这个订单号有没有,我们都会拿着receiptData去校验,获取方法如下,这时只要receiptData存在,后台就会去查询用户之前是否发起过一个订单号,如果有直接二次校验,如果没有,那就给用户申请一个新的订单号,然后再进行校验。这样不管用户有没有订单号都无所谓。

```javascript

    NSData *receiptData = [NSData dataWithContentsOfURL:[[NSBundle mainBundle] appStoreReceiptURL]];

```

## 着重所以下finishTransaction方法的处理

```javascript                 

  [[SKPaymentQueue defaultQueue] finishTransaction:transaction];

```

我只有在用户二次校验成功后才会调用该方法,如果不走这个方法,每次软件启动的时候,都会走上述的代理,所以如果你没有验证的话,用户卸载软件再安装以后还会走这代理,然后再去后天校验就行了,保证零丢单就是这么简单,不知道你们看懂没有?

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

推荐阅读更多精彩内容