Apple 內(nèi)購流程(代碼開發(fā)級別)

Apple 內(nèi)購流程:
1、向蘋果服務(wù)器止毕,發(fā)送請求模蜡,獲取可購買商品信息。
2扁凛、SKProductsRequest 協(xié)議 忍疾。獲取商品數(shù)據(jù)列表。
3谨朝、確定購買商品(或回復(fù)商品)卤妒。
4、監(jiān)測交易過程字币。
5则披、驗證交易收據(jù)(receipt)。
1洗出、向蘋果服務(wù)器士复,發(fā)送請求,獲取可購買商品信息翩活。

//提交商品信息請求
- (void)requestProductWithProductArray:(NSArray *)productIdAry {
     NSSet *set = [[NSSet alloc] initWithArray:productIdAry];
    
    //“異步”請求有哪些可售商品
    SKProductsRequest *request = [[SKProductsRequest alloc] initWithProductIdentifiers:set];
    //啟動服務(wù)
    [request start];
}

2阱洪、SKProductsRequest 協(xié)議 便贵。獲取商品數(shù)據(jù)列表。

#pragma mark - SKProductsRequest Delegate
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response {
    //獲取商品數(shù)據(jù)
    NSArray *productAry = response.products;
    if ([productAry count] <= 0) {
        //暫無商品信息
        return;
    }
    
    //初始化本地商品信息個數(shù)
    if (self.productDic == nil) {
        self.productDic = [NSMutableDictionary dictionaryWithCapacity:response.products.count];
    }

    //遍歷商品數(shù)據(jù)
    for (SKproduct *product in response.products) {
        [self.productDis setObject:product forKey:product.productIdentifier];
        
        //打印產(chǎn)品列表信息
        NSLog(@"product ID : %@",product.productIdentifier);
        NSLog(@"product Description : %@",product.description);
        NSLog(@"product Title :%@",product.localizedTitle);
    }

#warning - Todo 可以將商品信息列表傳給ViewController以供顯示商品列表冗荸。
#warning - Todo 但不建議使用此信息顯示商品列表承璃,可以用此信息進行產(chǎn)品ID的驗證。
}

#pragma mark - SKProductsRequest Delegate
- (void)request:(SKRequest *)request didFailWithError:(NSError *)error {
    NSLog(@"---------------- 錯誤 ---------------");
}

#pragma mark - SKProductsRequest Delegate
- (void)requestDidFinish:(SKPRequest *)request {
    NSLog(@"--------------- 反饋信息結(jié)束 ---------------");
}

3俏竞、確定購買商品

#pragma mark - Buy Product
- (void)buyProduct:(NSString *)productID {
    //購買商品
    SKProduct *buyProduct = self.productDic[productID];

    SKPayment *payment = [SKPayment paymentWithProduct:buyProduct];
    [[SKPaymentQueue defaultQueue] addPayment:payment];
}

4绸硕、回復(fù)商品

#pragma mark - Restore Product
- (void)restorePurchase {
    //回復(fù)已經(jīng)完成的所有交易(僅限永久有效商品)。
    [[SKPaymentQueue defaultQueue] restoreCompletedTransactions];
}

5魂毁、監(jiān)測交易過程

