Apple 內購流程(代碼開發級別)

Apple 內購流程:
1、向蘋果服務器,發送請求,獲取可購買商品信息。
2、SKProductsRequest 協議 。獲取商品數據列表。
3、確定購買商品(或回復商品)。
4、監測交易過程。
5、驗證交易收據(receipt)。
1、向蘋果服務器,發送請求,獲取可購買商品信息。

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

2、SKProductsRequest 協議 。獲取商品數據列表。

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

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

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

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

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

3、確定購買商品

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

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

4、回復商品

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

5、監測交易過程

#pragma mark - SKPaymentTransaction Observer
- (void)paymentQueue:(SKPaymentQueue *)queue updateTransactions:(NSArray<SKPaymentTransaction *> *)transaction {
    for (SKPaymentTransaction *transaction in transactions) {
        NSLog(@"交易隊列狀態 :%@",transactions);
        switch (transaction.transactionState) {
            case SKPaymentTransactionStatePurchased:    //購買成功
                //  向蘋果服務器進行驗證
                if (self.checkAfterPay) {
                    //支付成功了,并開始向蘋果服務器進行驗證(若CheckAfterPay為NO,則不會經過此步驟)
                }else {
                    //商品完全購買成功且驗證成功了。(若CheckAfterPay為NO,則會在購買成功后直接觸發此方法)
                }
                //  目前都是全部進行驗證。
                [self verifyPruchaseWithPaymentTransaction:transaction isTestServer:NO];
                break;
                
            case SKPaymentTransactionStatePurchasing:   //  正在購買
                NSLog(@"正在購買...");
                break;
                
            case SKPaymentTransactionStateRestored:     //  恢復成功
                //  將交易從交易隊列中刪除
                [[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、驗證交易收據(receipt)

#pragma mark - Verify Receipt
- (void)verifyPruchaseWithPaymentTransaction:(SKPaymentTransaction *)transaction isTestServer:(BOOL)flag {
    //  驗證憑據,獲取到蘋果返回的交易憑據
    //  appStore Receipt URL iOS7.0增加的,購買交易完成后,會將憑據存放在該地址
    NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];
    //  從沙盒中獲取到購買憑據receipte
    NSData *receipt = [NSData dataWithContentsOfURL:receiptURL];
    
    
    if (!receipt) {
        //  交易憑證為空,驗證失敗
        //  KIAPPurchVerFailed
        return;
    }else {
        //  購買成功將交易憑證發送給服務端進行再次校驗
        //  kIAppurchSuccess
    }
    
    // 在網絡中傳輸數據,大多情況下是傳輸的字符串而不是二進制數據
    // 傳輸的是BASE64編碼的字符串
    /**
     BASE64 常用的編碼方案,通常用于數據傳輸,以及加密算法的基礎算法,傳輸過程中能夠保證數據傳輸的穩定性
     BASE64是可以編碼和解碼的
     */
    NSString *encodeStr = [receipt base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];
    NSString *encodeLoad = [NSString stringWithFormat:@"{\"receipt-data\" : \"%@\"}", encodeStr];
    NSData *receiptData = [encodeLoad dataUsingEncoding:NSUTF8StringEncoding];
    
    //  發送網絡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) {
                                   // 無法連接服務器,購買校驗失敗
                                   // KIAPPurchVerFailed
                                   
                               } else {
                                   NSError *error;
                                   NSDictionary *jsonResponse = [NSJSONSerialization JSONObjectWithData:data
                                                                                                options:0
                                                                                                  error:&error];
                                   NSLog(@"----驗證結果 %@",jsonResponse);
                                   if (!jsonResponse) {
                                       // 蘋果服務器校驗數據返回為空校驗失敗
                                       // KIAPPurchVerFailed
                                   }
                                   // 先驗證正式服務器,如果正式服務器返回21007再去蘋果測試服務器驗證,沙盒測試環境蘋果用的是測試服務器
                                   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 購買成功切驗證成功
                                   }
                               }
                           }];
    
    // 驗證成功與否都注銷交易,否則會出現虛假憑證信息一直驗證不通過,每次進程序都得輸入蘋果賬號
    [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
    
}

PS:驗證流程

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

服務器要做的是:

1.接收iOS前端發過來的購買憑證。

2.判斷憑證是否已經存在或驗證過,然后存儲該憑證。

3.將該憑證發送到對應環境下的蘋果服務器驗證,并將驗證結果返回給客戶端。

4.根據需求,是否修改用戶相應信息。

注意事項

1.bundleID要與iTunes Connect上你App的相同,不然是請求不到產品信息的

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

3.在沙盒環境下真機測試內購時,請去app store中注銷你的apple ID,不然發起支付購買請求后會直接case:SKPaymentTransactionStateFailed。使用沙盒測試員的賬號時不需要真正花錢的。

4.如果只添加了一個沙盒測試員賬號,當一個真機已經使用了這個賬號,另一個真機再使用這個賬號支付也是會發生錯誤的。那就去多建幾個沙盒測試員賬號使用不同的,反正也是免費的,填寫也很快。

5.監聽購買結果,當失敗和成功時代碼中要調用:

[[SKPaymentQueue defaultQueue] finishTransaction:transaction];

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

請在本地做一下憑證存儲

現在訂單正確性的驗證是:iOS客戶端(購買成功)→ 后臺→后臺到蘋果服務器驗證→處理后臺返回結果做相應邏輯處理。

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

測試前提條件:
1.在itunesConnect中填寫測試賬號。
2.在itunesConnect中填寫稅務單(就是銀行賬號,開戶名,收款機構等等的稅務單)。
3.交易收據內容(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", //購買商品的數量
        "unique_vendor_identifier":"AEEC55C0-FA41-426A-B9FC-324128342652", //開發商交易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://毫秒
 }

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,732評論 6 539
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,214評論 3 426
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,781評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,588評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,315評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,699評論 1 327
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,698評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,882評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,441評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,189評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,388評論 1 372
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,933評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,613評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,023評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,310評論 1 293
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,112評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,334評論 2 377

推薦閱讀更多精彩內容

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