In App Purchase实现简介

In App Purchase(程序内支付),简称IAP,开发人员可以通过在程序中添加IAP利用自己的程序实现赢利。

虽然Apple官方有大量文档介绍IAP相关知识,但是实际运用中总是不可避免会出现一些错误,远不像文档上介绍的那么顺利。

下面是对实际项目中IAP运用的一些总结和介绍:

一,前期准备

    在开始动手之前,需要先根据项目要求,确定合适的商品支付类型,了解相应的支付处理流程,以决定程序的构架。

    建议参考文档:In App Purchase(Store Kit)

    相关链接:[WWW] http://wenku.baidu.com/view/71ba9c1eb7360b4c2e3f6455.html

    官方定义的支付类型,主要有以下2种:

    内置产品类型

        使用这种模型,需要交付的产品已经在程序内部。

        这种方式通常用在一些被锁定的功能上。也可以用来交付在程序束(AppBundle)中的内容。 该方式的一个重要的优点是你可以及时的给客户交付产品,大多数的内置产品应为非消耗性商品。

    服务器类型 使用这终方式,要提供另外的服务器将产品发送给程序。

        服务器交付适用于订阅、内容类商品和服务,因为商品可以作为数据发送,而不需改动程序束。

二,实现流程

    在程序中实现IAP的主要流程如下:

    创建唯一的App ID

    生成及安装新的provisioning profile文件

    在Xcode中更新 bundle ID 及 code signing profile

    如果还没做的话,请在iTunes Connect中提交有关你程序的 metadata

    如果还没做的话,请在iTunes Connect中提交你程序的二进制码

    为IAP添加新产品,取得产品的Product ID(产品ID)

    等待Apple处理产品相关信息和测试环境

    以上1~5、7项不作多余说明,第6项需注意根据项目需求选择合适的产品类型,主要有以下3种:

        Non-consumable(非消耗品): 仅需付费一次 (例如你希望将出现从免费版升级为专业版)

        Consumable(消耗品): 每次下载都需要付费

        Subscription(预订): 循环消费,主要有auto-renewable-subscription(自动订阅)和non-renewable-subscription(非自动订阅)两种,在iOS6开始又追加了一种free-subscriptions(免费订阅)。

        注意:non-consumable、auto-renewable-subscription、free-subscriptions这3种商品可以采用restore的支付操作。


