iOS 内购如何验证订单,iOS7.0以后transaction.transactionReceipt被弃用,使用appStoreReceiptURL获取收据

iOS 内购详细步骤

参考:iOS 内购验证订单方法  

无法判断是沙盒环境还是正式环境,思路:先验证正式环境,再验证沙盒环境!

在sandbox中验证receipt

https://sandbox.itunes.apple.com/verifyReceipt

在生产环境中验证receipt

https://buy.itunes.apple.com/verifyReceipt

验证方法:

#define SANDBOX_VERIFY_RECEIPT_URL      @"https://sandbox.itunes.apple.com/verifyReceipt"

#define BUY_VERIFY_RECEIPT_URL                  @"https://buy.itunes.apple.com/verifyReceipt"

#pragma mark - 客户端验证订单的方法

-(void)verifyFinishedWithTransaction:(SKPaymentTransaction *)transaction{

        if(transaction.transactionState == SKPaymentTransactionStatePurchased){  // 交易完成

            //   NSData *transactionReceipt  = transaction.transactionReceipt;

                NSData *receiptData;

        #ifdef NSFoundationVersionNumber_iOS_7_0

                //如果NSFoundation的版本在7.0之上,包括7.0

                NSURLRequest *urlRequest =[NSURLRequest requestWithURL:[[NSBundle mainBundle] appStoreReceiptURL]];

                NSError *error = nil;

                receiptData = [NSURLConnection sendSynchronousRequest:urlRequest returningResponse:nil error:&error];

        #else

                //注意transaction.transactionReceipt在iOS7以后被弃用

                receiptData = transaction.transactionReceipt;

        #endif

                // 获取到加密后的transactionReceipt数据,用于发送给server端(可以Post给自己的服务器,让服务器去验证)

                NSString* receipent = [self encode:(uint8_t *)receiptData.bytes

                length:receiptData.length];

                // 在APP客户端做验证(先正式,后沙盒)

                NSDictionary *requestContents = @{@"receipt-data":receipent};

                NSData *requestData = [NSJSONSerialization dataWithJSONObject:requestContents

                options:0

                error:nil];

                int status = [self verifyCodeWithURL:BUY_VERIFY_RECEIPT_URL requestData:requestData];

                if (status == 0) {

                        NSLog(@"success ---------------- 正式 ---------------- ");

                }else if (status == 21007){

                     // 沙盒环境订单(在正式环境下验证了,需要验证沙盒)

                    status = [self verifyCodeWithURL:SANDBOX_VERIFY_RECEIPT_URL requestData:requestData];

                    if(status == 0){

                           NSLog(@"success ---------------- 沙盒 ----------------  ");

                    }else{

                           NSLog(@"error---------------- 沙盒  ---------------- ");

                   }

            }else{

                     NSLog(@"error---------------- 正式 ---------------- ");

           }

      }

}

#pragma mark - 向苹果服务器发起请求,获取状态码

- (int)verifyCodeWithURL:(NSString *)checkURLStr requestData:(NSData *)requestData{

        NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:checkURLStr]];

        [request setHTTPMethod:@"POST"];

        [request setHTTPBody:requestData];

        NSError* err;

        NSURLResponse *theResponse = nil;

        NSData *data=[NSURLConnection sendSynchronousRequest:request

        returningResponse:&theResponse

        error:&err];

        NSError *jsonParsingError = nil;

        NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&jsonParsingError];

        NSLog(@"requestDict: %@", dict);

        if ([dict[@"status"] intValue] == 0) {

                NSLog(@"success");

                NSString *productId = nil;

#ifdef NSFoundationVersionNumber_iOS_7_0

                if ([dict[@"status"] intValue] == 0) {

                        NSLog(@"success");

                }

                NSArray* products = dict[@"receipt"][@"in_app"];

                for (NSDictionary *item in products) {

                        if ([item[@"product_id"] isEqualToString:@“实际支付的productId”) {

                                productId = item[@"product_id"];

                                break;

                        }

                }

                if(productId == nil){

                        productId = products.lastObject[@"product_id"];

                }

#else

                productId = dict[@"receipt"][@"product_id"];

#endif

                if(productId && [productId isEqualToString:@“实际支付的productId”){

                        return 0;

                }else{

                        NSLog(@"error----------------商品ID不一致");

                        return -1;

                }

        }

        return [dict[@"status"] intValue];

}

#pragma mark - 加密字符串方法

- (NSString *)encode:(const uint8_t *)input length:(NSInteger)length {

    static char table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";

    NSMutableData *data = [NSMutableData dataWithLength:((length + 2) / 3) * 4];

    uint8_t *output = (uint8_t *)data.mutableBytes;

    for (NSInteger i = 0; i < length; i += 3) {

        NSInteger value = 0;

        for (NSInteger j = i; j < (i + 3); j++) {

            value <<= 8;

            if (j < length) {

                value |= (0xFF & input[j]);

            }

        }

        NSInteger index = (i / 3) * 4;

        output[index + 0] =                    table[(value >> 18) & 0x3F];

        output[index + 1] =                    table[(value >> 12) & 0x3F];

        output[index + 2] = (i + 1) < length ? table[(value >> 6)  & 0x3F] : '=';

        output[index + 3] = (i + 2) < length ? table[(value >> 0)  & 0x3F] : '=';

    }

    return [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];

}

沙盒环境下的订单用沙盒环境链接 https://sandbox.itunes.apple.com/verifyReceipt 验证结果:正常返回

iOS 内购如何验证订单,iOS7.0以后transaction.transactionReceipt被弃用,使用appStoreReceiptURL获取收据_第1张图片
沙盒订单,测试链接(iOS7以前  )

沙盒环境下的订单用正式环境链接 https://buy.itunes.apple.com/verifyReceipt 验证结果:异常

沙盒订单,正式链接(iOS7以前)
iOS 内购如何验证订单,iOS7.0以后transaction.transactionReceipt被弃用,使用appStoreReceiptURL获取收据_第2张图片
沙盒订单,分别验证正式和沙盒环境,iOS7以后

苹果反馈的状态码status:

0          成功

21000 App Store无法读取你提供的JSON数据

21002 收据数据不符合格式

21003 收据无法被验证

21004 你提供的共享密钥和账户的共享密钥不一致

21005 收据服务器当前不可用

21006 收据是有效的,但订阅服务已经过期。当收到这个信息时,解码后的收据信息也包含在返回内容中

21007 收据信息是沙盒测试中使用(sandbox),但却被发送到正式环境中验证

21008 收据信息是正式环境中使用,但却被发送到测试环境中验证

所以,可以根据苹果反馈的状态码,判断是沙盒环境还是正式环境:

21007 收据信息是沙盒测试中使用(sandbox),但却被发送到正式环境中验证

21008 收据信息是正式环境中使用,但却被发送到测试环境中验证

验证订单步骤:先正式,后沙盒

如果是沙盒环境,去正式URL下验证订单会返回21008,再用沙盒URL验证,即可!

如果是正式环境,去正式URL下验证订单会正常返回!

你可能感兴趣的:(iOS 内购如何验证订单,iOS7.0以后transaction.transactionReceipt被弃用,使用appStoreReceiptURL获取收据)