iOS开发苹果内购

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

2017-05-24  本文已影响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内购的实现效果如下图所示。

确认购买 已购买 购买完成

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

后记

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

妈妈生日快乐!
上一篇 下一篇

猜你喜欢

热点阅读