內(nèi)購(gòu)是啥
App 內(nèi)購(gòu)買項(xiàng)目允許顧客通過訪問 App Store 購(gòu)買您 App 中的內(nèi)容、功能或服務(wù),并安全處理來自用戶的付款。
詳情傳送門https://help.apple.com/itunes-connect/developer/#/devb57be10e7
下面來說內(nèi)購(gòu)集成流程
1.協(xié)議
登錄蘋果開發(fā)者中心,進(jìn)入iTunes Connect,再進(jìn)入“協(xié)議病线、稅務(wù)和銀行業(yè)務(wù)”頁(yè)面,如圖
點(diǎn)擊進(jìn)入可以看到,目前共有兩個(gè)分組,三種合同送挑。(此處有坑绑莺,比如我們當(dāng)前賬號(hào)不能申請(qǐng)合同!如下圖)
Request Contracts 可以申請(qǐng)的合同惕耕;
Contracts In Effect 已經(jīng)生效的合同纺裁。
三種合同分別是
Free Applications 免費(fèi)應(yīng)用(默認(rèn)已經(jīng)生效);
Paid Applications 付費(fèi)應(yīng)用司澎,需要申請(qǐng)欺缘;
iAd App Network 廣告應(yīng)用,需要申請(qǐng)挤安。
內(nèi)購(gòu)對(duì)應(yīng)的是Paid Applications 付費(fèi)應(yīng)用谚殊,需要申請(qǐng),如圖2.(如果Request按鈕不顯示,則說明當(dāng)前賬號(hào)權(quán)限有問題)
點(diǎn)擊Request完善信息,提交就行.
2.內(nèi)購(gòu)集成
內(nèi)購(gòu)實(shí)現(xiàn)流程:
1.客戶端向Appstore請(qǐng)求購(gòu)買產(chǎn)品(假設(shè)產(chǎn)品信息已經(jīng)取得),Appstore驗(yàn)證產(chǎn)品成功后蛤铜,從用戶的Apple賬戶余額中扣費(fèi)嫩絮。
2.Appstore向客戶端返回一段receipt-data,里面記錄了本次交易的證書和簽名信息围肥。
3.客戶端向我們可以信任的服務(wù)器提供receipt-data
4.服務(wù)器對(duì)receipt-data進(jìn)行一次base64編碼
5.把編碼后的receipt-data發(fā)往itunes.appstore進(jìn)行驗(yàn)證
6.itunes.appstore返回驗(yàn)證結(jié)果給服務(wù)器
7.服務(wù)器對(duì)商品購(gòu)買狀態(tài)以及商品類型絮记,向客戶端發(fā)放相應(yīng)的道具與推送數(shù)據(jù)更新通知
注,下圖3步驟和上面流程不是一一對(duì)應(yīng)
我項(xiàng)目里面的購(gòu)買流程,加入了一點(diǎn)業(yè)務(wù)邏輯和后臺(tái)驗(yàn)證流程,有什么問題歡迎大家指出.
3.去蘋果開發(fā)者中心創(chuàng)建內(nèi)購(gòu)商品
如下圖5,點(diǎn)擊+號(hào)去創(chuàng)建內(nèi)購(gòu)商品,產(chǎn)品id最好是當(dāng)前應(yīng)用+數(shù)字,價(jià)格區(qū)間蘋果提供了一張表,商品價(jià)格只能是表上的價(jià)格,蘋果會(huì)抽取30%,商家能收到的錢是用戶充值的70%.這就造成了部分平臺(tái)區(qū)分安卓和蘋果.兩端賬號(hào)不互通,也造就了代充行業(yè),再次就不展開說了.
商品價(jià)格大于100$,提交審核的時(shí)候要說明這個(gè)金額是確認(rèn)過的,不然可能會(huì)被拒
4.代碼集成
建議單獨(dú)建一個(gè)類來處理內(nèi)購(gòu)業(yè)務(wù)
導(dǎo)入頭文件#import <StoreKit/StoreKit.h>
遵循協(xié)議<SKPaymentTransactionObserver,SKProductsRequestDelegate>
?[[SKPaymentQueue defaultQueue] addTransactionObserver:self];// 4.設(shè)置支付服務(wù)
-(void)starBuyToAppStore:(NSString *)goodsID{? ? if ([SKPaymentQueue canMakePayments]) {//5.判斷app是否允許apple支付?? ? ?? ? ? ? [self getRequestAppleProduct:goodsID];// 6.請(qǐng)求蘋果后臺(tái)商品?? ? ? ?? ? } else {//? ? ? ? NSLog(@"not");? ? }}
#pragma mark ------ 請(qǐng)求蘋果商品- (void)getRequestAppleProduct:(NSString *)goodsID{? ? self.goodsId = goodsID;//把前面?zhèn)鬟^來的商品id記錄一下,下面要用? ? // 7.這里的com.czchat.CZChat01就對(duì)應(yīng)著蘋果后臺(tái)的商品ID,他們是通過這個(gè)ID進(jìn)行聯(lián)系的虐先。? ? NSArray *product = [[NSArray alloc] initWithObjects:goodsID,nil];? ? NSSet *nsset = [NSSet setWithArray:product];?? ?? ? //SKProductsRequest參考鏈接:https://developer.apple.com/documentation/storekit/skproductsrequest? ? //SKProductsRequest 一個(gè)對(duì)象,可以從App Store檢索有關(guān)指定產(chǎn)品列表的本地化信息派敷。? ? SKProductsRequest *request = [[SKProductsRequest alloc] initWithProductIdentifiers:nsset];// 8.初始化請(qǐng)求? ? request.delegate = self;? ? [request start];// 9.開始請(qǐng)求}
// 10.接收到產(chǎn)品的返回信息,然后用返回的商品信息進(jìn)行發(fā)起購(gòu)買請(qǐng)求- (void) productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response{? ? NSArray *product = response.products;?? ?? ? if([product count] == 0){//如果服務(wù)器沒有產(chǎn)品? ? ? ? return;? ? }?? ?? ? SKProduct *requestProduct = nil;? ? for (SKProduct *pro in product) {//? ? ? ? NSLog(@"%@", [pro description]);//? ? ? ? NSLog(@"%@", [pro localizedTitle]);//? ? ? ? NSLog(@"%@", [pro localizedDescription]);//? ? ? ? NSLog(@"%@", [pro price]);//? ? ? ? NSLog(@"%@", [pro productIdentifier]);? ? ? ? // 11.如果后臺(tái)消費(fèi)條目的ID與我這里需要請(qǐng)求的一樣(用于確保訂單的正確性)? ? ? ? if([pro.productIdentifier isEqualToString:self.goodsId]){? ? ? ? ? ? requestProduct = pro;? ? ? ? }? ? }? ? // 12.發(fā)送購(gòu)買請(qǐng)求蛹批,創(chuàng)建票據(jù)? 這個(gè)時(shí)候就會(huì)有彈框了? ? SKPayment *payment = [SKPayment paymentWithProduct:requestProduct];? ? [[SKPaymentQueue defaultQueue] addPayment:payment];//將票據(jù)加入到交易隊(duì)列?? ?}
// 13.監(jiān)聽購(gòu)買結(jié)果- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transaction{? ? if (self.delegate && [self.delegate respondsToSelector:@selector(EMAppStorePay:responseAppStorePayStatusshow:error:)]) {? ? ? ? [self.delegate EMAppStorePay:self responseAppStorePayStatusshow:@{@"value":transaction} error:nil];? ? }? ? for(SKPaymentTransaction *tran in transaction){//? ? ? ? NSLog(@"%@",tran.payment.applicationUsername);? ? ? ? switch (tran.transactionState) {? ? ? ? ? ? case SKPaymentTransactionStatePurchased:{//? ? ? ? ? ? ? ? NSLog(@"交易完成");? ? ? ? ? ? ? ? // 購(gòu)買后告訴交易隊(duì)列,把這個(gè)成功的交易移除掉篮愉。? ? ? ? ? ? ? ? //走到這就說明這單交易走完了腐芍,無論成功失敗,所以要給它移出试躏。finishTransaction? ? ? ? ? ? ? ? [self completeTransaction:tran];//這兒出了問題拋異常猪勇,導(dǎo)致下面一句代碼沒執(zhí)行? ? ? ? ? ? ? ? [[SKPaymentQueue defaultQueue] finishTransaction:tran];?? ? ? ? ? ? ? ?? ? ? ? ? ? }? ? ? ? ? ? ? ? break;?? ? ? ? ? ? ? ?? ? ? ? ? ? case SKPaymentTransactionStatePurchasing://? ? ? ? ? ? ? ? NSLog(@"商品添加進(jìn)列表");? ? ? ? ? ? ? ? break;?? ? ? ? ? ? ? ?? ? ? ? ? ? case SKPaymentTransactionStateRestored://? ? ? ? ? ? ? ? NSLog(@"已經(jīng)購(gòu)買過商品");? ? ? ? ? ? ? ? [[SKPaymentQueue defaultQueue] finishTransaction:tran];? ? ? ? ? ? ? ? break;?? ? ? ? ? ? ? ?? ? ? ? ? ? case SKPaymentTransactionStateFailed://? ? ? ? ? ? ? ? NSLog(@"交易失敗");? ? ? ? ? ? ? ? [[SKPaymentQueue defaultQueue] finishTransaction:tran];? ? ? ? ? ? ? ? break;?? ? ? ? ? ? ? ?? ? ? ? ? ? case SKPaymentTransactionStateDeferred://? ? ? ? ? ? ? ? NSLog(@"交易還在隊(duì)列里面,但最終狀態(tài)還沒有決定");? ? ? ? ? ? ? ? break;?? ? ? ? ? ? ? ?? ? ? ? ? ? default:? ? ? ? ? ? ? ? break;? ? ? ? }?? ? ? ?? ? }?? ?}
#pragma mark ------ 支付完成,得到交易憑證- (void)completeTransaction:(SKPaymentTransaction *)transaction{?? ?? ? //此時(shí)告訴后臺(tái)交易成功颠蕴,并把receipt傳給后臺(tái)驗(yàn)證? ? NSString *transactionReceiptString= nil;? ? //系統(tǒng)IOS7.0以上獲取支付驗(yàn)證憑證的方式應(yīng)該改變泣刹,切驗(yàn)證返回的數(shù)據(jù)結(jié)構(gòu)也不一樣了。? ? // 驗(yàn)證憑據(jù)犀被,獲取到蘋果返回的交易憑據(jù)? ? // appStoreReceiptURL iOS7.0增加的椅您,購(gòu)買交易完成后,會(huì)將憑據(jù)存放在該地址? ? NSURLRequest *appstoreRequest = [NSURLRequest requestWithURL:[[NSBundle mainBundle] appStoreReceiptURL]];? ? NSError *error = nil;? ? // 從沙盒中獲取到購(gòu)買憑據(jù)?? ?? ? NSData * receiptData = [NSURLConnection sendSynchronousRequest:appstoreRequest returningResponse:nil error:&error];? ? // 20 BASE64 常用的編碼方案寡键,通常用于數(shù)據(jù)傳輸掀泳,以及加密算法的基礎(chǔ)算法,傳輸過程中能夠保證數(shù)據(jù)傳輸?shù)姆€(wěn)定性 21 BASE64是可以編碼和解碼的 22? ? transactionReceiptString = [receiptData base64EncodedStringWithOptions:0];//[receiptData base64EncodedStringWithOptions:0];? ? //? ? NSLog(@"requestContentstr:%@",[receiptData base64EncodedStringWithOptions:0]);?? ?? ? //? ? NSDictionary *dic = @{@"orderCode":self.dataOrder.orderCode,? ? //? ? ? ? ? ? ? ? ? ? ? ? ? @"receipt":transactionReceiptString,? ? //? ? ? ? ? ? ? ? ? ? ? ? ? @"category":@"1"? ? //? ? ? ? ? ? ? ? ? ? ? ? ? };? ? //? ? NSLog(@"diczhi:%@",dic);? ? //? ? //? ? self.tran = transaction;? ? //? ? [self.bizEBeanBuy requestAppStorePaySuccessCallBack:dic];//蘋果支付成功,傳receipt-data給后臺(tái)驗(yàn)證?? ???? ?? ? [[SKPaymentQueue defaultQueue] finishTransaction:transaction];?? ?}
5.沙盒測(cè)試
如下圖6,點(diǎn)添加創(chuàng)建沙盒測(cè)試賬號(hào),賬號(hào)未未注冊(cè)成AppleID的賬號(hào),測(cè)試前先到設(shè)置里退出當(dāng)前AppleID,登錄沙盒測(cè)試賬號(hào),沙盒測(cè)試賬號(hào)只能用來測(cè)試沙盒支付,不具備正常AppleID的功能.
需要了解雙重驗(yàn)證,交易憑證判重機(jī)制,漏單處理,提交審核坑,集成坑,交易流水對(duì)賬的朋友下方留言我抽時(shí)間補(bǔ)充.
補(bǔ)充內(nèi)容和代碼請(qǐng)看我的另一篇文章:iOS內(nèi)購(gòu)全面實(shí)戰(zhàn)