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 客户端验证的订单状态
[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 收据信息是产品环境中使用,但却被发送到测试环境中验证
相关文章推荐
- ios In-App Purchase 内购验证购买是沙盒环境还是真实环境
- iOS In-App Purchase 内购之 验证订单是沙盒环境还是真实环境
- ios内购及订单验证(In-App Purchases in iOS 6 Tutorial: Consumables and Receipt Validation)
- iOS开发--In-app Purchase内购验证方法
- iOS In-App Purchase(IAP)内购服务端二次验证注意事项
- IOS In App Purchase(内购)验证
- C# [IPA]IOS In App Purchase(内购)验证(asp.net 版本)
- iOS的in-app purchase C#服务器二次验证实现
- iOS开发内购教程In App Purchase 需要了解的
- iOS In-App Purchase 内购之问题总结
- ios 应用内支付(In-App Purchase,沙盒测试,后台验证)
- iOS开发 app内购In-App Purchase(一)
- ios内购(iap)关于问题“您已经购买了此程序内购买(In App Purchase)项目,但尚未下载"的解决方案
- iOS In-App Purchase 内购之 什么是恢复购买记录
- iOS内购—— In-App Purchase(消耗型)
- iOS内购In-App Purchase
- [绍棠] ios 应用内支付(In-App Purchase,沙盒测试,后台验证)
- in-app Purchase (iOS内购)
- iOS In-App Purchase 内购之问题总结
- IOS内购集成(InAppPurchase)