Google内购完成后,服务端需要校验订单的状态是否正确(是否已经成功付款)。
一、申请认证
参考https://developers.google.cn/android-publisher/getting_started申请流程
-
进入Google控制台,选择开发者者账号登陆
-
设置API权限(默认未开通,点击开通即可,然后创建一个新的项目)。
-
创建一个Google Cloud平台服务账号
-
创建秘钥,选择json格式
-
添加将刚刚注册的那个服务账号为新用户,关联对应的app,授予以下权限
二、服务端校验订单
服务端校验订单要准备以下内容:
- 第一步申请到的认证凭据
- 用户成功付款之后,客户端传递给服务端的相关订单信息,消息如下
{
"packageName": "xxx", # 应用包名
"purchaseState": 0, # 付款状态,0为已购买
"orderId": "GPA.xxxxxx", # 订单ID
"purchaseTime": xx, # 付款时间
"productId": "001", # 产品ID
"quantity": 1, # 数量
"purchaseToken": "xxxxx" # Token,可用于后续的验证
接下来根据purchases.products 这个API来查询订单状态。这是一个Rest API,接下来使用python来请求
# pip3 install oauth2client google-api-python-client
import httplib2, json
from pprint import pprint
from oauth2client.service_account import ServiceAccountCredentials
packageName = "xxx"
productId = "xxx"
token = "xxx"
URL = f"https://androidpublisher.googleapis.com/androidpublisher/v3/applications/{packageName}/purchases/products/{productId}/tokens/{token}"
credentials = ServiceAccountCredentials.from_json_keyfile_name(
"google-sa.json", # 使用上面申请到的凭据
scopes="https://www.googleapis.com/auth/androidpublisher",
)
# 注意需要能访问到google,这里开了代理
http = httplib2.Http(proxy_info=httplib2.ProxyInfo(httplib2.socks.PROXY_TYPE_SOCKS5, '127.0.0.1', 7890))
http = credentials.authorize(http)
resp, content = http.request(URL, "GET")
pprint(json.loads(content))
返回结果如下,一般我们就是验证purchaseState
是否为0,对于消耗性的内购应用,验证consumptionState
字段是否为1
{
"acknowledgementState": 1,
"consumptionState": 1,
"developerPayload": "", # 如果有透传我们自定义的字段,例如自己系统的订单ID,这里会显示
"kind": "androidpublisher#productPurchase",
"orderId": "GPA.xxx",
"purchaseState": 0,
"purchaseTimeMillis": "xxx",
"purchaseType": 0,
"regionCode": "US"
}
完整的返回字段说明参考purchases.products/acknowledge
{
"kind": string,
"purchaseTimeMillis": string,
"purchaseState": integer,
"consumptionState": integer,
"developerPayload": string,
"orderId": string,
"purchaseType": integer,
"acknowledgementState": integer,
"purchaseToken": string,
"productId": string,
"quantity": integer,
"obfuscatedExternalAccountId": string,
"obfuscatedExternalProfileId": string,
"regionCode": string
}