美文网首页iOS开发苹果内购
iOS内购IAP(二) —— 工程实践(一)

iOS内购IAP(二) —— 工程实践(一)

作者: 刀客传奇 | 来源:发表于2017-05-24 01:53 被阅读0次

    版本记录

    版本号 时间
    V1.0 2017.05.24

    前言

    大家都知道,ios虚拟商品如宝石、金币等都需要走内购,和苹果三七分成,如果这类商品不走内购那么上不去架或者上架以后被发现而被下架。最近有一个项目需要增加内购支付功能,所以最近又重新集成并整理了下,希望对大家有所帮助。感兴趣的可以参考上面几篇。
    1. iOS内购IAP(一) —— 基础配置篇(一)

    实现详情

    这里ios开发平台上的证书和税务等基础配置我就不说了,不明白的可以参考为的另外一篇文章ios内购之基础配置篇。这一篇的重点就是说一下我在项目中的具体实现,将抽象进一步具体化。

    一、增加内购项目

    在开发者账号itunesConnect--我的app中增加内购项目,如下图所示。

    增加内购项目

    细心的朋友可能发现,我这里状态中有的是已删除,有的是元数据丢失,这是怎么回事呢?这里我要和大家说一下,这里提示已删除的是因为我有的信息填错了,后来让我在这里删除了;而下面的元数据丢失是因为,在增加内购项目的时候,没有填写完全,比如screenshot我就没有填写,这里就显示了元数据丢失。这里还有一点需要提醒大家,产品ID是唯一的,假如你增加的内购项目删除了,那么这个产品ID就不能用了,你下边就是增加再多的内购项目也不能使用这个删除的产品ID了,所以填写要慎重。还要就是别忘记添加沙盒测试人员账号,不会的同样参考我上面的文章。还有就是这里的价格是根据内购的一个价格表定的,这里不支持自定义价格。


    二、代码集成

    下面我就只要说一下内购项目的代码及其逻辑。不废话,我就直接上代码了。

    JJMoneyChargeVC.m文件
    
    
    //增加头文件
    #import "StoreKit/StoreKit.h"
    
    //必要的几个属性
    @property (nonatomic, strong) SKProductsRequest *productRequest;
    @property (nonatomic, copy) NSString *productID;
    @property (nonatomic, copy) NSString *chargeMoneyNumStr;
    @property (nonatomic, copy) NSString *orderIDStr;
    
    //开启内购
    - (void)viewDidLoad
    {
        [super viewDidLoad];
        
        self.title = @"充值";
        
        self.view.backgroundColor = [UIColor whiteColor];
        
        [self setupUI];
        //开启内购
        [[SKPaymentQueue defaultQueue] addTransactionObserver:self];
        
    }
    
    //下面就是具体的方法实现了
    
    //点击手势选择要充值的金额
    - (void)tapDidTapped:(UITapGestureRecognizer *)tapGesture
    {
        switch (tapGesture.view.tag) {
                
            case JJChargeVCChargeType100:
                NSLog(@"我充值100金币");
                self.chargeMoneyNumStr = @"1";
                break;
                
            case  JJChargeVCChargeType600:
                NSLog(@"我充值600金币");
                self.chargeMoneyNumStr = @"6";
                break;
                
            case  JJChargeVCChargeType1800:
                NSLog(@"我充值1800金币");
                self.chargeMoneyNumStr = @"18";
                break;
                
            case  JJChargeVCChargeType3000:
                NSLog(@"我充值3000金币");
                self.chargeMoneyNumStr = @"30";
                break;
                
            case  JJChargeVCChargeType9800:
                NSLog(@"我充值9800金币");
                self.chargeMoneyNumStr = @"98";
                break;
                
            case  JJChargeVCChargeType19800:
                NSLog(@"我充值19800金币");
                self.chargeMoneyNumStr = @"198";
                break;
                
            default:
                break;
        }
        
        //向服务器请求生成订单号
        [self getOderNumbderRequest];
    }
    
    //请求服务器生成订单号
    -(void)getOderNumbderRequest
    {
        //先检查网络
        
        if (self.chargeMoneyNumStr.length == 0) {
            return;
        }
        NSMutableDictionary *paramatersDictM = [NSMutableDictionary dictionary];
        [paramatersDictM setObject:@"1"   forKey:@"chargeType"];
        [paramatersDictM setObject:self.chargeMoneyNumStr forKey:@"totalAmount"];
        
        [[JJNetWorkManager manager] requestByPostNetworkWithPayUrl:kappleInnerPharchase parameters:paramatersDictM success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
            NSLog(@"responseObject---%@",responseObject);
            if ([[responseObject objectForKey:@"code"] integerValue] == 0) {
                NSDictionary *dataDict = [responseObject objectForKey:@"data"];
                self.orderIDStr = [dataDict objectForKey:@"orderNo"];
                
                if ([self.chargeMoneyNumStr isEqualToString:@"1"]) {
                    self.productID = @"这里是添加的内购项目产品ID";
                }
                
                else if([self.chargeMoneyNumStr isEqualToString:@"6"]){
                    self.productID = @"这里是添加的内购项目产品ID";
                }
                
                else if([self.chargeMoneyNumStr isEqualToString:@"18"]){
                    self.productID = @"这里是添加的内购项目产品ID";
                    
                }
                
                else if([self.chargeMoneyNumStr isEqualToString:@"30"]){
                    self.productID = @"这里是添加的内购项目产品ID";
                    
                }
                
                else if([self.chargeMoneyNumStr isEqualToString:@"98"]){
                    self.productID = @"这里是添加的内购项目产品ID";
                    
                }
                
                else if([self.chargeMoneyNumStr isEqualToString:@"198"]){
                    self.productID = @"这里是添加的内购项目产品ID";
                }
                
                if (self.productID && self.chargeMoneyNumStr) {
                      //根据产品信息发起请求,去苹果服务器请求商品
                    [self beginRequestWithProductID:self.productID];
                    }
                else {
                    NSLog(@"不允许程序内付费,必须走内购");
                }
            }
        } error:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
             NSLog(@"error---%@",error);
        }];
    }
    
    //根据产品信息发起请求,去苹果服务器请求商品
    - (void)beginRequestWithProductID:(NSString *)productID
    {
        NSArray *productArr = [[NSArray alloc] initWithObjects:productID, nil];
        NSSet *productSet = [NSSet setWithArray:productArr];
        self.productRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:productSet];;
        self.productRequest.delegate = self;
        [self.productRequest start];
    }
    
    //下面就是走请求的代理方法
    #pragma mark - SKProductsRequestDelegate
    
    //当请求到可卖商品的结果会执行该方法
    - (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
    {
        NSArray *productArr = response.products;
        
        if (productArr.count == 0) {
            NSLog(@"购买失败");
            return;
        }
        
        SKProduct *productInfo;
        for (SKProduct *product in productArr) {
            
            NSLog(@"商品描述 %@", [product description]);
            NSLog(@"商品标题 %@", [product localizedTitle]);
            NSLog(@"商品本地化描述 %@", [product localizedDescription]);
            NSLog(@"商品价格 %@", [product price]);
            NSLog(@"商品ID %@", [product productIdentifier]);
            
            if ([product.productIdentifier isEqualToString:self.productID]) {
                productInfo = product;
            }
        }
        
        //发送购买请求
        if (productInfo) {
            SKPayment *payment = [SKPayment paymentWithProduct:productInfo];
            [[SKPaymentQueue defaultQueue] addPayment:payment];
        }
    
    }
    
    //支付失败
    - (void)request:(SKRequest *)request didFailWithError:(NSError *)error
    {
        NSLog(@"%@---error",error);
    
    }
    
    //支付后的反馈信息
    - (void)requestDidFinish:(SKRequest *)request
    {
        //这里可以取消提示框
    }
    
    //下面就是查询购买结果
    #pragma mark - SKPaymentTransactionObserver
    
    //监听购买结果
    - (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray<SKPaymentTransaction *> *)transactions
    {
        for (SKPaymentTransaction *transaction in transactions) {
            switch (transaction.transactionState) {
                    
                case SKPaymentTransactionStatePurchased:
                    NSLog(@"可以请求购买了");
                    [self completeTransactionWithTransaction:transaction];
                    break;
                    
                case SKPaymentTransactionStatePurchasing:
                    NSLog(@"商品正在购买中。。。");
                    break;
                    
                case SKPaymentTransactionStateRestored:
                    NSLog(@"已经购买过商品");
                    [self restoreTransaction:transaction];
                    break;
                    
                case SKPaymentTransactionStateFailed:
                    NSLog(@"购买失败");
                    [self failedTransaction:transaction];
                    break;
                    
                default:
                    break;
            }
        }
    
    }
    
    //完成购买
    - (void)completeTransactionWithTransaction:(SKPaymentTransaction *)transaction
    {
        [self getPhuechaseReceipt:transaction];
        
        NSString *productIdentify = transaction.payment.productIdentifier;
        if (productIdentify.length > 0) {
            //向自己的服务器请求验证,增加金币
          [self requestPurchaseViaServerWithReceipt:self.receiptStr];
        }
        [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
    }
    
    //服务器端验证金币,成功后服务器则给予用户虚拟物
    - (void)requestPurchaseViaServerWithReceipt:(NSString *)storeReceipt
    {
        NSMutableDictionary *mutableDictM = [NSMutableDictionary dictionary];
        [mutableDictM setObject:self.orderIDStr?:@"" forKey:@"orderNo"];
        [mutableDictM setObject:storeReceipt?:@"" forKey:@"receipt"];
        
        [[JJNetWorkManager manager] requestByPostNetworkWithPayUrl:kappleInnerPharchaseToMyServer parameters:mutableDictM success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
            NSLog(@"responseObject---%@",responseObject);
            if ([[responseObject objectForKey:@"code"] integerValue] == 0) {
                NSDictionary *dataDict = [responseObject objectForKey:@"data"];
                self.accountCashNumLabel.text = [NSString stringWithFormat:@"%@",[dataDict objectForKey:@"userCoin"]];
            }
        } error:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
            
            NSLog(@"error--%@",error);
        }];
    }
    
    //已经购买过改商品
    - (void)restoreTransaction:(SKPaymentTransaction *)transaction
    {
        NSString * productIdentifier = transaction.payment.productIdentifier;
        if ([productIdentifier length] > 0) {
            // 向自己的服务器验证购买凭证,成功后服务器则给予用户虚拟物
            //post请求传给服务器
            [self  requestPurchaseViaServerWithReceipt:self.receiptStr];
        }
        [[SKPaymentQueue defaultQueue] finishTransaction: transaction];
    
    }
    
    //购买失败
    - (void)failedTransaction:(SKPaymentTransaction *)transaction
    {
        if(transaction.error.code != SKErrorPaymentCancelled) {
            NSLog(@"购买失败");
            [MBProgressHUD hideHUDForView:self.view animated:YES];
            [self showNotice:@"购买失败"];
        }
        else {
            NSLog(@"用户取消交易");
            [MBProgressHUD hideHUDForView:self.view animated:YES];
            [self showNotice:@"交易已取消"];
        }
        [[SKPaymentQueue defaultQueue] finishTransaction: transaction];
    }
    
    //获取购买凭证
    -(void)getPhuechaseReceipt:(SKPaymentTransaction *)transaction
    {
        //从沙盒中获取交易凭证并且拼接成请求体数据
        
        NSURL *receiptUrl = [[NSBundle mainBundle] appStoreReceiptURL];
        NSData *receiptData = [NSData dataWithContentsOfURL:receiptUrl];
        self.receiptStr = [receiptData base64EncodedStringWithOptions:0];
    }
    
    

    三、实现效果

    ios内购的实现效果如下图所示。

    确认购买 已购买 购买完成

    我这里使用的是沙盒进行的测试。

    后记

      内购就写这么多了,明后天有时间我再把支付宝支付的也加上。谢谢大家,晚安哦~~~

    妈妈生日快乐!

    相关文章

      网友评论

        本文标题:iOS内购IAP(二) —— 工程实践(一)

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