Python Google内购服务端验证

Google内购完成后,服务端需要校验订单的状态是否正确(是否已经成功付款)。

一、申请认证

参考https://developers.google.cn/android-publisher/getting_started申请流程

  1. 进入Google控制台,选择开发者者账号登陆

  2. 设置API权限(默认未开通,点击开通即可,然后创建一个新的项目)。

  3. 创建一个Google Cloud平台服务账号

  4. 创建秘钥,选择json格式

  5. 添加将刚刚注册的那个服务账号为新用户,关联对应的app,授予以下权限

二、服务端校验订单

服务端校验订单要准备以下内容:

  1. 第一步申请到的认证凭据
  2. 用户成功付款之后,客户端传递给服务端的相关订单信息,消息如下
    1
    2
    3
    4
    5
    6
    7
    8
    {
    "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来请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 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

1
2
3
4
5
6
7
8
9
10
11
{
"acknowledgementState": 1,
"consumptionState": 1,
"developerPayload": "", # 如果有透传我们自定义的字段,例如自己系统的订单ID,这里会显示
"kind": "androidpublisher#productPurchase",
"orderId": "GPA.xxx",
"purchaseState": 0,
"purchaseTimeMillis": "xxx",
"purchaseType": 0,
"regionCode": "US"
}

完整的返回字段说明参考purchases.products/acknowledge

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{
"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
}