多语言展示
当前在线:1936今日阅读:138今日分享:34

IOS IAP内置付费

最近自己做了个iOS内置付费的功能,写下心得。
工具/原料

xcode+iphone+apple开发者帐号

方法/步骤
1

创建APPID,就是唯一标识这个APP的identifer.登录开发中心,https://developer.apple.com/devcenter/ios/index.action网站好像改版了,跟网上的教程都不一致),依次点击红框里的链接,选择右上角的+号,创建一个唯一的ID,一般是域名的倒写加上一些其他的东西,反正唯一就行了。这里取com.baidu.test

2

创建测试用的空APP,(就是没有实际的程序,只是用来测试内置付费的)还是登录开发中心,如上1图,选择iTunes connect,登入。框1进去后是你所有的APP,框2帐号,测试帐号管理,框3是银行卡 税率等信息,这个务必要写完整。

3

先说框3,你的银行信息必须是完整的,像下图那样。否则你在创建产品列表时,产品的种类就可能只有免费订阅,消耗品,非消耗品等是看不见的。

4

框1 MYAPP。进去后顶上有个+号,就是新建APP,上面有提示,一步一步填写就行了,有些信息是不必要的,你可以save一下,看看有没有报错什么的。顶部会有一行链接,如图,我只填了price和inAPP purchase。inAPP purchase就是设置你的产品列表的地方,点开后如图,点击create,创建一个假的商品,也可以很多个,产品的ID必须是唯一的,可以用你的APPID+产品名什么的。这里假设是com.baidu.test.product1

5

框2,用来创建沙盒测试帐号,选择下图红框,填入一个邮箱地址,随便编,还有密码,邮箱不需要验证的。这里假设是sahetester@qq.com 这一步做完,准备工作就做好了,然后就是编码了。

6

先说一下IAP的大致流程,如图,首先你得先有一个在iTunes设置的产品列表,这样才知道向iTunes请求什么商品,这个列表可以硬编码,或者放到服务器上动态获取,然后拿着这个列表通过apple的API去请求产品,返回后显示到界面,用户操作发起一个购买请求,成功或失败会有相应的回调方法,成功的时候applestore会产生一个收据,这个收据可以反馈给服务器用来向store验证,然后就是服务器向玩家发放道具什么的。这里说的非常粗,详见代码。对于交易恢复restoreTransaction,我不是特别理解这个概念,网上找到一张图2,有更明白的欢迎指教。刚搜了一下,有一条:恢复交易信息(Transactions)当transaction被处理并从队列移除之后,正常情况下,程序就再也看不到它们了。 如果你的程序提供的是非消耗性的或是订阅类的商品,就必须提供restore的功能,使用户可以在其他设备上重新存储购买信息。是不是说,如果这个商品是非消耗品,购买完成之后,再次拿着它的ID去请求它就请求不到了??????所以才需要恢复????

7

代码的编写需要导入StoreKit.framework,需要用到它的SKPayment,SKPaymentQueue,SKPaymentTransaction,SKPaymentTransactionObserver类。

8

1.假设我们已经有了一个产品列表:NSSet *productIdentifiers = [NSSet setWithObjects:@'com.baidu.test.product1', nil];2.我们用这个列表去向商店请求商品的具体信息,这个请求通过类SKProductsRequest完成:创建SKProductsRequest对象,SKProductsRequest * _request=[[[SKProductsRequest alloc] initWithProductIdentifiers:_productIdentifiers] autorelease];创建后还不能立即请求,因为我们要回收结果,所以要实现一些的回调方法。在网上找了找,说是设置代理delegate,自己强行理解了下,这个delegate和java C#里的接口差不多,规定一套实现者必须执行的动作,我学objectC才第2天,理解的不好请指教。那么这个代理该怎么设置呢:_request.delegate = self;咋一看的晕晕的,把自己设成代理,然后看了下所在类的声明:黑体部分应该就是所谓的代理了,它里面有一些方法必须实现,这些方法在合适的时机被回调。@interface IAPHelper : NSObject { @protected    NSSet * _productIdentifiers;        NSArray * _products;    NSMutableSet * _purchasedProducts;    SKProductsRequest * _request;}然后是发送请求:[_request start];整个方法是这样的:- (void)requestProducts {        self.request = [[[SKProductsRequest alloc] initWithProductIdentifiers:_productIdentifiers] autorelease];    _request.delegate = self;//设置回调代理对象    [_request start];//请求    }回调方法:这里只实现了成功时的回调,如果请求不成功的,可以实现request:didFailWithError://请求成功的回调- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response {        NSLog(@'Received products results...');       self.products = response.products;//接收列表    self.request = nil;  //Null,释放内存    //发送消息给界面,界面要接收消息,必须得先监听才可以。    [[NSNotificationCenter defaultCenter] postNotificationName:kProductsLoadedNotification object:_products];    }

9

假设我们成功取到了产品列表,那么接下列就是要显示到界面上了。显示代码就略过了。接下来要做的就是用户操作后发出购买请求:因为产品的信息都在self.products中,用户点击后我们取出对应的产品ID,创建一个购买对象,放入队列中,关键代码如下://SKPayment对象SKPayment *payment = [SKPayment paymentWithProductIdentifier:productIdentifier]; //加载到队列中  [[SKPaymentQueue defaultQueue] addPayment:payment];剩下的事情由apple来完成,但是交易的状态还是要获取的,获取状态通过添加监视:监视最好在创建类实例,或者程序加载时就加上。[[SKPaymentQueue defaultQueue] addTransactionObserver:参数];因为IAPHelper: NSObject 实现了SKPaymentTransactionObserver代理协议(就是实现了交易状态改变时的回调方法),所以『参数』应该设置为IAPHelper的实例。具体是哪个方法呢?我只找到一个://当发生交易事务时回调该方法,该方法根据对应状态调用合适的方法- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions{    for (SKPaymentTransaction *transaction in transactions)    {        switch (transaction.transactionState)        {            case SKPaymentTransactionStatePurchased://成功完成事物                [self completeTransaction:transaction];                break;            case SKPaymentTransactionStateFailed://事物失败                [self failedTransaction:transaction];                break;            case SKPaymentTransactionStateRestored://                [self restoreTransaction:transaction];                NSLog(@'已经购买过该商品');                            default:                break;        }    }}到这里基本上就算完了。

10

还有一个收据问题,只有交易状态是成功(SKPaymentTransactionStatePurchased或者恢复(SKPaymentTransactionStateRestored)时,才会产生收据Receipt,他保存本次交易的详细内容,是transaction对象的一个属性。怎么获取呢?网上找了半天,_iOS_6_1之前的版本,保存在transaction.transactionReceipt.bytes,好像是2进制,得转码什么的,新版本通过NSBundle的一个方法appStoreReceiptURL来获取。拿到2进制的收据经过base64编码之后就是向Appstore验证交易是不是真的生效了。沙盒的验证地址是'https://sandbox.itunes.apple.com/verifyReceipt';正式的验证地址是https://buy.itunes.apple.com/verifyReceipt,代码大致像这样:NSString* receipt64 = [self encode64:(uint8_t *)transaction.transactionReceipt.bytes length:transaction.transactionReceipt.length];    NSLog(@'receipt64== %@',receipt64);        /*本地验证    NSString *URL=@'https://sandbox.itunes.apple.com/verifyReceipt';    //https://buy.itunes.apple.com/verifyReceipt    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];// autorelease];    [request setURL:[NSURL URLWithString:URL]];    [request setHTTPMethod:@'POST'];    //设置contentType    [request addValue:@'application/json' forHTTPHeaderField:@'Content-Type'];    //设置Content-Length    [request setValue:[NSString stringWithFormat:@'%d', [receipt64 length]] forHTTPHeaderField:@'Content-Length'];        NSDictionary* body = [NSDictionary dictionaryWithObjectsAndKeys:receipt64, @'receipt-data', nil];        SBJsonWriter* w = [SBJsonWriter new];    [request setHTTPBody:[[w stringWithObject:body] dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES]];        NSHTTPURLResponse *urlResponse=nil;    NSError *errorr=nil;    NSData *receivedData = [NSURLConnection sendSynchronousRequest:request                                                 returningResponse:&urlResponse                                                             error:&errorr];        //解析    NSString *results=[[NSString alloc]initWithBytes:[receivedData bytes] length:[receivedData length] encoding:NSUTF8StringEncoding];    NSLog(@'-Himi-  %@',results);    NSDictionary*dic = [results JSONValue];        if([[dic objectForKey:@'status'] intValue]==0){//注意,status=@'0' 是验证收据成功       NSLog(@'valid ok');    }

11

网上还说发起购买时最好先判断一些内置购买能不能用,通过if([SKPaymentQueue canMakePayments])  {      ...//Display a store to the user  }  else {      ...//Warn the user that purchases are disabled.  }

12

还有就是我对于恢复交易的理解:restoreTransaction,如果你有一个商品是一次性的,玩家已经购买过,因为某种原因玩家的设备丢失了这个商品,这时候可以通过apple提供的API帮助玩家找回丢失的商品。具体流程是:通过[[SKPaymentQueue defaultQueue] restoreCompletedTransactions];发起恢复,商品成功恢复会回调 paymentQueueRestoreCompletedTransactionsFinished方法,失败会回调paymentQueue:restoreCompletedTransactionsFailedWithError:方法。

推荐信息