创建APPID,就是唯一标识这个APP的identifer.登录开发中心,https://developer.apple.com/devcenter/ios/index.action网站好像改版了,跟网上的教程都不一致),依次点击红框里的链接,选择右上角的+号,创建一个唯一的ID,一般是域名的倒写加上一些其他的东西,反正唯一就行了。这里取com.baidu.test
创建测试用的空APP,(就是没有实际的程序,只是用来测试内置付费的)还是登录开发中心,如上1图,选择iTunes connect,登入。框1进去后是你所有的APP,框2帐号,测试帐号管理,框3是银行卡 税率等信息,这个务必要写完整。
先说框3,你的银行信息必须是完整的,像那样。否则你在创建产品列表时,产品的种类就可能只有免费订阅,消耗品,非消耗品等是看不见的。
框1 MYAPP。进去后顶上有个+号,就是新建APP,上面有提示,一步一步填写就行了,有些信息是不必要的,你可以save一下,看看有没有报错什么的。顶部会有一行链接,我只填了price和inAPP purchase。inAPP purchase就是设置你的产品列表的地方,点开后,点击create,创建一个假的商品,也可以很多个,产品的ID必须是唯一的,可以用你的APPID+产品名什么的。这里假设是com.baidu.test.product1
框2,用来创建沙盒测试帐号,选择红框,填入一个邮箱地址,随便编,还有密码,邮箱不需要验证的。这里假设是sahetester@qq.com 这一步做完,准备工作就做好了,然后就是编码了。
先说一下IAP的大致流程,首先你得先有一个在iTunes设置的产品列表,这样才知道向iTunes请求什么商品,这个列表可以硬编码,或者放到服务器上动态获取,然后拿着这个列表通过apple的API去请求产品,返回后显示到界面,用户操作发起一个购买请求,成功或失败会有相应的回调方法,成功的时候applestore会产生一个收据,这个收据可以反馈给服务器用来向store验证,然后就是服务器向玩家发放道具什么的。这里说的非常粗,详见代码。对于交易恢复restoreTransaction,我不是特别理解这个概念,网上找到一张图2,有更明白的欢迎指教。刚搜了一下,有一条:恢复交易信息(Transactions)当transaction被处理并从队列移除之后,正常情况下,程序就再也看不到它们了。 如果你的程序提供的是非消耗性的或是订阅类的商品,就必须提供restore的功能,使用户可以在其他设备上重新存储购买信息。是不是说,如果这个商品是非消耗品,购买完成之后,再次拿着它的ID去请求它就请求不到了??????所以才需要恢复????
代码的编写需要导入StoreKit.framework,需要用到它的SKPayment,SKPaymentQueue,SKPaymentTransaction,SKPaymentTransactionObserver类。
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]; }
假设我们成功取到了产品列表,那么接下列就是要显示到界面上了。显示代码就略过了。接下来要做的就是用户操作后发出购买请求:因为产品的信息都在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; } }}到这里基本上就算完了。
还有一个收据问题,只有交易状态是成功(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"); }
网上还说发起购买时最好先判断一些内置购买能不能用,通过if([SKPaymentQueuecanMakePayments]) { ...//Displayastoretotheuser} else{ ...//Warntheuserthatpurchasesaredisabled.}
还有就是我对于恢复交易的理解:restoreTransaction,如果你有一个商品是一次性的,玩家已经购买过,因为某种原因玩家的设备丢失了这个商品,这时候可以通过apple提供的API帮助玩家找回丢失的商品。具体流程是:通过[[SKPaymentQueue defaultQueue] restoreCompletedTransactions];发起恢复,商品成功恢复会回调paymentQueueRestoreCompletedTransactionsFinished方法,失败会回调paymentQueue:restoreCompletedTransactionsFailedWithError:方法。