IOS?

Tags: 內置,

最近自己做了個iOS內置付費的功能,寫下心得。

工具/原料

xcode+iphone+apple開發者帳號

方法/步驟

創建APPID,就是唯一標識這個APP的identifer.

登錄開發中心,https://developer.apple.com/devcenter/ios/index.action網站好像改版了,跟網上的教程都不一致),依次點擊紅框裡的鏈接,選擇右上角的+號,創建一個唯一的ID,一般是域名的倒寫加上一些其他的東西,反正唯一就行了。這裡取com.baidu.test

IOS IAP內置付費

IOS IAP內置付費

創建測試用的空APP,(就是沒有實際的程序,只是用來測試內置付費的)

還是登錄開發中心,如上1圖,選擇iTunes connect,登入。框1進去後是你所有的APP,框2帳號,測試帳號管理,框3是銀行卡 稅率等信息,這個務必要寫完整。

IOS IAP內置付費

先說框3,你的銀行信息必須是完整的,像下圖那樣。否則你在創建產品列表時,產品的種類就可能只有免費訂閱,消耗品,非消耗品等是看不見的。

IOS IAP內置付費

框1 MYAPP。進去後頂上有個+號,就是新建APP,上面有提示,一步一步填寫就行了,有些信息是不必要的,你可以save一下,看看有沒有報錯什麼的。頂部會有一行鏈接,如圖,我只填了price和inAPP purchase。inAPP purchase就是設置你的產品列表的地方,點開後如圖,點擊create,創建一個假的商品,也可以很多個,產品的ID必須是唯一的,可以用你的APPID+產品名什麼的。這裡假設是com.baidu.test.product1

IOS IAP內置付費

框2,用來創建沙盒測試帳號,選擇下圖紅框,填入一個郵箱地址,隨便編,還有密碼,郵箱不需要驗證的。這裡假設是[email protected] 這一步做完,準備工作就做好了,然後就是編碼了。

IOS IAP內置付費

先說一下IAP的大致流程,如圖,首先你得先有一個在iTunes設置的產品列表,這樣才知道向iTunes請求什麼商品,這個列表可以硬編碼,或者放到服務器上動態獲取,然後拿著這個列表通過apple的API去請求產品,返回後顯示到界面,用戶操作發起一個購買請求,成功或失敗會有相應的回調方法,成功的時候applestore會產生一個收據,這個收據可以反饋給服務器用來向store驗證,然後就是服務器向玩家發放道具什麼的。這裡說的非常粗,詳見代碼。對於交易恢復restoreTransaction,我不是特別理解這個概念,網上找到一張圖2,有更明白的歡迎指教。

剛搜了一下,有一條:

恢復交易信息(Transactions)當transaction被處理並從隊列移除之後,正常情況下,程序就再也看不到它們了。 如果你的程序提供的是非消耗性的或是訂閱類的商品,就必須提供restore的功能,使用戶可以在其他設備上重新存儲購買信息。

是不是說,如果這個商品是非消耗品,購買完成之後,再次拿著它的ID去請求它就請求不到了??????所以才需要恢復????

IOS IAP內置付費

IOS IAP內置付費

代碼的編寫需要導入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 *[email protected]"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){//注意,[email protected]"0" 是驗證收據成功

NSLog(@"valid ok");

}

網上還說發起購買時最好先判斷一些內置購買能不能用,通過

if([SKPaymentQueue canMakePayments])

{

...//Display a store to the user

}

else

{

...//Warn the user that purchases are disabled.

}

還有就是我對於恢復交易的理解:restoreTransaction,如果你有一個商品是一次性的,玩家已經購買過,因為某種原因玩家的設備丟失了這個商品,這時候可以通過apple提供的API幫助玩家找回丟失的商品。具體流程是:

通過

[[SKPaymentQueue defaultQueue] restoreCompletedTransactions];發起恢復,

商品成功恢復會回調 paymentQueueRestoreCompletedTransactionsFinished方法,失敗會回調paymentQueue:restoreCompletedTransactionsFailedWithError:方法。

相關問題答案