您的位置:首页 > 移动开发

iOS In-App Purchase 内购之 验证订单是沙盒环境还是真实环境

2017-08-30 13:51 489 查看


测试环境

在sandbox中验证receipt:https://sandbox.itunes.apple.com/verifyReceipt

在生产环境中验证receipt:https://buy.itunes.apple.com/verifyReceipt

那么如何自动的识别收据是否是sandbox receipt呢?

识别沙盒环境下收据的方法有两种:
根据收据字段 environment = sandbox。
根据收据验证接口返回的状态码。

如果status=21007,则表示当前的收据为沙盒环境下收据, t进行验证。


苹果反馈的状态码:

21000 App Store无法读取你提供的JSON数据
21002 收据数据不符合格式
21003 收据无法被验证
21004 你提供的共享密钥和账户的共享密钥不一致
21005 收据服务器当前不可用
21006 收据是有效的,但订阅服务已经过期。当收到这个信息时,解码后的收据信息也包含在返回内容中
21007 收据信息是测试用(sandbox),但却被发送到产品环境中验证
21008 收据信息是产品环境中使用,但却被发送到测试环境中验证


注意:

在verifyWithRetry方法中,首先向向真实环境验证票据,如果是21007则向沙盒环境验证;==但是在消耗品类型的测试中,使用沙盒票据在真实环境中验证票据得到返回码:21002.所以下面代码在真实环境运行时,沙盒测试消耗型商品得不到正确的验证结果==。

/*
verifyWithRetry the receipt
*/
IAPVerifier.verifyWithRetry = function(receipt, isBase64, cb) {
var encoded = null, receiptData = {};
if (isBase64) {
encoded = receipt;
} else {
encoded = new Buffer(receipt).toString('base64');
}
receiptData['receipt-data'] = encoded;
var options = this.requestOptions();
return this.verify(receiptData, options, (function(_this) {
return function(error, data) {
if (error) return cb(error);
if ((21007 === (data != null ? data.status : void 0)) && (_this.productionHost == _this.host)) {
var options_this.requestOptions();
// 指向沙盒测试环境再次验证
options.host = 'sandbox.itunes.apple.com/verifyReceipt';
return _this.verify(receiptData, options, function(err, data) {
return cb(err, data);
});
} else {
return cb(err, data);
}
};
})(this));
};

/*
verify the receipt data
*/

IAPVerifier.verify = function(data, options, cb) {
var post_data, request;
post_data = JSON.stringify(data);
options.headers = {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': post_data.length
};
var request = https.request(options, (function(_this) {
return function(response) {
var response_chunk = [];
response.on('data', function(data) {
if (response.statusCode !== 200) {
return cb(new Error("response.statusCode != 200"));
}
response_chunk.push(data);
});
return response.on('end', function() {
var responseData, totalData;
totalData = response_chunk.join('');
try {
responseData = JSON.parse(totalData);
} catch (_error) {
return cb(_error);
}
return cb(null, responseData);
});
};
})(this));
request.write(post_data);
request.end();
request.on('error', function (exp) {
console.log('problem with request: ' + exp.message);
});
};

IAPVerifier.requestOptions = function() {
return options = {
host: 'buy.itunes.apple.com',
port: 443,
path: '/verifyReceipt',
method: "POST",
rejectUnauthorized: false/*不加:返回证书不受信任CERT_UNTRUSTED*/
};
};


建议:

为保证审核的通过,需要在客户端或server进行双重验证,即,先以线上交易验证地址进行验证,如果苹果正式验证服务器的返回验证码code为21007,则再一次连接沙盒测试服务器进行验证即可。在应用提审时,苹果IAP提审验证时是在沙盒环境的进行的,即:苹果在审核App时,只会在sandbox环境购买,其产生的购买凭证,也只能连接苹果的测试验证服务器,如果没有做双验证,需要特别注意此问题,否则会被拒。

PS:上面代码是服务器的验证方式。客户端的验证方式的代码如下:


5、iOS7 客户端验证的订单状态


苹果在iOS7提升了购买凭据的安全性,可以直接单独在客户端完成订单正确性的验证,但是处于金钱考虑,购买完成后,建议还是要做凭据的后台验证工作。

[objc] view
plain copy

 

 





#pragma mark 客户端验证购买凭据  

- (void)verifyTransactionResult  

{  

    // 验证凭据,获取到苹果返回的交易凭据  

    // appStoreReceiptURL iOS7.0增加的,购买交易完成后,会将凭据存放在该地址  

    NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];  

    // 从沙盒中获取到购买凭据  

    NSData *receipt = [NSData dataWithContentsOfURL:receiptURL];  

    // 传输的是BASE64编码的字符串  

    /** 

     BASE64 常用的编码方案,通常用于数据传输,以及加密算法的基础算法,传输过程中能够保证数据传输的稳定性 

     BASE64是可以编码和解码的 

     */  

    NSDictionary *requestContents = @{  

                                      @"receipt-data": [receipt base64EncodedStringWithOptions:0]  

                                      };  

    NSError *error;  

    // 转换为 JSON 格式  

    NSData *requestData = [NSJSONSerialization dataWithJSONObject:requestContents  

                                                          options:0  

                                                            error:&error];  

    // 不存在  

    if (!requestData) { /* ... Handle error ... */ }  

      

    // 发送网络POST请求,对购买凭据进行验证  

    NSString *verifyUrlString;  

#if (defined(APPSTORE_ASK_TO_BUY_IN_SANDBOX) && defined(DEBUG))  

    verifyUrlString = @"https://sandbox.itunes.apple.com/verifyReceipt";  

#else  

    verifyUrlString = @"https://buy.itunes.apple.com/verifyReceipt";  

#endif  

    // 国内访问苹果服务器比较慢,timeoutInterval 需要长一点  

    NSMutableURLRequest *storeRequest = [NSMutableURLRequest requestWithURL:[[NSURL alloc] initWithString:verifyUrlString] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:10.0f];  

      

    [storeRequest setHTTPMethod:@"POST"];  

    [storeRequest setHTTPBody:requestData];  

      

    // 在后台对列中提交验证请求,并获得官方的验证JSON结果  

    NSOperationQueue *queue = [[NSOperationQueue alloc] init];  

    [NSURLConnection sendAsynchronousRequest:storeRequest queue:queue  

                           completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {  

                               if (connectionError) {  

                                   NSLog(@"链接失败");  

                               } else {  

                                   NSError *error;  

                                   NSDictionary *jsonResponse = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];  

                                   if (!jsonResponse) {  

                                       NSLog(@"验证失败");  

                                   }  

                                     

                                   // 比对 jsonResponse 中以下信息基本上可以保证数据安全  

                                   /* 

                                    bundle_id 

                                    application_version 

                                    product_id 

                                    transaction_id 

                                    */  

                                     

                                   NSLog(@"验证成功");  

                               }  

                           }];  

      

}  


6、内购验证凭据返回结果状态码说明

苹果反馈的状态码:

[objc] view
plain copy

 

 





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

21002 收据数据不符合格式  

21003 收据无法被验证  

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

21005 收据服务器当前不可用  

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

21007 收据信息是测试用(sandbox),但却被发送到产品环境中验证  

21008 收据信息是产品环境中使用,但却被发送到测试环境中验证
 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: