iOS In-App Purchase(IAP)内购服务端二次验证注意事项
前端iOS完成对应的商品购买之后,会得到一个Transaction(交易)的数据结构指针,后端实际上只需要这个结构内的一个东西,那就是 transaction.transactionReceipt。
前端将它进行Base64编码之后,再请求后端的HTTP接口就行了,我这里着重讲一下后端需要做的一些事情。
首先,拿到这个Base64的字符串之后,不用任何修改,只需要将它原封不动的请求给苹果的验证接口就行了,下面是一个HTTP请求构造信息:
请求地址:
测试:https://sandbox.itunes.apple.com/verifyReceipt
正式:https://buy.itunes.apple.com/verifyReceipt
请求方式:
HTTP POST
Header:
Content-Type: application/json
请求的Body:
{
"receipt-data":"...接收到的Base64字符串..."
}
返回的响应信息(删减版):
{
"status": 0
"receipt": {
"bundle_id": "iOS应用标识,需要做校验。",
"in_app": [
{
"transaction_id": "1000000XXXXXXXXX(未结束的交易ID)",
"product_id": "xxxxxxx(购买的产品ID,用于映射到底买了哪些东西)"
},
...more...
]
}
}
Q/A问答
Q1:我该请求哪一个地址呢?
A1:如果不想设置什么状态标识,简单点不管三七二十一,直接请求正式版本的地址,如果在测试环境,返回给你的数据的status字段会为21007,只要检查这个值再次请求测试版本的链接即可。
Q2:我如何得到购买的产品信息呢?
A2:注意返回数据的receipt.in_app是一个数组,里面保存了所有未结束的交易,每一笔交易内,都会有一个product_id用于自行映射相关的产品信息,这个信息的获取不用我说了吧,你想放到哪里都可以。
Q3:如何防止重复的交易造成多次购买呢?比如客户端使用一个Base64的参数请求了多次?
A3:注意返回数据的receipt.in_app是一个数组,里面保存了所有未结束的交易,每一笔交易内,都会有一个transaction_id用以唯一标识这个交易。我们可以在我们自己的数据库内将这个字段设置为唯一索引,这样的话,当你重复插入相同的transaction_id的时候,会触发异常,只要根据这个异常进行数据回滚或者简单的忽略掉这个交易就行了。
Q4:后端因当返回什么样的数据给前端,让前端结束交易呢?否则的话,recetpt.in_app这个数组内的值将会无限制累加?
A4:因为receipt.in_app里面保存了不止一笔交易,因此当后端循环这个数据处理完毕之后,应当将处理之后的transaction_id进行收集,然后以列表的形式返回给前端,前端收到这个数据之后,传递给SDK,然后结束交易即可。需要注意的是,哪怕有一笔交易在我们的数据库中是重复的,也要将这个重复的transaction_id一起返回给前端,好让前端能够结束掉这笔交易,否则的话将会一直存在,不停的处理这个case。
Q5:如何处理漏单的情况?比如前端支付完毕之后,因为网络或者其他原因没有请求后端进行处理。
A5:虽然我不是前端,看了一下苹果的文档之后发现,只要在应用启动时监听支付Queue,苹果会调用你的处理函数,再次进行处理,因为存在可能漏单的情况,因此后端的接口一定要具备幂等(防重,可多次调用)。重复的校验上面A3已经回答了。需要注意的是,不止是后端可能会没有接收到来自前端的请求,也有可能后端处理完毕之后前端已经关闭,因此无法结束处理完毕的交易。只要前端能够在启动APP的时候得到SDK的回调,再次请求一下后端进行处理就行了。