欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2024-01-14 22:47:34
...

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

@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<SKPaymentTransaction *> *)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内购第二篇

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