最近在更新版本,發(fā)現(xiàn)好多用戶來進(jìn)行應(yīng)用內(nèi)的服務(wù)退款,理由頻多,但是還不能確定用戶是否支付成功,所以看了一下蘋果內(nèi)購的官方文檔,發(fā)現(xiàn)有驗(yàn)證服務(wù)器的方法,于是就加上了楷拳。
具體內(nèi)購怎么做在這里就不說了,網(wǎng)上有詳細(xì)的講解。
首先內(nèi)購有幾種類別呢,這個一定要搞清楚,否則會遇到很多問題。在游戲中我們經(jīng)常用到的主要由分兩種:
非消耗品 (Nonconsumable)買了就有筑悴,頭銜谋逻,功能
指的是在游戲中一次性購買并擁有永久訪問權(quán)的物品或服務(wù)蘑险。非消耗品物品可以被用戶再次下載,并且能夠在用戶的所有設(shè)備上使用
消耗品 (Consumable)窄做,買了就用,用了就沒
專為支持可消耗的物品或服務(wù)設(shè)計的慰技,消耗品購買不可被再次下載椭盏,根據(jù)其特點(diǎn),消耗品不能在用戶的設(shè)備之間跨設(shè)備使用吻商,除非自定義服務(wù)在用戶的賬號之間共享這些信息庸汗。
接下來我們就開始應(yīng)用內(nèi)購,需要導(dǎo)入StoreKit框架手报。定義好的商品
#define kIAPBomb @ "airplay.10bombs"
#define kIAPBullet @"airplay.laserBullet"
1. 實(shí)例化請求時蚯舱,必須指定有效的identifiers集合改化,之所以如此處理,主要是為了確保提交的內(nèi)購商品真的通過了蘋果的審批枉昏,處于可用狀態(tài)陈肛!
2. 要想獲取到準(zhǔn)確的可用產(chǎn)品集合,需要通過代理方法實(shí)現(xiàn)
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
3. 越獄用戶無法測試內(nèi)購兄裂,但是可以購買
1@interfaceITViewController() <SKProductsRequestDelegate,SKPaymentTransactionObserver>
2{
3// 產(chǎn)品字典
4NSMutableDictionary*_productDict;
5}
1-(void)viewDidLoad
2{
3[super viewDidLoad];
4
5[self requestProducts];
6
7// 設(shè)置購買隊(duì)列的監(jiān)聽器
8[[SKPaymentQueue defaultQueue]addTransactionObserver:self];
9}
3.4.詢問蘋果的服務(wù)器能夠銷售哪些商品
#pragma mark 詢問蘋果的服務(wù)器能夠銷售哪些商品
- (void)requestProducts
{
// 能夠銷售的商品
NSSet*set=[[NSSetalloc] initWithObjects:kIAPBomb, kIAPBullet,nil];
// "異步"詢問蘋果能否銷售
SKProductsRequest*request = [[SKProductsRequestalloc] initWithProductIdentifiers:set];
request.delegate=self;
// 啟動請求
[request start];
}
3.5.獲取詢問結(jié)果句旱,成功采取操作把商品加入可售商品字典里
- (void)productsRequest:(SKProductsRequest*)request didReceiveResponse:(SKProductsResponse*)response
{
if(_productDict ==nil) {
_productDict=[NSMutableDictionarydictionaryWithCapacity:response.products.count];
}
for(SKProduct*productinresponse.products) {
// 激活了對應(yīng)的銷售操作按鈕,相當(dāng)于商店的商品上架允許銷售
NSLog(@"%@", product.productIdentifier);
if([product.productIdentifier isEqualToString:kIAPBullet]) {
_bulletButton.enabled=YES;
}
if([product.productIdentifier isEqualToString:kIAPBomb]) {
_bombButton.enabled=YES;
}
// 填充商品字典
[_productDict setObject:product forKey:product.productIdentifier];
}
}
3.6.用戶決定購買商品
1#pragma mark - 用戶決定購買商品
2- (void)buyProduct:(SKProduct*)product
3{
4// 要購買產(chǎn)品(店員給用戶開了個小票)
5SKPayment*payment =[SKPaymentpaymentWithProduct:product];
6
7//// 設(shè)置購買隊(duì)列的監(jiān)聽器
8//[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
9
10// 去收銀臺排隊(duì)晰奖,準(zhǔn)備購買(異步網(wǎng)絡(luò))
11[[SKPaymentQueuedefaultQueue] addPayment:payment];
12}
1-(IBAction)purchaseProducts
2{
3[self buyProduct:_productDict[kIAPBullet]];
4}
5
6-(IBAction)purchaseBomb:(id)sender
7{
8[self buyProduct:_productDict[kIAPBomb]];
9}
3.7.判斷購買狀態(tài)是否成功
#pragma mark - SKPaymentTransaction Observer
#pragma mark 購買隊(duì)列狀態(tài)變化
- (void)paymentQueue:(SKPaymentQueue*)queue updatedTransactions:(NSArray*)transactions
{
// 調(diào)試
for(SKPaymentTransaction*transactionintransactions) {
NSLog(@"隊(duì)列狀態(tài)變化 %@", transaction);
// 如果小票狀態(tài)是購買完成
if(SKPaymentTransactionStatePurchased==transaction.transactionState) {
NSLog(@"購買完成 %@", transaction.payment.productIdentifier);
// 更新界面或者數(shù)據(jù)妻顶,把用戶購買得商品交給用戶
// ...
// 驗(yàn)證購買憑據(jù)
[selfverifyPruchase];
// 將交易從交易隊(duì)列中刪除
[[SKPaymentQueuedefaultQueue] finishTransaction:transaction];
}elseif(SKPaymentTransactionStateRestored==transaction.transactionState) {
NSLog(@"恢復(fù)成功 %@", transaction.payment.productIdentifier);
// 更新界面或者數(shù)據(jù),把用戶購買得商品交給用戶
// ...
// 將交易從交易隊(duì)列中刪除
[[SKPaymentQueuedefaultQueue] finishTransaction:transaction];
}
}
}
3.8.給用戶提供恢復(fù)功能(因?yàn)樵诓煌O(shè)備上永久性商品可能會出現(xiàn)需要恢復(fù)購買的情況)
#pragmamark-恢復(fù)商品
-(void)restorePurchase
{
// 恢復(fù)已經(jīng)完成的所有交易.(僅限永久有效商品)
[[SKPaymentQueue defaultQueue]restoreCompletedTransactions];
}
3.9.驗(yàn)證購買(防止第三方插件漏洞)iOS7新特性
提示:雖然蘋果在iOS7提升了購買憑據(jù)的安全性伯襟,但是處于金錢考慮馏锡,購買完成后,一定要做憑據(jù)的驗(yàn)證工作蛆楞。
#pragma mark 驗(yàn)證購買憑據(jù)
- (void)verifyPruchase
{
// 驗(yàn)證憑據(jù)溯乒,獲取到蘋果返回的交易憑據(jù)
// appStoreReceiptURL iOS7.0增加的,購買交易完成后豹爹,會將憑據(jù)存放在該地址
NSURL*receiptURL =[[NSBundlemainBundle] appStoreReceiptURL];
// 從沙盒中獲取到購買憑據(jù)
NSData*receiptData =[NSDatadataWithContentsOfURL:receiptURL];
// 發(fā)送網(wǎng)絡(luò)POST請求裆悄,對購買憑據(jù)進(jìn)行驗(yàn)證
NSURL*url =[NSURLURLWithString:ITMS_SANDBOX_VERIFY_RECEIPT_URL];
// 國內(nèi)訪問蘋果服務(wù)器比較慢,timeoutInterval需要長一點(diǎn)
13NSMutableURLRequest*request = [NSMutableURLRequestrequestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicytimeoutInterval:10.0f];
request.HTTPMethod =@"POST";
// 在網(wǎng)絡(luò)中傳輸數(shù)據(jù)臂聋,大多情況下是傳輸?shù)淖址皇嵌M(jìn)制數(shù)據(jù)
/ 傳輸?shù)氖荁ASE64編碼的字符串
/**
BASE64 常用的編碼方案光稼,通常用于數(shù)據(jù)傳輸,以及加密算法的基礎(chǔ)算法孩等,傳輸過程中能夠保證數(shù)據(jù)傳輸?shù)姆€(wěn)定性
BASE64是可以編碼和解碼的
*/
NSString*encodeStr =[receiptData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];
NSString*payload = [NSStringstringWithFormat:@"{\"receipt-data\" : \"%@\"}", encodeStr];
NSData*payloadData =[payload dataUsingEncoding:NSUTF8StringEncoding];
request.HTTPBody =payloadData;
// 提交驗(yàn)證請求钟哥,并獲得官方的驗(yàn)證JSON結(jié)果
NSData*result =[NSURLConnectionsendSynchronousRequest:request returningResponse:nilerror:nil];
// 官方驗(yàn)證結(jié)果為空
if(result ==nil) {
NSLog(@"驗(yàn)證失敗");
}
NSDictionary*dict =[NSJSONSerializationJSONObjectWithData:result options:NSJSONReadingAllowFragmentserror:nil];
NSLog(@"%@", dict);
if(dict !=nil) {
// 比對字典中以下信息基本上可以保證數(shù)據(jù)安全
// bundle_id&application_version&product_id&transaction_id
NSLog(@"驗(yàn)證成功");
}
}
3.9.說說整個購買流程結(jié)構(gòu)
1.蘋果APP(商家) ——— 2.告訴蘋果Store服務(wù)器要賣的商品 ——— 3.蘋果審核完(告訴你是否可以賣)
4.用戶(買商品) ———? 5.蘋果APP(商家) ——— ?6.開發(fā)票給(用戶) ————
7.用戶(拿著發(fā)票去蘋果Store服務(wù)器付款) —— 8.付款成功(用戶在APP里獲得服務(wù)商品)
(注意:如果要模擬測試內(nèi)購,需要用真機(jī)才可以測試)