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 验证结果:正常返回

沙盒订单,测试链接(iOS7以前  )

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

沙盒订单,正式链接(iOS7以前)
沙盒订单,分别验证正式和沙盒环境,iOS7以后

苹果反馈的状态码status:

0          成功

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

21002 收据数据不符合格式

21003 收据无法被验证

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

21005 收据服务器当前不可用

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

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

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

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

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

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

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

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

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,393评论 5 467
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,790评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,391评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,703评论 1 270
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,613评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,003评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,507评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,158评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,300评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,256评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,274评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,984评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,569评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,662评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,899评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,268评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,840评论 2 339

推荐阅读更多精彩内容

  • 一.总说内购的内容 协议、税务和银行业务 信息填写 内购商品的添加 添加沙盒测试账号 内购代码的具体实现 内购的注...
    默默_David阅读 3,626评论 0 6
  • iOS应用如果涉及到支付功能,分为两类:第三方支付和苹果内购。那么什么情况下选择使用第三方支付,又在什么情况下选择...
    ZfRee阅读 38,729评论 36 66
  • 后台服务器验证 IOS 内支付有两种模式: 1) 内置模式 2) 服务器模式 内置模式的流程可以简单的总结为以下几...
    月醉花听阅读 5,269评论 1 2
  • 一.总说内购的内容 协议、税务和银行业务 信息填写 内购商品的添加 添加沙盒测试账号 内购代码的具体实现 内购的注...
    九洲仙人阅读 2,934评论 2 3
  • 1 、在iTunes Connect中,每个应用程序可以创建多少格内置购买产品 ID ? 阅读 In-App Pu...
    Dosun阅读 3,872评论 0 0