我正在开发Swift中的iOS应用,并尝试为应用内购买实施收据验证。我无法弄清楚如何在Swift中实现这一点,所以我在this看到Giulio Roggero的例子之后尝试让我的应用程序通过Node.js中的Lambda函数发送请求。题。我的Swift代码如下所示:
let receiptPath = Bundle.main.appStoreReceiptURL?.path
if FileManager.default.fileExists(atPath: receiptPath!){
var receiptData:NSData?
do{
receiptData = try NSData(contentsOf: Bundle.main.appStoreReceiptURL!, options: NSData.ReadingOptions.alwaysMapped)
}
catch{
print("ERROR: " + error.localizedDescription)
}
let receiptString = receiptData?.base64EncodedString(options: .endLineWithLineFeed)
let invocationRequest = AWSLambdaInvokerInvocationRequest()
invocationRequest?.functionName = "sendReceiptRequest"
invocationRequest?.invocationType = AWSLambdaInvocationType.requestResponse
invocationRequest?.payload = ["receipt-data" : receiptString!, "password" : SUBSCRIPTION_SECRET]
let lambdaInvoker = AWSLambdaInvoker.default()
lock()
lambdaInvoker.invoke(invocationRequest!).continue(with: AWSExecutor.mainThread(), with: { (task:AWSTask!) -> AnyObject! in
if task.error != nil {
self.sendErrorPopup("Error: \(task.error?.localizedDescription)")
} else {
print("TOKEN: ", task.result)
}
self.unlock()
return nil
})}
My Lambda node.js函数如下所示:
function (receiptData_base64, password, production, cb)
{
var url = production ? 'buy.itunes.apple.com' : 'sandbox.itunes.apple.com'
var receiptEnvelope = {
"receipt-data": receiptData_base64,
"password":password
};
var receiptEnvelopeStr = JSON.stringify(receiptEnvelope);
var options = {
host: url,
port: 443,
path: '/verifyReceipt',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': Buffer.byteLength(receiptEnvelopeStr)
}
};
var req = https.request(options, function(res) {
res.setEncoding('utf8');
res.on('data', function (chunk) {
console.log("body: " + chunk);
cb(true, chunk);
});
res.on('error', function (error) {
console.log("error: " + error);
cb(false, error);
});
});
req.write(receiptEnvelopeStr);
req.end();
}
但是,在运行此代码时,无论是通过lambda测试还是通过我的应用程序,我都会收到一条简单的Response body:
{"errorMessage":"true"}
错误消息。我注意到,如果我调整代码,我可以创建更多预期错误 - 例如,如果我对收据数据有其他值,我会得到21002错误代码作为响应,如果我更改&#34 ;生产"如果是这样,我收到21007错误。问题的一部分是我不确切地知道回调应该如何工作 - https.request
内的块是否正确我想在Swift中做什么?我得到的结论是收据数据格式正确,因为更改它会产生不同的结果,那么为什么最终结果仍然是错误?
编辑:
我之前没有注意到的是,当我运行Lambda函数时,行"正文:(收据数据)"出现,其中(收据数据)是我发送给函数的基本64位编码数据。这让我怀疑我根本没有到达错误回调块,并且该错误与我将回调结果发送回我的应用程序的方式有关。这块是什么:
var req = https.request(options, function(res) {
res.setEncoding('utf8');
res.on('data', function (chunk) {
console.log("body: " + chunk);
cb(true, chunk);
});
res.on('error', function (error) {
console.log("error: " + error);
cb(false, error);
});
});
应该怎么做?是否有可能我需要启用一些权限来接收回调?
答案 0 :(得分:1)
对于后来发现这一点的人来说,潜在的问题:
Content-Type
不正确。你需要发布JSON,而不是url编码;当代码执行此操作时,它使用错误的类型来告诉服务器它使用的格式。它应该是application/json
而不是application/x-www-form-urlencoded
。.endLineWithLineFeed
让我怀疑。status
为21007
,则代码应该针对沙盒服务器尝试相同的收据。一旦收据被解码和验证,客户端就可以检查收据,看看它被验证的服务器和(如有必要)忽略沙箱收据。答案 1 :(得分:0)
最终我通过跟随this示例并使用Python而不是Node.js解决了这个问题。我之前仍然不知道我的代码到底出了什么问题,但是在Swift中使用base-64编码然后将收据数据和密码发送到Python Lambda函数给了我正确的结果。
答案 2 :(得分:0)
在你的Swift代码中,你检查"如果task.error!= nil"然后你有一个错误
cb(true, chunk);
但是在您的节点代码中,您可以通过以下方式调用回调:
cb(null, chunk);
第一个参数是你的错误,它不会是零。你应该用以下代码替换这一行:
{{1}}
你将以这种方式获得正确的Json
答案 3 :(得分:0)
这对我有用:
'use strict'
var AWS = require('aws-sdk')
var https = require('https')
exports.handler = (event, context, callback) => {
var payload = JSON.stringify({
'receipt-data': event.arguments.input.base64_receipt
})
function generateOptions(url) {
return {
host: url,
port: 443,
path: '/verifyReceipt',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': Buffer.byteLength(payload)
}
}
}
function validateReceipt(url, payload, errorCallback) {
var req = https.request(generateOptions(url), function(res) {
res.setEncoding('utf8')
res.on('data', function(chunk) {
var data = JSON.parse(chunk)
// success
callback(null, event)
})
res.on('error', function(error) {
//error
errorCallback ? errorCallback() : callback('There was an error validating the transaction', event)
})
})
req.write(payload)
req.end()
}
// attempt to validate on production and sandbox
validateReceipt('buy.itunes.apple.com', payload, function() {
validateReceipt('sandbox.itunes.apple.com', payload)
})
}