美文网首页
苹果内购买-In-App-Purchase开发和自己遇到的坑

苹果内购买-In-App-Purchase开发和自己遇到的坑

作者: 追梦小怪兽 | 来源:发表于2017-12-23 11:10 被阅读0次
    1. 在接入微信支付和支付宝支付后被苹果拒绝了。审核条例 3.1.1 -In-App-Purchase。所以就研究了一波苹果内支付。
      下面只是代码部分,iTunes上面的协议领导解决了。
      第一步在工程中打开应用内支付,如下图:


      image.png

      然后在你的购买界面导入库:

    #import <StoreKit/StoreKit.h>
    

    购买界面添加2个代理:

    <SKPaymentTransactionObserver,SKProductsRequestDelegate>
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        // 苹果内购
        [[SKPaymentQueue defaultQueue] addTransactionObserver:self];
    }
    

    在你点击购买的事件中:

    if([SKPaymentQueue canMakePayments]){
            // 这里需要时间比较长,所以加一个菊花
            [WINDOW addSubview:self.hubView];  // 这个可以不管。
            [self requestProductData:self.currentProId]; // self.currentProId 这个是你正在购买的商品的ID,在iTunes Connect上面。我这边是在工程中加了宏定义,不过是从上个界面传过来的。
        }else{
            NSLog(@"不允许程序内付费");
        }
    

    接下来就是对代理方法的处理:<SKPaymentTransactionObserver,SKProductsRequestDelegate>
    当然这些代码网上都大同小异,我也是看了很多代码(英文文档看的头疼)

    //去苹果服务器请求商品
    - (void)requestProductData:(NSString *)type{
        NSLog(@"请求对应的产品信息");  
        NSArray *product = [[NSArray alloc] initWithObjects:type,nil];
        NSSet *nsset = [NSSet setWithArray:product]; 
        SKProductsRequest *request = [[SKProductsRequest alloc] initWithProductIdentifiers:nsset];
        request.delegate = self;
        [request start];
    }
    /// 苹果那边给的回调
    - (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response{
        // 收到苹果的回调之后菊花消失
        // [self.hubView removeFromSuperview];
        
        NSLog(@"收到产品反馈信息");
        NSArray *myProduct = response.products;
        NSLog(@"产品Pro ID:%@",response.invalidProductIdentifiers);
        NSLog(@"产品数量: %d", (int)[myProduct count]); // 当然我这里的数组只有一个商品
        
        SKProduct *pro = nil;
        for(SKProduct *product in myProduct){
            NSLog(@"Product id: %@" , product.productIdentifier);
            if ([product.productIdentifier isEqualToString:self.currentProId]) {
                pro = product;
            }
        }
        // 找到你想要的商品,那么就将这个商品加入购买队列。
        if (pro != nil) { 
            SKPayment *payment = [SKPayment paymentWithProduct:pro];
            [[SKPaymentQueue defaultQueue] addPayment:payment];
        }
    }
    
    /// 购买状态的回调
    - (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray<SKPaymentTransaction *> *)transactions{
        for (SKPaymentTransaction *transaction in transactions)
        {
            switch (transaction.transactionState)
            {
                case SKPaymentTransactionStatePurchased:{//交易完成
                    [[SKPaymentQueue defaultQueue] finishTransaction: transaction]; // 购买完成之后一定要移除队列
                    // 验证是否购买成功
                    [self verifyPurchaseWithPaymentTransaction:transaction];
                    
                    UIAlertView *alerView =  [[UIAlertView alloc] initWithTitle:@""
                                                                        message:@"购买成功"
                                                                       delegate:nil cancelButtonTitle:NSLocalizedString(@"关闭",nil) otherButtonTitles:nil];
                    
                    [alerView show];
                    
                } break;
                case SKPaymentTransactionStateFailed://交易失败
                { [self failedTransaction:transaction];
                    [[SKPaymentQueue defaultQueue] finishTransaction: transaction]; // 购买完成之后一定要移除队列
    
                    UIAlertView *alerView2 =  [[UIAlertView alloc] initWithTitle:@"提示"
                                                                         message:@"购买失败,请重新尝试购买"
                                                                        delegate:nil cancelButtonTitle:NSLocalizedString(@"关闭",nil) otherButtonTitles:nil];
                    
                    [alerView2 show];
                    
                }break;
                case SKPaymentTransactionStateRestored://已经购买过该商品
                    NSLog(@"已经购买过该商品");
                case SKPaymentTransactionStatePurchasing://商品添加进列表
                    NSLog(@"商品添加进列表");
                    break;
                default:
                    break;
            }
        }
    }
    
    // 验证购买成功的方法
    -(void)verifyPurchaseWithPaymentTransaction:(SKPaymentTransaction *)paymentTransactionp{
    //    NSString * productIdentifier = paymentTransactionp.payment.productIdentifier; // 商品id
    //    NSLog(@"productIdentifier Product id:%@", productIdentifier);
        
        NSString *transactionReceiptString= nil;
        
        //系统IOS7.0以上获取支付验证凭证的方式应该改变,切验证返回的数据结构也不一样了。
        NSString *version = [UIDevice currentDevice].systemVersion;
        if([version intValue] >= 7.0){
            // 验证凭据,获取到苹果返回的交易凭据
            // appStoreReceiptURL iOS7.0增加的,购买交易完成后,会将凭据存放在该地址
            NSURLRequest * appstoreRequest = [NSURLRequest requestWithURL:[[NSBundle mainBundle]appStoreReceiptURL]];
            NSError *error = nil;
            NSData * receiptData = [NSURLConnection sendSynchronousRequest:appstoreRequest returningResponse:nil error:&error];
            transactionReceiptString = [receiptData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];
        }else{
            
            NSData * receiptData = paymentTransactionp.transactionReceipt;
            //  transactionReceiptString = [receiptData base64EncodedString];
            transactionReceiptString = [receiptData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];
        }
       // 自己后台校验
        [self verifyInAppPurchaseWithReceipt:transactionReceiptString];
    }
    
    // 自己后台校验的方法实现
    // 我们后台校验
    - (void)verifyInAppPurchaseWithReceipt: (NSString *)receipt {
        NSString * userId = [USERDEFAULTS objectForKey:@"account"];
        NSString * isSandbox = nil;
    #ifdef DEBUG 
        isSandbox = @"true";
    #else
        isSandbox = @"false";
    #endif
                   // 下面就是你去调用后台的接口,根据返回成功或失败来处理相应的UI和逻辑。   
                   // isSandbox 给后台判断是否是沙盒测试。当然这是后台的事情,你也不用管。
                   //沙盒测试环境验证
                   #define SANDBOX @"https://sandbox.itunes.apple.com/verifyReceipt"
                   //正式环境验证
                   #define AppStore @"https://buy.itunes.apple.com/verifyReceipt"
    }
    
    // 一些失败的回调
    - (void)request:(SKRequest *)request didFailWithError:(NSError *)error{
        [AlertView alertViewWithTitle:[NSString stringWithFormat:@"%@",[error localizedDescription]]]; // 一个弹窗
    }
    
    - (void) failedTransaction: (SKPaymentTransaction *)transaction{
        NSLog(@"交易失败");
        if (transaction.error.code != SKErrorPaymentCancelled){
             // code
        }
    //    [[SKPaymentQueue defaultQueue] finishTransaction: transaction];
    }
        
    // 最后移除监听*************************************这一步我要重点说一下我遇到的坑
    -(void)dealloc{
        [[SKPaymentQueue defaultQueue] removeTransactionObserver:self];//移除监听
    }
    
    

    在最后一步移除监听的时候,有个问题。就是在页面切换后这个dealloc不走。。
    *************不走会导致你购买过的商品还会出现在商品列表中**************
    反正这个很烦就是了。

    那么问题来了,为啥他不走呢?
    我的理解是:
    ****** 在block 中有self.语法导致循环引用。没有走dealloc。*****
    然后我不管了。反正我这个商品只需要他购买一次。在切换页面的时候强行移除监听就完事了。
    所以我将移除监听的方法写到了viewwilldisappear中。。不要骂我。当然需求决定你该怎么处理。

    下面给大家一些链接吧。这些都是有iTunesConnect中的设置。
    https://www.2cto.com/kf/201605/513647.html
    http://www.jianshu.com/p/c252b2ccb078
    当然也得谢谢上面2个文章的作者

    -- 来自涛胖子的工作笔记

    相关文章

      网友评论

          本文标题:苹果内购买-In-App-Purchase开发和自己遇到的坑

          本文链接:https://www.haomeiwen.com/subject/jjzawxtx.html