Himi 原创, 欢迎转载,转载请在明显处注明! 谢谢。css
原文地址:http://blog.csdn.net/xiaominghimi/article/details/6937097node
终于在11月公司的游戏即将上线了,那么对于iOS游戏来讲当今都是内置道具收费属于主流,那么咱们的游戏也是内置收费,因此Himi这里分享给你们关于内置应用收费以及申请测试帐号进行测试购买的经验;网络
在应用内嵌入付费代码这一快Himi能够直接将代码分享给你们,因此咱们来讲一些主要流程,毕竟没有接触过这一块的童鞋确定至关头疼 =。 =app
OK,步入总体,若是你想在iOS里内嵌收费,那么分为如下几步:框架
【提示:如下建立App部份内容,你不用非要等项目能打包了才开始作,能够随时而且随便的建立个测试项目便可,由于嵌入付费并不要求上传App的ipa包的!!】 ide
第一步:你须要在iTunesConnect中建立个新的App,而后为这个App设置一些产品(付费道具)等;测试
OK,这里Himi稍微解释下,iTunesConnect是苹果提供的一个平台,主要提供AP发布和管理App的,最重要的功能是建立管理项目信息,项目付费产品(道具)管理、付费的测试帐号、提交App等等,这里就简单介绍这么多,关于产品一词在此咱们能够理解成游戏道具便可;在苹果看来全部付费都属于产品 =。 =千万不要纠结字眼哦~网站
OK,打开iTunesConnect网站:https://itunesconnect.apple.com/WebObjects/iTunesConnect.woa (注意:企业级的用户必须使用公司主开发者帐号登录才可!)this
成功登录后的页面以下:spa
这里大概说下重要的一些项:
Contracts, Tax, and Banking : 管理银行帐号、联系人以及税等等;这里要根据提示完成对应的信息填写!必定要详细填写喔~
Manage Users :管理用户的,好比主帐号以及测试付费的(测试App)帐号;
Manage Your Applictions:管理应用程序的,你全部发布的应用和每一个应用的状态都在这里面;
下面咱们新建一个App项目,你们放心,咱们这里建立的是不会直接提交给App审核的,因此放心建立,只要控制好App的状态不要是待审核状态便可,不过即便你不当心将项目提交了,也没事,直接更改App状态便可了;
选择Manage Your Applictions选项,而后新建一个项目:【Add New App】,根据提示来填写吧,这里就不细致说明了~
建立好一个App以后,在点击Manage Your Applictions后的界面应该以下:
这里你将看到本身建立的App,点击你建立的App项目,这里Himi建立的项目名字叫”ProjectForBuyTest“,点击你的App进入以下界面:
(注意:这里的Bundle ID必定要跟你的项目中的info.plist中的Bundle ID保证一致!!!!)
这里能够管理你的项目的信息、状态、是否嵌入GameCenter等等选项,那么本章咱们重点介绍如何使用IAp沙盒测试程序内付费,因此这里咱们点击右上角的”Manage In-App Purchases“选项进入建立产品(游戏道具)界面以下:
上图中的下方看到Himi建立过的四个产品(道具)了,你能够点击”Create New“选项新建一个产品(付费道具),点击新建以下界面:
上图中Himi没有截图出全部的选项,这里大概介绍下,这个界面是选择你的消费道具的种类,种类说明以下:
类型选择有四种选择:
1.Consumable(消耗品): 每次下载都须要付费;
2.Non-consumable(非消耗品): 仅需付费一次;
3.Auto-Renewable Subscriptions:自动订阅;
4.Free Subscription:免费订阅
最下方是你沙盒测试的截图,暂且无论便可;
这里Himi选择Consumable选项,好比不少游戏都是购买金币啦这样子就能够选择这个;而后出现以下界面:
Reference Name: 付费产品(道具的)参考名称
Product ID(产品ID): 你产品的惟一id。一般格式是 com.xx.yy,但它能够是任何形式,不要求以程序的App ID做为前缀。
Add Language: 添加产品名称与描述语言;
Price Tier:选择价格,这里你选择价格后,会出现如上图最下方的价格对照表
Screenshot(截屏): 展现你产品的截屏。(这个直接无视,测试App务必要管这个的)
Product ID(产品ID)能够建立多个,好比我想游戏中分为0.99$ 、1.99$等道具那就建立对应多个产品ID!
咱们填写好了”Reference Name“与”Product ID“以及”Price Tier“后,点击”Add Language“选项而后出现以下界面:
上图中的选项:
Language:语言
Displayed Name(显示名称): 用户看到的产品名称。
Description(描述): 对产品进行描述。
Ok,一路 Save保存回到”Manage In-App Purchases“界面中会看到咱们新建的产品(道具)以下:
你们能够看到新建的产品(道具)ID:这里Himi建立的产品ID是com.himi.wahaha ,这里要记住这个产品ID哦~
第二步:申请测试帐号,利用沙盒测试模拟AppStore购买道具流程!
回到itunesconnect主页中,选择“Manage Users”而后选择“Test User”,而后出现的界面以下图:
这里Himi已经建立了两个测试帐号了,点击界面中的 “Add New User”进行建立便可;记住帐号和密码哈,记不住就删掉从新建 娃哈哈~(切记:不能用于真正的AppStore中使用此帐号,不只不能用,并且一旦AppStore发现后果你懂得~)
第三步:在项目中申请购买产品代码以及监听;
这里关于购买的代码部分呢,我都有备注的,Himi这里就不详细讲解了,Himi只是在代码后介绍几点值得注意的地方:
这里Himi是新建的一个Cocos2d的项目,而后给出HelloWorldLayer.h以及HelloWorldLayer.m的所有代码,全部购买代码也全在里面也对应有Himi的注释!
HelloWorldLayer.h
// // HelloWorldLayer.h // buytest // // Created by 华明 李 on 11-10-29. // Copyright Himi 2011年. All rights reserved. // // When you import this file, you import all the cocos2d classes #import "cocos2d.h" #import <UIKit/UIKit.h> #import <StoreKit/StoreKit.h> enum{ IAP0p99=10, IAP1p99, IAP4p99, IAP9p99, IAP24p99, }buyCoinsTag; @interface HelloWorldLayer : CCLayer<SKProductsRequestDelegate,SKPaymentTransactionObserver> { int buyType; } +(CCScene *) scene; - (void) requestProUpgradeProductData; -(void)RequestProductData; -(bool)CanMakePay; -(void)buy:(int)type; - (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions; -(void) PurchasedTransaction: (SKPaymentTransaction *)transaction; - (void) completeTransaction: (SKPaymentTransaction *)transaction; - (void) failedTransaction: (SKPaymentTransaction *)transaction; -(void) paymentQueueRestoreCompletedTransactionsFinished: (SKPaymentTransaction *)transaction; -(void) paymentQueue:(SKPaymentQueue *) paymentQueue restoreCompletedTransactionsFailedWithError:(NSError *)error; - (void) restoreTransaction: (SKPaymentTransaction *)transaction; -(void)provideContent:(NSString *)product; -(void)recordTransaction:(NSString *)product; @end
// // IapLayer.m // // Created by Himi on 11-5-25. // Copyright 2011年 李华明 . All rights reserved. // #import "HelloWorldLayer.h" #define ProductID_IAP0p99 @"com.buytest.one"//$0.99 #define ProductID_IAP1p99 @"com.buytest.two" //$1.99 #define ProductID_IAP4p99 @"com.buytest.three" //$4.99 #define ProductID_IAP9p99 @"com.buytest.four" //$19.99 #define ProductID_IAP24p99 @"com.buytest.five" //$24.99 @implementation HelloWorldLayer +(CCScene *) scene { CCScene *scene = [CCScene node]; HelloWorldLayer *layer = [HelloWorldLayer node]; [scene addChild: layer]; return scene; } -(id)init { if ((self = [super init])) { CGSize size = [[CCDirector sharedDirector] winSize]; CCSprite *iap_bg = [CCSprite spriteWithFile:@"Icon.png"]; [iap_bg setPosition:ccp(size.width/2,size.height/2)]; [self addChild:iap_bg z:0]; //--------------------- //----监听购买结果 [[SKPaymentQueue defaultQueue] addTransactionObserver:self]; //申请购买 /* enum{ IAP0p99=10, IAP1p99, IAP4p99, IAP9p99, IAP24p99, }buyCoinsTag; */ [self buy:IAP24p99]; } return self; } -(void)buy:(int)type { buyType = type; if ([SKPaymentQueue canMakePayments]) { //[[SKPaymentQueue defaultQueue] restoreCompletedTransactions]; [self RequestProductData]; CCLOG(@"容许程序内付费购买"); } else { CCLOG(@"不容许程序内付费购买"); UIAlertView *alerView = [[UIAlertView alloc] initWithTitle:@"Alert" message:@"You can‘t purchase in app store(Himi说你没容许应用程序内购买)" delegate:nil cancelButtonTitle:NSLocalizedString(@"Close(关闭)",nil) otherButtonTitles:nil]; [alerView show]; [alerView release]; } } -(bool)CanMakePay { return [SKPaymentQueue canMakePayments]; } -(void)RequestProductData { CCLOG(@"---------请求对应的产品信息------------"); NSArray *product = nil; switch (buyType) { case IAP0p99: product=[[NSArray alloc] initWithObjects:ProductID_IAP0p99,nil]; break; case IAP1p99: product=[[NSArray alloc] initWithObjects:ProductID_IAP1p99,nil]; break; case IAP4p99: product=[[NSArray alloc] initWithObjects:ProductID_IAP4p99,nil]; break; case IAP9p99: product=[[NSArray alloc] initWithObjects:ProductID_IAP9p99,nil]; break; case IAP24p99: product=[[NSArray alloc] initWithObjects:ProductID_IAP24p99,nil]; break; default: break; } NSSet *nsset = [NSSet setWithArray:product]; SKProductsRequest *request=[[SKProductsRequest alloc] initWithProductIdentifiers: nsset]; request.delegate=self; [request start]; [product release]; } //<SKProductsRequestDelegate> 请求协议 //收到的产品信息 - (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response{ NSLog(@"-----------收到产品反馈信息--------------"); NSArray *myProduct = response.products; NSLog(@"产品Product ID:%@",response.invalidProductIdentifiers); NSLog(@"产品付费数量: %d", [myProduct count]); // populate UI for(SKProduct *product in myProduct){ NSLog(@"product info"); NSLog(@"SKProduct 描述信息%@", [product description]); NSLog(@"产品标题 %@" , product.localizedTitle); NSLog(@"产品描述信息: %@" , product.localizedDescription); NSLog(@"价格: %@" , product.price); NSLog(@"Product id: %@" , product.productIdentifier); } SKPayment *payment = nil; switch (buyType) { case IAP0p99: payment = [SKPayment paymentWithProductIdentifier:ProductID_IAP0p99]; //支付$0.99 break; case IAP1p99: payment = [SKPayment paymentWithProductIdentifier:ProductID_IAP1p99]; //支付$1.99 break; case IAP4p99: payment = [SKPayment paymentWithProductIdentifier:ProductID_IAP4p99]; //支付$9.99 break; case IAP9p99: payment = [SKPayment paymentWithProductIdentifier:ProductID_IAP9p99]; //支付$19.99 break; case IAP24p99: payment = [SKPayment paymentWithProductIdentifier:ProductID_IAP24p99]; //支付$29.99 break; default: break; } CCLOG(@"---------发送购买请求------------"); [[SKPaymentQueue defaultQueue] addPayment:payment]; [request autorelease]; } - (void)requestProUpgradeProductData { CCLOG(@"------请求升级数据---------"); NSSet *productIdentifiers = [NSSet setWithObject:@"com.productid"]; SKProductsRequest* productsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:productIdentifiers]; productsRequest.delegate = self; [productsRequest start]; } //弹出错误信息 - (void)request:(SKRequest *)request didFailWithError:(NSError *)error{ CCLOG(@"-------弹出错误信息----------"); UIAlertView *alerView = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Alert",NULL) message:[error localizedDescription] delegate:nil cancelButtonTitle:NSLocalizedString(@"Close",nil) otherButtonTitles:nil]; [alerView show]; [alerView release]; } -(void) requestDidFinish:(SKRequest *)request { NSLog(@"----------反馈信息结束--------------"); } -(void) PurchasedTransaction: (SKPaymentTransaction *)transaction{ CCLOG(@"-----PurchasedTransaction----"); NSArray *transactions =[[NSArray alloc] initWithObjects:transaction, nil]; [self paymentQueue:[SKPaymentQueue defaultQueue] updatedTransactions:transactions]; [transactions release]; } //<SKPaymentTransactionObserver> 千万不要忘记绑定,代码以下: //----监听购买结果 //[[SKPaymentQueue defaultQueue] addTransactionObserver:self]; - (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions//交易结果 { CCLOG(@"-----paymentQueue--------"); for (SKPaymentTransaction *transaction in transactions) { switch (transaction.transactionState) { case SKPaymentTransactionStatePurchased://交易完成 [self completeTransaction:transaction]; CCLOG(@"-----交易完成 --------"); CCLOG(@"不容许程序内付费购买"); UIAlertView *alerView = [[UIAlertView alloc] initWithTitle:@"Alert" message:@"Himi说你购买成功啦~娃哈哈" delegate:nil cancelButtonTitle:NSLocalizedString(@"Close(关闭)",nil) otherButtonTitles:nil]; [alerView show]; [alerView release]; break; case SKPaymentTransactionStateFailed://交易失败 [self failedTransaction:transaction]; CCLOG(@"-----交易失败 --------"); UIAlertView *alerView2 = [[UIAlertView alloc] initWithTitle:@"Alert" message:@"Himi说你购买失败,请从新尝试购买~" delegate:nil cancelButtonTitle:NSLocalizedString(@"Close(关闭)",nil) otherButtonTitles:nil]; [alerView2 show]; [alerView2 release]; break; case SKPaymentTransactionStateRestored://已经购买过该商品 [self restoreTransaction:transaction]; CCLOG(@"-----已经购买过该商品 --------"); case SKPaymentTransactionStatePurchasing: //商品添加进列表 CCLOG(@"-----商品添加进列表 --------"); break; default: break; } } } - (void) completeTransaction: (SKPaymentTransaction *)transaction { CCLOG(@"-----completeTransaction--------"); // Your application should implement these two methods. NSString *product = transaction.payment.productIdentifier; if ([product length] > 0) { NSArray *tt = [product componentsSeparatedByString:@"."]; NSString *bookid = [tt lastObject]; if ([bookid length] > 0) { [self recordTransaction:bookid]; [self provideContent:bookid]; } } // Remove the transaction from the payment queue. [[SKPaymentQueue defaultQueue] finishTransaction: transaction]; } //记录交易 -(void)recordTransaction:(NSString *)product{ CCLOG(@"-----记录交易--------"); } //处理下载内容 -(void)provideContent:(NSString *)product{ CCLOG(@"-----下载--------"); } - (void) failedTransaction: (SKPaymentTransaction *)transaction{ NSLog(@"失败"); if (transaction.error.code != SKErrorPaymentCancelled) { } [[SKPaymentQueue defaultQueue] finishTransaction: transaction]; } -(void) paymentQueueRestoreCompletedTransactionsFinished: (SKPaymentTransaction *)transaction{ } - (void) restoreTransaction: (SKPaymentTransaction *)transaction { NSLog(@" 交易恢复处理"); } -(void) paymentQueue:(SKPaymentQueue *) paymentQueue restoreCompletedTransactionsFailedWithError:(NSError *)error{ CCLOG(@"-------paymentQueue----"); } #pragma mark connection delegate - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { NSLog(@"%@", [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease]); } - (void)connectionDidFinishLoading:(NSURLConnection *)connection{ } - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{ switch([(NSHTTPURLResponse *)response statusCode]) { case 200: case 206: break; case 304: break; case 400: break; case 404: break; case 416: break; case 403: break; case 401: case 500: break; default: break; } } - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error { NSLog(@"test"); } -(void)dealloc { [[SKPaymentQueue defaultQueue] removeTransactionObserver:self];//解除监听 [super dealloc]; } @end
代码注释的至关清楚了,没有什么可解释的,这里说几点值得注意的地方:
1.添加对应对应代码时不要忘记,添加框架 StoreKit.framework,如何添加框架请看个人博文【iOS-Cocos2d游戏开发之十四】音频/音效/视频播放(利用Cocos2D-iPhone-Extensions嵌入Cocos2d进行视频播放!)!
2. 越狱机器没法沙盒测试!模拟器的话,Himi用4.3模拟器不能够,由于提示没有开启程序内付费- -(我都没看到模拟器有store的选项,so~);可是使用iOS5的模拟器能够测试沙盒,可是执行的顺序会有些问题,可是还没真机的童鞋可使用,建议一切以真机实测为准
3. 千万不要忘记在iTunesConnect中建立App Bundle ID必定要跟你的项目中的info.plist中的Bundle ID保证一致!!!!
4. 以上代码中你须要修改的就是我在HelloWorldLayer.m类中的宏定义的Product ID(产品ID),例如Himi刚才新建了一个产品ID是“com.himi.wahaha"
而后我运行项目截图以下以及运行控制台打印的信息以下:
点击Buy以后运行截图以及打印信息:
输入测试帐号密码后以及打印信息:
这里Himi最后一张截图是没有购买成功,这里Himi是故意截图出来的,缘由就是想告诉童鞋们:
若是你的产品信息可以正常获得,可是始终没法成功的话,不要着急,由于你的产品要进入iTunes Connect,而且Apple准备好沙箱环境须要一些时间。Himi以前遇到过,而后在过了段时间后我没有修改任何一行代码,但产品ID变为有效并能成功购买。=。 =郁闷ing~~ 其实要使产品发布到Apple的网络系统是须要一段时间的,so~这里别太着急!
越狱机器没法正常测试沙盒的喔~
顺便提示一下:Bundle ID 尽量与开发者证书的app ID 一致。
好了,写了这么多了,咳咳、Himi继续忙了,作iOS的童鞋们我想此篇将成为你必须收藏的一篇哦~嘿嘿!