#pragma mark - SKPaymentTransaction Observer
- (void)paymentQueue:(SKPaymentQueue *)queue updateTransactions:(NSArray<SKPaymentTransaction *> *)transaction {
    for (SKPaymentTransaction *transaction in transactions) {
        NSLog(@"交易隊列狀態(tài) :%@",transactions);
        switch (transaction.transactionState) {
            case SKPaymentTransactionStatePurchased:    //購買成功
                //  向蘋果服務(wù)器進行驗證
                if (self.checkAfterPay) {
                    //支付成功了玻佩,并開始向蘋果服務(wù)器進行驗證(若CheckAfterPay為NO,則不會經(jīng)過此步驟)
                }else {
                    //商品完全購買成功且驗證成功了席楚。(若CheckAfterPay為NO咬崔,則會在購買成功后直接觸發(fā)此方法)
                }
                //  目前都是全部進行驗證。
                [self verifyPruchaseWithPaymentTransaction:transaction isTestServer:NO];
                break;
                
            case SKPaymentTransactionStatePurchasing:   //  正在購買
                NSLog(@"正在購買...");
                break;
                
            case SKPaymentTransactionStateRestored:     //  恢復(fù)成功
                //  將交易從交易隊列中刪除
                [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
                break;
                
            case SKPaymentTransactionStateFailed:       //  購買取消或失敗
                if (transaction.error.code != SKErrorPaymentCancelled) {
                    NSLog(@"購買失敺持取垮斯!");
                }else{
                    NSLog(@"購買取消!");
                }
                //  將交易從交易隊列中刪除
                [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
                break;
            
            default:
                //  將交易從交易隊列中刪除
                [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
                break;
        }
    }
}

6只祠、驗證交易收據(jù)(receipt)

#pragma mark - Verify Receipt
- (void)verifyPruchaseWithPaymentTransaction:(SKPaymentTransaction *)transaction isTestServer:(BOOL)flag {
    //  驗證憑據(jù)兜蠕,獲取到蘋果返回的交易憑據(jù)
    //  appStore Receipt URL iOS7.0增加的,購買交易完成后抛寝,會將憑據(jù)存放在該地址
    NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];
    //  從沙盒中獲取到購買憑據(jù)receipte
    NSData *receipt = [NSData dataWithContentsOfURL:receiptURL];
    
    
    if (!receipt) {
        //  交易憑證為空熊杨,驗證失敗
        //  KIAPPurchVerFailed
        return;
    }else {
        //  購買成功將交易憑證發(fā)送給服務(wù)端進行再次校驗
        //  kIAppurchSuccess
    }
    
    // 在網(wǎng)絡(luò)中傳輸數(shù)據(jù),大多情況下是傳輸?shù)淖址皇嵌M制數(shù)據(jù)
    // 傳輸?shù)氖荁ASE64編碼的字符串
    /**
     BASE64 常用的編碼方案盗舰,通常用于數(shù)據(jù)傳輸晶府,以及加密算法的基礎(chǔ)算法,傳輸過程中能夠保證數(shù)據(jù)傳輸?shù)姆€(wěn)定性
     BASE64是可以編碼和解碼的
     */
    NSString *encodeStr = [receipt base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];
    NSString *encodeLoad = [NSString stringWithFormat:@"{\"receipt-data\" : \"%@\"}", encodeStr];
    NSData *receiptData = [encodeLoad dataUsingEncoding:NSUTF8StringEncoding];
    
    //  發(fā)送網(wǎng)絡(luò)POST請求钻趋,對購買憑證進行驗證
    //  In the test environment, use https://sandbox.itunes.apple.com/verifyReceipt
    //  In the real environment, use https://buy.itunes.apple.com/verifyReceipt
    NSString *serverStr = @"https://buy.itunes.apple.com/verifyReceipt";
    if (flag) {
        serverStr = @"https://sandbox.itunes.apple.com/verifyReceipt";
    }
    
    NSURL *storeURL = [NSURL URLWithString:serverStr];
    
    NSMutableURLRequest *storeRequest = [NSMutableURLRequest requestWithURL:storeURL];
    [storeRequest setHTTPMethod:@"POST"];
    [storeRequest setHTTPBody:receiptData];
    
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    [NSURLConnection sendAsynchronousRequest:storeRequest
                                       queue:queue
                           completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
                               if (connectionError) {
                                   // 無法連接服務(wù)器,購買校驗失敗
                                   // KIAPPurchVerFailed
                                   
                               } else {
                                   NSError *error;
                                   NSDictionary *jsonResponse = [NSJSONSerialization JSONObjectWithData:data
                                                                                                options:0
                                                                                                  error:&error];
                                   NSLog(@"----驗證結(jié)果 %@",jsonResponse);
                                   if (!jsonResponse) {
                                       // 蘋果服務(wù)器校驗數(shù)據(jù)返回為空校驗失敗
                                       // KIAPPurchVerFailed
                                   }
                                   // 先驗證正式服務(wù)器,如果正式服務(wù)器返回21007再去蘋果測試服務(wù)器驗證,沙盒測試環(huán)境蘋果用的是測試服務(wù)器
                                   NSString *status = [NSString stringWithFormat:@"%@",jsonResponse[@"status"]];
                                   if (status && [status isEqualToString:@"21007"]) {
#warning - Todo 給ViewController提示
                                       [self verifyPruchaseWithPaymentTransaction:transaction isTestServer:YES];
                                       
                                   }else if(status && [status isEqualToString:@"0"]){
#warning - Todo 給ViewController提示
                                       //   kIAPPurchVerSuccwss 購買成功切驗證成功
                                   }
                               }
                           }];
    
    // 驗證成功與否都注銷交易,否則會出現(xiàn)虛假憑證信息一直驗證不通過,每次進程序都得輸入蘋果賬號
    [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
    
}

PS:驗證流程

訂單正確性的驗證:
1.iOS客戶端(購買成功)→ 到蘋果服務(wù)器驗證 → 蘋果服務(wù)器返回驗證結(jié)果川陆,做相應(yīng)處理
2.iOS客戶端(購買成功)→ 后臺 → 蘋果服務(wù)器驗證 → 蘋果服務(wù)器返回驗證結(jié)果,做相應(yīng)處理

服務(wù)器要做的是:

1.接收iOS前端發(fā)過來的購買憑證蛮位。

2.判斷憑證是否已經(jīng)存在或驗證過较沪,然后存儲該憑證。

3.將該憑證發(fā)送到對應(yīng)環(huán)境下的蘋果服務(wù)器驗證失仁,并將驗證結(jié)果返回給客戶端购对。

4.根據(jù)需求,是否修改用戶相應(yīng)信息陶因。

注意事項

1.bundleID要與iTunes Connect上你App的相同骡苞,不然是請求不到產(chǎn)品信息的

2.在沙盒環(huán)境進行測試內(nèi)購的時候,要使用沒有越獄的蘋果手機。

3.在沙盒環(huán)境下真機測試內(nèi)購時解幽,請去app store中注銷你的apple ID贴见,不然發(fā)起支付購買請求后會直接case:SKPaymentTransactionStateFailed。使用沙盒測試員的賬號時不需要真正花錢的躲株。

4.如果只添加了一個沙盒測試員賬號片部,當一個真機已經(jīng)使用了這個賬號,另一個真機再使用這個賬號支付也是會發(fā)生錯誤的霜定。那就去多建幾個沙盒測試員賬號使用不同的档悠,反正也是免費的,填寫也很快望浩。

5.監(jiān)聽購買結(jié)果辖所,當失敗和成功時代碼中要調(diào)用:

[[SKPaymentQueue defaultQueue] finishTransaction:transaction];

該方法通知蘋果支付隊列該交易已完成,不然就會已發(fā)起相同 ID 的商品購買就會有此項目將免費恢復(fù)的提示磨德。

請在本地做一下憑證存儲

現(xiàn)在訂單正確性的驗證是:iOS客戶端(購買成功)→ 后臺→后臺到蘋果服務(wù)器驗證→處理后臺返回結(jié)果做相應(yīng)邏輯處理缘回。

注意:
如果Your App 和 Your Server 中斷了鏈接
當我們前端購買成功后,憑證(receipt)本地保留一份典挑,當與后臺驗證成功后酥宴,再將本地保留的憑證刪除。
否者一直使用本地已經(jīng)保留的憑證與后臺交互您觉。

測試前提條件:
1.在itunesConnect中填寫測試賬號拙寡。
2.在itunesConnect中填寫稅務(wù)單(就是銀行賬號,開戶名琳水,收款機構(gòu)等等的稅務(wù)單)倒庵。
3.交易收據(jù)內(nèi)容(receipt)

 "receipt":
    {
        "original_purchase_date_pst":"2015-06-22 20:56:34 America/Los_Angeles", //購買時間,太平洋標準時間
        "purchase_date_ms":"1435031794826", //購買時間毫秒
        "unique_identifier":"5bcc5503dbcc886d10d09bef079dc9ab08ac11bb",//唯一標識符
        "original_transaction_id":"1000000160390314", //原始交易ID
        "bvrs":"1.0",//iPhone程序的版本號
        "transaction_id":"1000000160390314", //交易的標識
        "quantity":"1", //購買商品的數(shù)量
        "unique_vendor_identifier":"AEEC55C0-FA41-426A-B9FC-324128342652", //開發(fā)商交易ID
        "item_id":"1008526677",//App Store用來標識程序的字符串
        "product_id":"cosmosbox.strikehero.gems60",//商品的標識 
        "purchase_date":"2015-06-23 03:56:34 Etc/GMT",//購買時間
        "original_purchase_date":"2015-06-23 03:56:34 Etc/GMT", //原始購買時間
        "purchase_date_pst":"2015-06-22 20:56:34 America/Los_Angeles",//太平洋標準時間
        "bid":"com.cosmosbox.StrikeHero",//iPhone程序的bundle標識
        "original_purchase_date_ms":"1435031794826"http://毫秒
 }

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市炫刷,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌郁妈,老刑警劉巖浑玛,帶你破解...
    沈念sama閱讀 206,723評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異噩咪,居然都是意外死亡顾彰,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評論 2 382
  • 文/潘曉璐 我一進店門胃碾,熙熙樓的掌柜王于貴愁眉苦臉地迎上來涨享,“玉大人,你說我怎么就攤上這事仆百〔匏恚” “怎么了?”我有些...
    開封第一講書人閱讀 152,998評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長吁讨。 經(jīng)常有香客問我髓迎,道長,這世上最難降的妖魔是什么建丧? 我笑而不...
    開封第一講書人閱讀 55,323評論 1 279
  • 正文 為了忘掉前任排龄,我火速辦了婚禮,結(jié)果婚禮上翎朱,老公的妹妹穿的比我還像新娘橄维。我一直安慰自己,他們只是感情好拴曲,可當我...
    茶點故事閱讀 64,355評論 5 374
  • 文/花漫 我一把揭開白布争舞。 她就那樣靜靜地躺著,像睡著了一般疗韵。 火紅的嫁衣襯著肌膚如雪兑障。 梳的紋絲不亂的頭發(fā)上资厉,一...
    開封第一講書人閱讀 49,079評論 1 285
  • 那天赊级,我揣著相機與錄音尽纽,去河邊找鬼婆誓。 笑死艰垂,一個胖子當著我的面吹牛屎开,可吹牛的內(nèi)容都是我干的碉钠。 我是一名探鬼主播流妻,決...
    沈念sama閱讀 38,389評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼驹马,長吁一口氣:“原來是場噩夢啊……” “哼革砸!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起糯累,我...
    開封第一講書人閱讀 37,019評論 0 259
  • 序言:老撾萬榮一對情侶失蹤算利,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后泳姐,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體效拭,經(jīng)...
    沈念sama閱讀 43,519評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,971評論 2 325
  • 正文 我和宋清朗相戀三年胖秒,在試婚紗的時候發(fā)現(xiàn)自己被綠了缎患。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,100評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡阎肝,死狀恐怖挤渔,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情风题,我是刑警寧澤判导,帶...
    沈念sama閱讀 33,738評論 4 324
  • 正文 年R本政府宣布嫉父,位于F島的核電站,受9級特大地震影響骡楼,放射性物質(zhì)發(fā)生泄漏熔号。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,293評論 3 307
  • 文/蒙蒙 一鸟整、第九天 我趴在偏房一處隱蔽的房頂上張望引镊。 院中可真熱鬧,春花似錦篮条、人聲如沸弟头。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,289評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽赴恨。三九已至,卻和暖如春伴栓,著一層夾襖步出監(jiān)牢的瞬間伦连,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,517評論 1 262
  • 我被黑心中介騙來泰國打工钳垮, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留惑淳,地道東北人。 一個月前我還...
    沈念sama閱讀 45,547評論 2 354
  • 正文 我出身青樓饺窿,卻偏偏與公主長得像歧焦,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子肚医,可洞房花燭夜當晚...
    茶點故事閱讀 42,834評論 2 345

推薦閱讀更多精彩內(nèi)容

  • 花了快10個工作日绢馍,終于完成了內(nèi)購(IAP)功能。必須寫篇文章來記錄一下這十天來的心得體會肠套,更是為了避免后續(xù)的開發(fā)...
    flightlessBirdT閱讀 9,412評論 16 38
  • iOS應(yīng)用如果涉及到支付功能舰涌,分為兩類:第三方支付和蘋果內(nèi)購。那么什么情況下選擇使用第三方支付你稚,又在什么情況下選擇...
    ZfRee閱讀 38,782評論 36 66
  • 參考借鑒了一下幾篇文章(在這里很感謝各位作者大大做出的總結(jié)和方案): http://blog.csdn.net/a...
    輝546閱讀 13,866評論 3 12
  • 自己開發(fā)的視頻直播項目瓷耙,牽涉到充值金幣,用到了蘋果公司的內(nèi)購入宦,趴坑了兩天,這里總結(jié)下實現(xiàn)蘋果內(nèi)購室琢。 一. 創(chuàng)建測試...
    Leo丶Dicaprio閱讀 3,361評論 8 7
  • Web前端框架就是為了節(jié)約開發(fā)成本和時間乾闰,一般開發(fā)一個項目都會用到前端框架(除非自己有前端開發(fā)團隊),根據(jù)我經(jīng)驗找...
    UIleader閱讀 3,597評論 0 4