原文地址:http://blog.csdn.net/xiaominghimi/article/details/6937097/
//——2012-12-11日更新 獲取"產品付費數量等於0這個問題"的原因
看到很多童鞋問到,爲什麼每次都返回數量等於0??
其實有童鞋已經找到原因了,原因是你在 ItunesConnect 裏的 “Contracts, Tax, and Banking ”沒有設置賬戶信息。
這裏也是由於Himi疏忽的原因沒有說明,這裏先給童鞋們帶來的麻煩,致以歉意。
//——2012-6-25日更新iap恢復
看到很多童鞋說讓Himi講解如何恢復iap產品,其實博文已經給出了。這裏再詳細說下:
首先向AppStore請求恢復交易:
1
|
[[SKPaymentQueue
defaultQueue] restoreCompletedTransactions]; |
然後當用戶輸入正確的appStore賬號密碼後,進入
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions//交易結果
進入上面函數中的
1
2
3
4
5
6
|
case
SKPaymentTransactionStateRestored: //恢復 { [self
restoreTransaction:transaction]; } break ; |
然後我們再以下重寫函數中處理即可!
- (void) restoreTransaction: (SKPaymentTransaction *)transaction
//——-
終於在11月公司的遊戲即將上線了,那麼對於iOS遊戲來說當今都是內置道具收費屬於主流,那麼我們的遊戲也是內置收費,所以Himi這裏分享給大家關於內置應用收費以及申請測試賬號進行測試購買的經驗;
在應用內嵌入付費代碼這一快Himi可以直接將代碼分享給大家,所以我們來說一些主要流程,畢竟沒有接觸過這一塊的童鞋肯定相當頭疼 =。 =
OK,步入整體,如果你想在iOS裏內嵌收費,那麼分爲以下幾步:
【提示:以下創建App部分內容,你不用非要等項目能打包了纔開始做,可以隨時並且隨便的創建個測試項目即可,因爲嵌入付費並不要求上傳App的ipa包的!!】
第一步:你需要在iTunesConnect中創建個新的App,然後爲這個App設置一些產品(付費道具)等;
OK,這裏Himi稍微解釋下,iTunesConnect是蘋果提供的一個平臺,主要提供AP發佈和管理App的,最重要的功能是創建管理項目信息,項目付費產品(道具)管理、付費的測試賬號、提交App等等,這裏就簡單介紹這麼多,關於產品一詞在此我們可以理解成遊戲道具即可;在蘋果看來所有付費都屬於產品 =。 =千萬不要糾結字眼哦~
OK,打開iTunesConnect網站:https://itunesconnect.apple.com/WebObjects/iTunesConnect.woa (注意:企業級的用戶必須使用公司主開發者賬號登陸纔可!)
成功登陸後的頁面如下:
這裏大概說下重要的一些項:
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
HelloWorldLayer.m
- //
- // 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的童鞋們我想此篇將成爲你必須收藏的一篇哦~嘿嘿!