天天看點

iOS-内購注意 沙盒二次驗證

1、發送請求,注意請求ID

NSString *productID = @"這是建立内購項目填寫的ID";
NSArray *product = [[NSArray alloc] initWithObjects: productID,nil];
NSSet *nsset = [NSSet setWithArray:product];
SKProductsRequest *request = [[SKProductsRequest alloc] initWithProductIdentifiers:nsset];
request.delegate = self;
           

2、 在監聽購買結果後,一定要調用[[SKPaymentQueue defaultQueue] finishTransaction:tran];來允許你從支付隊列中移除交易。

//監聽購買結果
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transaction{
    for(SKPaymentTransaction *tran in transaction){
        switch (tran.transactionState) {
            case SKPaymentTransactionStatePurchased:{
                NSLog(@"交易完成");
                // 發送到蘋果伺服器驗證憑證,進行二次驗證
                [self verifyPurchaseWithProductionEnvironment];
                [[SKPaymentQueue defaultQueue] finishTransaction:tran];

            }
                break;
            case SKPaymentTransactionStatePurchasing:
                NSLog(@"商品添加進清單");

                break;
            case SKPaymentTransactionStateRestored:{
                NSLog(@"已經購買過商品");

                [[SKPaymentQueue defaultQueue] finishTransaction:tran];
            }
                break;
            case SKPaymentTransactionStateFailed:{
                NSLog(@"交易失敗");
                [[SKPaymentQueue defaultQueue] finishTransaction:tran];
                [SVProgressHUD showErrorWithStatus:@"購買失敗"];
            }
                break;
            default:
                break;
        }
    }
}
           

3、 沙盒環境測試appStore内購流程的時候,請使用沒越獄的裝置。

請務必使用真機來測試,一切以真機為準。

4、 項目的Bundle identifier需要與您申請AppID時填寫的bundleID一緻,不然會無法請求到商品資訊。

5、真機測試的時候,一定要退出原來的賬号,才能用沙盒測試賬号

6、二次驗證,請注意區分宏, 測試用沙盒驗證,App Store稽核的時候也使用的是沙盒購買,是以驗證購買憑證的時候需要判斷傳回Status Code決定是否去沙盒進行二次驗證,為了線上使用者的使用,驗證的順序肯定是先驗證正式環境,此時若傳回值為21007,就需要去沙盒二次驗證,因為此購買的是在沙盒進行的。

//沙盒測試環境驗證
#define SANDBOX @"https://sandbox.itunes.apple.com/verifyReceipt"
//正式環境驗證
#define AppStore @"https://buy.itunes.apple.com/verifyReceipt"
/**
 *  驗證購買,避免越獄軟體模拟蘋果請求達到非法購買問題
 *
 */
-(void)verifyPurchaseWithProductionEnvironment{
    //從沙盒中擷取交易憑證并且拼接成請求體資料
    NSURL *receiptUrl=[[NSBundle mainBundle] appStoreReceiptURL];
    NSData *receiptData=[NSData dataWithContentsOfURL:receiptUrl];

    NSString *receiptString=[receiptData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];//轉化為base64字元串

    NSString *bodyString = [NSString stringWithFormat:@"{\"receipt-data\" : \"%@\"}", receiptString];//拼接請求資料
    NSData *bodyData = [bodyString dataUsingEncoding:NSUTF8StringEncoding];

/*
注意:
自己測試的時候使用的是沙盒購買(測試環境)
App Store稽核的時候也使用的是沙盒購買(測試環境)
上線以後就不是用的沙盒購買了(正式環境)

是以此時應該先驗證正式環境,在驗證測試環境

正式環境驗證成功,說明是線上使用者在使用
正式環境驗證不成功傳回21007,說明是自己測試或者稽核人員在測試
*/

//第一步,驗證正式環境
 //建立請求到蘋果官方進行購買驗證(正式環境)
    NSURL *url=[NSURL URLWithString: AppStore];
    NSMutableURLRequest *requestM=[NSMutableURLRequest requestWithURL:url];
    requestM.HTTPBody=bodyData;
    [email protected]"POST";
    //建立連接配接并發送同步請求
    NSError *error=nil;
    NSData *responseData=[NSURLConnection sendSynchronousRequest:requestM returningResponse:nil error:&error];
    if (error) {
        NSLog(@"驗證購買過程中發生錯誤,錯誤資訊:%@",error.localizedDescription);
        return;
    }
    NSDictionary *dic=[NSJSONSerialization JSONObjectWithData:responseData options:NSJSONReadingAllowFragments error:nil];
    NSLog(@"%@",dic);
    if([dic[@"status"] intValue]==0){
        //正式環境驗證通過(說明是上線以後的使用者購買)
        NSLog(@"購買成功!");
        //在此處對購買記錄進行存儲,可以存儲到開發商的伺服器端
    }else if([dic[@"status"] intValue]== 21007){
        //This receipt is from the test environment, but it was sent to the production environment for verification. Send it to the test environment instead.
        //購買憑證來自于測試環境,但是卻發送到了正式環境,請改成測試環境(這種情況下可能是自己測試的,也可能是稽核人員測試的)

        //第二步,驗證測試環境
        [self verifyPurchaseWithTestEnvironment];

    }
}

 //建立請求到蘋果官方進行購買驗證(測試環境)
- (void)verifyPurchaseWithTestEnvironment {
    NSURL *url=[NSURL URLWithString:SANDBOX];
    NSMutableURLRequest *requestM=[NSMutableURLRequest requestWithURL:url];
    requestM.HTTPBody=bodyData;
    [email protected]"POST";
    //建立連接配接并發送同步請求
    NSError *error=nil;
    NSData *responseData=[NSURLConnection sendSynchronousRequest:requestM returningResponse:nil error:&error];
    if (error) {
        NSLog(@"驗證購買過程中發生錯誤,錯誤資訊:%@",error.localizedDescription);
        return;
    }
    NSDictionary *dic=[NSJSONSerialization JSONObjectWithData:responseData options:NSJSONReadingAllowFragments error:nil];
    NSLog(@"%@",dic);
    if([dic[@"status"] intValue]==0){
        NSLog(@"購買成功!");
        //在此處對購買記錄進行存儲,可以存儲到開發商的伺服器端
    }else{
        NSLog(@"購買失敗,未通過驗證!");
    }
}
           

繼續閱讀