三,实装代码

    IAP功能的实装需要使用StoreKit framework,所以请先在framework中追加。

    另,StoreKit无法在模拟器上工作。模拟器上只会收到如下警告信息:WARNING: SKPaymentQueue does not work in the simulator

    添加StoreObserver类,用于处理返回信息

        做成TestStoreObserverDelegate.h文件,定义以下2个回调函数:

            // 支付成功 - (void) didCompleteTransaction: (SKPaymentTransaction *)transaction;

            // 支付失败 - (void) didFailedTransaction: (SKPaymentTransaction *)transaction;

        做成TestStoreObserver.h文件,声明以下3个方法:

           #import
           #import
           #import "TestStoreObserverDelegate.h"


           @interface TestStoreObserver : NSObject {
               id delegate;
           }

           @property (assign) id delegate;

           - (void) paymentQueue: (SKPaymentQueue *)queue updatedTransactions: (NSArray *)transactions;

           - (void) completeTransaction: (SKPaymentTransaction *)transaction;

           - (void) failedTransaction: (SKPaymentTransaction *)transaction;

           @end

    TestStoreObserver.m文件,实装以下3个方法:


   1            #import "TestStoreObserver.h"
   2
   3            @implementation GolfStoreObserver
   4            @synthesize delegate;
   5
   6            - (void)paymentQueue: (SKPaymentQueue *)queue updatedTransactions: (NSArray *)transactions {
   7                for (SKPaymentTransaction* transaction in transactions)  {  
   8                    switch (transaction.transactionState)  {  
   9                        case SKPaymentTransactionStatePurchased:      // 支付结束
  10                            [self completeTransaction: transaction];  
  11                            break;  
  12                 
  13                        case SKPaymentTransactionStateFailed:         // 支付失败
  14                            [self failedTransaction: transaction];  
  15                            break;  
  16                 
  17                        case SKPaymentTransactionStateRestored:
  18                            break;  
  19                 
  20                        default:  
  21                            break;  
  22                    }  
  23                }
  24            }
  25
  26            - (void)completeTransaction: (SKPaymentTransaction *)transaction
  27            {
  28                // 支付成功的回调函数
  29                if (self.delegate != nil && [self.delegate respondsToSelector: @selector(didCompleteTransaction:)]) {
  30                    [self.delegate didCompleteTransaction: transaction];
  31                }
  32            }
  33
  34            - (void)failedTransaction: (SKPaymentTransaction *)transaction
  35            {
  36                [[NSNotificationCenter defaultCenter] postNotificationName: @"faliedTransaction" object:nil];
  37                    [[SKPaymentQueue defaultQueue] finishTransaction: transaction];
  38                // 支付失败的回调函数
  39                if (self.delegate != nil && [self.delegate respondsToSelector: @selector(didFailedTransaction:)]) {
  40                    [self.delegate didFailedTransaction: transaction];
  41                }
  42            }
  43
  44            -(void) dealloc {
  45                    [super dealloc];
  46            }
  47
  48            @end

    在controller类,添加SKProductsRequestDelegate协议,支付开始的处理中,添加以下代码,用来从APPLE获取商品信息:

        request = [[SKProductsRequest alloc] initWithProductIdentifiers: [NSSet setWithObject: entity.productId]];
        request.delegate = self;
        [request start];

    在controller类,追加以下回调函数,当接收到商品信息的时候,向支付队列里添加一个支付对象:

        - (void)productsRequest: (SKProductsRequest *)request didReceiveResponse: (SKProductsResponse *)response {
            SKPayment *payment = [SKPayment paymentWithProductIdentifier: entity.productId];
            [[SKPaymentQueue defaultQueue] addPayment: payment];

        }

    另外添加- (void)request:(SKRequest *)request didFailWithError: (NSError *)error函数用于处理产品信息接收异常。

    在controller类,追加以- (void) didCompleteTransaction: (SKPaymentTransaction *)transaction函数,处理支付返回信息:

        [[SKPaymentQueue defaultQueue] finishTransaction: transaction]; // 将支付对象移出支付队列

        APPLE的支付返回信息是,JSON格式的字符串,可以直接根据其中的status的值是否为0来判断成功与否(0为成功)

        如果是内置产品类型的商品,进行到这里,再进行如下的确认处理,正常处理就已经完成了。


   1         NSString *json = [NSString stringWithFormat: @"{\"receipt-data\":\"%@\"}", [transaction.transactionReceipt base64Encoding]]; // 需要将返回结果进行base64加密处理
   2         NSString *urlsting = @“https://sandbox.itunes.apple.com/verifyReceipt”;
   3         NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL: [NSURL URLWithString: urlsting]];
   4         [urlRequest setHTTPMethod: @"POST"];
   5         [urlRequest setHTTPBody: [json dataUsingEncoding: NSUTF8StringEncoding]];
   6         NSError *error;
   7         NSURLResponse *response;
   8         NSData *result = [NSURLConnection sendSynchronousRequest: urlRequest returningResponse: &response error:&error];
   9         NSString *resultString = [[NSString alloc] initWithData: result encoding: NSUTF8StringEncoding];
  10         NSDictionary *dict = (NSDictionary*) [resultString JSONValue];
  11     
  12         //支払成功フラグ
  13         BOOL paymentSuccessFlg = NO;
  14     
  15         //支払結果を確認する
  16         if (dict != nil) {
  17             NSNumber *status = [dict objectForKey: @"status"];
  18             if ([status isEqual: [NSNumber numberWithInt: 0]] == YES) {
  19                 paymentSuccessFlg = YES;
  20             }
  21         }

    如果是服务器类型的商品,还需要进行服务器端验证,下面是准备将APPLE的支付返回信息提交到程序服务器端的处理。服务器的环境是struts2+sesear2,数据采用JSON格式。


   1 NSString *json = [NSString stringWithFormat: @"{\"receipt-data\":\"%@\"}", [transaction.transactionReceipt base64Encoding]];  // 需要将返回结果进行base64加密处理
   2 NSData *postData = [json dataUsingEncoding: NSUTF8StringEncoding];

    将postData作为参数传递个服务器端后,由服务器端把这个支付结果提交APPLE确认即可。


你可能感兴趣的:(iOS开发相关)