zoukankan      html  css  js  c++  java
  • iOS- 给App添加内购& 验证购买iOS7新特性

    http://blog.csdn.net/tspangle/article/details/39315355

    1.内购——应用内购买                      

    我所说的内购——也可以说是应用内购买

    大家都知道通过苹果应用程序商店有三种主要赚钱的方式:
    1.直接收费(与国内大部分用户的消费习惯相悖,如果要收费,直接收高的,别收6块钱)
    2.广告(降低用户体验 应用程序名称带Lite可以添加广告)
    3.内购
    至于设计哪些卖钱?产品经理需要认真考虑和调研的。记录用户行为是可以帮助产品经理确认哪些收费!
    所以要做好游戏,一定要研究心理,要研究哲学,哈哈。
     

    2.内购的类别有哪几种呢?                    

    在游戏中我们经常用到的主要由分两种:
     
    非消耗品(Nonconsumable)买了就有,头衔,功能
    指的是在游戏中一次性购买并拥有永久访问权的物品或服务。非消耗品物品可以被用户再次下载,并且能够在用户的所有设备上使用
    消耗品(Consumable),买了就用,用了就没
    专为支持可消耗的物品或服务设计的,消耗品购买不可被再次下载,根据其特点,消耗品不能在用户的设备之间跨设备使用,除非自定义服务在用户的账号之间共享这些信息
     
     

    3.添加内购功能                             

    3.1在iTunes Connect中给自己的应用添加消耗品定义                      

    3.2在iTunes Connect中给自己的应用添加定义的商品              

    3.3要使用内购,需要导入StoreKit框架                            

     定义好的商品

    #define kIAPBomb @"airplay.10bombs"

    #define kIAPBullet @"airplay.laserBullet"

    1. 实例化请求时,必须指定有效的identifiers集合,之所以如此处理,主要是为了确保提交的内购商品真的通过了苹果的审批,处于可用状态!

    2. 要想获取到准确的可用产品集合,需要通过代理方法实现

    - (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response

    3. 越狱用户无法测试内购,但是可以购买

    1. @interface ITViewController () <SKProductsRequestDelegate, SKPaymentTransactionObserver>  
    2. {  
    3.     // 产品字典  
    4.     NSMutableDictionary *_productDict;  
    5. }  

    1. - (void)viewDidLoad  
    2. {  
    3.     [super viewDidLoad];  
    4.       
    5.     [self requestProducts];  
    6.       
    7.     // 设置购买队列的监听器  
    8.     [[SKPaymentQueue defaultQueue] addTransactionObserver:self];  
    9. }  

    3.4.询问苹果的服务器能够销售哪些商品                        

    1. #pragma mark 询问苹果的服务器能够销售哪些商品  
    2. - (void)requestProducts  
    3. {  
    4.     // 能够销售的商品  
    5.     NSSet *set = [[NSSet alloc] initWithObjects:kIAPBomb, kIAPBullet, nil nil];  
    6.       
    7.     // "异步"询问苹果能否销售  
    8.     SKProductsRequest *request = [[SKProductsRequest alloc] initWithProductIdentifiers:set];  
    9.       
    10.     request.delegate = self;  
    11.       
    12.     // 启动请求  
    13.     [request start];  
    14. }  

    3.5.获取询问结果,成功采取操作把商品加入可售商品字典里                   

    1. - (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response  
    2. {  
    3.     if (_productDict == nil) {  
    4.         _productDict = [NSMutableDictionary dictionaryWithCapacity:response.products.count];  
    5.     }  
    6.       
    7.     for (SKProduct *product in response.products) {  
    8.         // 激活了对应的销售操作按钮,相当于商店的商品上架允许销售  
    9.         NSLog(@"%@", product.productIdentifier);  
    10.           
    11.         if ([product.productIdentifier isEqualToString:kIAPBullet]) {  
    12.             _bulletButton.enabled = YES;  
    13.         }  
    14.           
    15.         if ([product.productIdentifier isEqualToString:kIAPBomb]) {  
    16.             _bombButton.enabled = YES;  
    17.         }  
    18.           
    19.         // 填充商品字典  
    20.         [_productDict setObject:product forKey:product.productIdentifier];  
    21.     }  
    22. }  

    3.6.用户决定购买商品                                      

    1. #pragma mark - 用户决定购买商品  
    2. - (void)buyProduct:(SKProduct *)product  
    3. {  
    4.     // 要购买产品(店员给用户开了个小票)  
    5.     SKPayment *payment = [SKPayment paymentWithProduct:product];  
    6.       
    7. //    // 设置购买队列的监听器  
    8. //    [[SKPaymentQueue defaultQueue] addTransactionObserver:self];  
    9.       
    10.     // 去收银台排队,准备购买(异步网络)  
    11.     [[SKPaymentQueue defaultQueue] addPayment:payment];  
    12. }  
    1. - (IBAction)purchaseProducts  
    2. {  
    3.     [self buyProduct:_productDict[kIAPBullet]];  
    4. }  
    5.   
    6. - (IBAction)purchaseBomb:(id)sender  
    7. {  
    8.     [self buyProduct:_productDict[kIAPBomb]];  
    9. }  

    3.7.判断购买状态是否成功                                

    1. #pragma mark - SKPaymentTransaction Observer  
    2. #pragma mark 购买队列状态变化  
    3. - (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions  
    4. {  
    5.     // 调试  
    6.     for (SKPaymentTransaction *transaction in transactions) {  
    7.         NSLog(@"队列状态变化 %@", transaction);  
    8.         // 如果小票状态是购买完成  
    9.         if (SKPaymentTransactionStatePurchased == transaction.transactionState) {  
    10.             NSLog(@"购买完成 %@", transaction.payment.productIdentifier);  
    11.               
    12.             // 更新界面或者数据,把用户购买得商品交给用户  
    13.             // ...  
    14.             // 验证购买凭据  
    15.             [self verifyPruchase];  
    16.               
    17.             // 将交易从交易队列中删除  
    18.             [[SKPaymentQueue defaultQueue] finishTransaction:transaction];  
    19.         } else if (SKPaymentTransactionStateRestored == transaction.transactionState) {  
    20.             NSLog(@"恢复成功 %@", transaction.payment.productIdentifier);  
    21.   
    22.             // 更新界面或者数据,把用户购买得商品交给用户  
    23.             // ...  
    24.   
    25.             // 将交易从交易队列中删除  
    26.             [[SKPaymentQueue defaultQueue] finishTransaction:transaction];  
    27.         }  
    28.     }  
    29. }  

    3.8.给用户提供恢复功能(因为在不同设备上永久性商品可能会出现需要恢复购买的情况)    

    1. #pragma mark - 恢复商品  
    2. - (void)restorePurchase  
    3. {  
    4.     // 恢复已经完成的所有交易.(仅限永久有效商品)  
    5.     [[SKPaymentQueue defaultQueue] restoreCompletedTransactions];  
    6. }  

    3.9.验证购买(防止第三方插件漏洞)iOS7新特性                      

    提示:虽然苹果在iOS7提升了购买凭据的安全性,但是处于金钱考虑,购买完成后,一定要做凭据的验证工作。

    1. #pragma mark 验证购买凭据  
    2. - (void)verifyPruchase  
    3. {  
    4.     // 验证凭据,获取到苹果返回的交易凭据  
    5.     // appStoreReceiptURL iOS7.0增加的,购买交易完成后,会将凭据存放在该地址  
    6.     NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];  
    7.     // 从沙盒中获取到购买凭据  
    8.     NSData *receiptData = [NSData dataWithContentsOfURL:receiptURL];  
    9.       
    10.     // 发送网络POST请求,对购买凭据进行验证  
    11.     NSURL *url = [NSURL URLWithString:ITMS_SANDBOX_VERIFY_RECEIPT_URL];  
    12.     // 国内访问苹果服务器比较慢,timeoutInterval需要长一点  
    13.     NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:10.0f];  
    14.       
    15.     request.HTTPMethod = @"POST";  
    16.       
    17.     // 在网络中传输数据,大多情况下是传输的字符串而不是二进制数据  
    18.     // 传输的是BASE64编码的字符串  
    19.     /** 
    20.      BASE64 常用的编码方案,通常用于数据传输,以及加密算法的基础算法,传输过程中能够保证数据传输的稳定性 
    21.      BASE64是可以编码和解码的 
    22.      */  
    23.     NSString *encodeStr = [receiptData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];  
    24.       
    25.     NSString *payload = [NSString stringWithFormat:@"{"receipt-data" : "%@"}", encodeStr];  
    26.     NSData *payloadData = [payload dataUsingEncoding:NSUTF8StringEncoding];  
    27.   
    28.     request.HTTPBody = payloadData;  
    29.       
    30.     // 提交验证请求,并获得官方的验证JSON结果  
    31.     NSData *result = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];  
    32.   
    33.     // 官方验证结果为空  
    34.     if (result == nil) {  
    35.         NSLog(@"验证失败");  
    36.     }  
    37.       
    38.     NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:result options:NSJSONReadingAllowFragments error:nil];  
    39.       
    40.     NSLog(@"%@", dict);  
    41.       
    42.     if (dict != nil) {  
    43.         // 比对字典中以下信息基本上可以保证数据安全  
    44.         // bundle_id&application_version&product_id&transaction_id  
    45.         NSLog(@"验证成功");  
    46.     }  
    47. }  

    3.10.说说整个购买流程结构                                    

    1.苹果APP(商家)——— 2.告诉苹果Store服务器要卖的商品 ——— 3.苹果审核完(告诉你是否可以卖)

    4.用户(买商品)——— 5.苹果APP(商家)——— 6.开发票给(用户)————

    7.用户(拿着发票去苹果Store服务器付款)——8.付款成功(用户在APP里获得服务商品)

    (注意:如果要模拟测试内购,需要用真机才可以测试)


    转自:http://www.cnblogs.com/qingche/p/3561424.html
  • 相关阅读:
    马哥Linux——第三周作业
    [laravel]phpunit
    [laravel]要点
    [laravel]请求处理
    [angularJS]ng-hide|ng-show切换
    [yii2]urlmanger
    虚拟机bridged, NAT and host-only网络区别
    [yii]Fetch data from database and create listbox in yii
    [shell test] multiple conditions
    特殊的shell变量:
  • 原文地址:https://www.cnblogs.com/itlover2013/p/4810603.html
Copyright © 2011-2022 走看看