iOS内购你看我就够了(一)

内购坑多,
开始(建议先去看些入门的)

@import StoreKit;

#import "IAPManager.h"

@implementation IAPManager
+ (instancetype)sharedInstance
{
    static id sharedInstance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstance = [[IAPManager alloc] init]; 
    });
    return sharedInstance;
}
单利的入口,传进来一个后台得到的商品ID(在苹果网站注册的)
- (void)payBtnPressed:(NSString *)product_id {//这传进来个商品id,lzc
    if ([SKPaymentQueue canMakePayments])//是否允许应用内付费
    {
        SKProductsRequest *request = [[SKProductsRequest alloc] initWithProductIdentifiers:[NSSet setWithObject:product_id]];
        request.delegate = self;
        [request start];
    }else
        DLog(@"用户不允许内购");//提示框
}

// 查询成功后的回调
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
{
    //这里菊花消失
    DLog(@"菊花消失");
    NSArray *products = response.products;
    if (products.count != 0) {
        
        self.product = products[0];
        SKMutablePayment *payment = [SKMutablePayment paymentWithProduct:self.product];//lzc 改
        payment.applicationUsername = @(1000000).stringValue;//充值用户的id,也就是uid.
        [[SKPaymentQueue defaultQueue] addPayment:payment];//发起购买
当然还有监听,这个东西写在程序入口比较好,至于为何下次讲
    }
    if (products.count == 0){
        DLog(@"无法获取商品");
    }
}
//查询失败后的回调
- (void)request:(SKRequest *)request didFailWithError:(NSError *)error {
    //菊花消失
    DLog(@"请求苹果服务器失败%@",[error localizedDescription]);
}

下边就是监听结果了

//监听购买结果,每个状态下都要结束订单,否则就坑爹了
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions {//当用户购买的操作有结果时,就会触发下面的回调函数,
    //菊花消失
    DLog(@"来监听购买结果吧");
    for (SKPaymentTransaction *transaction in transactions) {
       
        switch (transaction.transactionState) {
            case SKPaymentTransactionStatePurchased://交易成功
            
                [self completeTransaction:transaction];//验证
                //如果用户在这中间退出,咋办??不知道的看下一篇,坑坑坑都是坑
                DLog(@"结束订单了");
                [[SKPaymentQueue defaultQueue] finishTransaction:transaction];//验证成功与否,咱们都注销交易,否则会出现虚假凭证信息一直验证不通过..每次进程序都得输入苹果账号的情况
                break;
                
            case SKPaymentTransactionStateFailed:
             
               
                [self failedTransaction:transaction];//交易失败方法
                break;
                
            case SKPaymentTransactionStateRestored://已经购买过该商品

                DLog(@"已经购买过");
                [[SKPaymentQueue defaultQueue] finishTransaction:transaction];//消耗型不支持恢复,所以我就不写了

                break;
            case SKPaymentTransactionStatePurchasing:
                DLog(@"已经在商品列表中");//菊花
                break;
            case SKPaymentTransactionStateDeferred:
                DLog(@"最终状态未确定 ");
                break;
            default:
                break;
        }
    }
}

- (void)failedTransaction:(SKPaymentTransaction *)transaction
{
    if(transaction.error.code != SKErrorPaymentCancelled) {
        NSLog(@"购买失败");
    } else {
        NSLog(@"用户取消交易");
    }
    [[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}

下边就是和服务器验证凭证了,重点坑在这里

- (void)completeTransaction:(SKPaymentTransaction *)transaction
{
    if (self.cash != nil) { //self.cash这玩意我是点击商品后传进来的,所以通过它判断是不是漏单的,有他的话就走正常流程
        DLog(@"购买成功验证订单");
        NSData *data = [NSData dataWithContentsOfFile:[[[NSBundle mainBundle] appStoreReceiptURL] path]];
        NSString *a = [data base64EncodedStringWithOptions:0];
        NSLog(@"base64JSONString =---%@---",a);//得到凭证
      
        NSDictionary * dic = @{@"uid":用户id,
                               @"receipt":a,
                               还有后台要的其他东西,起码凭证和用户id是必须的吧};
        DLog(@"验证信息%@",dic);
        //存起来
        [self addDicToPayAry:dic];//先把这个信息存起到本地,这是你埋坑的第一步,有空再解释
        [self testForServer:dic];//和后台去二次验证,这个很必要
    }
else
    {
        DLog(@"漏单流程从本地取凭证去验证");
        [self checkUnTestReceipt];//从本地取凭证验证去,下篇分解
    }//不是点击cell 进来的,也就是说上次订单没结束,日狗去吧
}

服务器交互,只要服务器有反应咱就把本地的信息移除,因为验证成功删了正常,验证不成功说明凭证有假(当然也可能苹果出问题,这咱管不了了)删,咱这边服务器出毛病(我们后台说这个状态是后台验证过了但是没有发商品,用户找客服),删.
只有没和自己后台交互上的时候,我们就在本地找村过的凭证,有的话说明有没验证过的,咱继续验证.没的话(第一次也不会没,因为存过一次但是就没删过)说明都验证过了.总之这个过程不管怎么样都要结束订单.


- (void)testForServer:(NSDictionary *)dic
{
     WEAKSELF;
    [[NetWorkManager sharedInstance]postJsonData:dic url:url successBlock:^(id responseBody) {
        DLog(@"支付成功%@",responseBody);
        if ([responseBody[@"code"]isEqualToNumber:@(200)]) {
            DLog(@"1验证成功完成交易OKOKOKOK");
            if (weakSelf.paySuccessBlock){
                weakSelf.paySuccessBlock();//告诉外边UI做处理
            }
            [weakSelf removeDicFromPayAry:dic];//从本地移除凭证等信息dic
        }
        if (验证receipt-data失败) {
            DLog(@"1验证receipt-data失败");
            [weakSelf removeDicFromPayAry:dic];//移除
        }
        if (我们服务器有毛病) {
            [weakSelf removeDicFromPayAry:dic];
            DLog(@"1你去找客服吧我们服务器有毛病");
        }
        //        DLog(@"我结束订单了-----");
        
    } failureBlock:^(NSString *error) {
        DLog(@"%@和自己服务器交互失败11",error);
        [weakSelf checkUnTestReceipt];//和自己后台没联系上,所以要检查本地有没有存过的凭证,有的话继续验证.下篇详聊
    }];
}

篇幅问题,存凭证删凭证和再次验证凭证下次说.
还有订单没结束的坑(用户买成功了苹果服务器不给力,用户急脾气关应用了,订单还没结束)等等,下回分解.

8.25更,来埋坑了,点进来↓
iOS内购第二篇

感觉还是不太完美啊,先这样吧

你可能感兴趣的:(iOS内购你看我就够了(一))