美文网首页
苹果内购买-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开发和自己遇到的坑

    在接入微信支付和支付宝支付后被苹果拒绝了。审核条例 3.1.1 -In-App-Purchase。所以就研究了一波...

  • 苹果内购IAP 简单总结

    1. 何为苹果内购IAP IAP(in-app-purchase),指苹果平台上所有在应用内购买的虚拟商品(商品的...

  • Apple 内购

    关于内购所需东西:1.测试开发证书:需要打开in-app-purchase,绑定bundleid:com.arag...

  • iOS 内购的实现

    自己开发的视频直播项目,牵涉到充值金币,用到了苹果公司的内购,趴坑了两天,这里总结下实现苹果内购。 一. 创建测试...

  • 【iOS开发】IAP开发的那些坑

    最近正在做的项目,涉及到了IAP(In-App Purchase),即苹果的应用内购买。在开发过程中遇到了各种各样...

  • 2022-04-27关于苹果续订内购踩坑记录

    坑一 最近在看苹果内购的东西,小伙伴的APP要把非续订类型的购买,变成续订类型的,然后在提交完购买项时苹果返回了错...

  • Ios内购iap

    最近游戏项目需要上线,需要集成Ios内购 1:首先来谈谈遇到的坑 1)首先我们需要对苹果开发账号里进行配置(这里不...

  • iOS应用内付费(IAP)开发步骤

    iOS应用内付费(IAP)开发步骤 1.苹果iTunes Connect内购产品信息录入。 1)创建app内购买项...

  • iOS 内购

    简介 内购是苹果提供给开发者在应用内购买的唯一方式 配置 iTunesConnect后台创建应用和商品(Produ...

  • iOS内购自动续费验证交易凭证 status返回21003

    去苹果后台->功能->苹果应用内购买项目

网友评论

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

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