概要:Google 建议在完成支付后依据服务器返回订单结果为准所以才有了这篇文章。本文针对订单支付完成后 验证购买交易 过程、踩坑记录。开始前,先有一个大致的过程,流程图大概说明了 向Google服务器验证订单的过程,其中具体的过程下文会详细解释:
前提
- Google Api
- Google Play Console
- 测试App程序
- 最好使用自己应用内创建的商品(不建议使用Google提供的测试商品)
Google 文档:Google Play Developer API、Api使用入门
Google Api
由于这里是向Google服务器验证,需要使用调用相关的 Google Api 进行相关操作 :
这里我选择的是 OAuth客户端 ,OAuth客户端需要在Google Play Console ---> 设置 -----> 开发者账号 -----> Api 权限 进行创建,如下图:
创建完成后,点击 在Google Developers Console中查看 , 进入到 Api 控制台 ,需要新建项目,创建项目完成,点击 OAuth同意屏幕 配置验证信息,比如:我使用到了../androidpublisher
Api添加即可如下图:
添加凭据,并添加
注意,右侧下载按钮,下载出来的json,包含后续所需要的参数,如下图:
1,获取授权 Api 调用
OAuth 2.0 for Mobile & Desktop Apps 官网地址
授权接口:https://accounts.google.com/o/oauth2/v2/auth
调用,这里解释一下 必填 参数(全部可以参考上面链接查看)
参数 | 解释 |
---|---|
client_id | api控制台获取,上图也有 |
redirect_uri | api控制台获取,上图也有,比如:urn:ietf:wg:oauth:2.0:oob |
response_type | 固定值:code 。(确定Google OAuth 2.0端点是否返回授权码。code为已安装的应用程序设置参数值。) |
scope | 我这里填入的是:https://www.googleapis.com/auth/androidpublisher 。范围指的是应用程序可以访问的Api范围,附:OAuth2.0 Api范围 |
这里的的接口,需要在浏览器调用 (需要你的Google账号进行授权) ,例如我在浏览器调用下面的接口(需要将里面的id参数替换为自己的参数):
https://accounts.google.com/o/oauth2/v2/auth?client_id=你的id&redirect_uri=urn:ietf:wg:oauth:2.0:oob&response_type=code&scope=https://www.googleapis.com/auth/androidpublisher
-
页面访问url后,首先需要进行授权:
-
确认选择、结果页面
上面的结果,就是下面所需要的 code 值,注意,这里调用一次,保存在项目即可,不需要每次都进行该步骤!!!!坑!!
2,获取access_token api调用
post 请求: https://www.googleapis.com/oauth2/v4/token
参数 | 解释 |
---|---|
code | https://accounts.google.com/o/oauth2/v2/auth 接口返回的值,就是上面授权后获得的值 |
client_id | api控制台获取,上面也有 |
client_secret | api控制台获取,上面json中也有 |
redirect_uri | api控制台获取,上面也有,比如:urn:ietf:wg:oauth:2.0:oob |
grant_type | 固定值:authorization_code |
比如我的网络请求,请求成功返回结果如下:
/**
* 获取access_token : 每个请求,都需要拼接到后面,例如:?access_token=xxxxx
*/
String tokenUrl = "https://accounts.google.com/o/oauth2/token";
String code = "4/qQFrmvbxm5hEnXPxiBz-LYoFAf4kIqHhHvmn2CfaeI_2kq3bqtPYnUs";
String client_secret = "rlCm_3T2zOitkOA6cS4TDR_P";
OkHttpUtils.post().url(tokenUrl)
.addParams("client_id",cliendId) //GoogleApi后台拿到
.addParams("redirect_uri",redirect_uri) //GoogleApi后台拿到
.addParams("grant_type","authorization_code")//固定值
.addParams("code",code)//上面获取,只需要调用一次
.addParams("client_secret",client_secret)////GoogleApi后台拿到
.build().execute(new StringCallback() {
@Override
public void onError(Call call, Exception e, int id) {
Log.d(TAG, "onError: ");
}
@Override
public void onResponse(String response, int id) {
//返回的结果都在 response 包含
Log.d(TAG, "onResponse: ");//返回,GoogleAccsessTokenBean.java 相关内容
}
});
********************** 返回结果 ***********************************
/**
* access_token : ya29.GltyB1aAtM7QEz0T0GVtNZk64bXldamoCWU32us0fe2zD8HvBNW3LMig4-T2p3EAc4oDfozqa6ZHIaNfCC19KFk4qFhPwAniSzy2r7OeunPHx8P6tzCwjKA1_H4F
* expires_in : 3600
* refresh_token : 1/ZSenrx4IL5iUnyA_P0TjDG9GpY6xENpEIv4LeQeo3mg
* scope : https://www.googleapis.com/auth/androidpublisher
* token_type : Bearer
*/
注意:
- 这里需要保存 access_token、refresh_token,下面会解释refresh_token用途
- 这里返回的
access_token
就是每次调用Api,需要拼接的参数!!!坑,这个access_token
必须正确(不然会报400 401错误)!!
refresh_token
测试阶段过了一会发现接口无法调通,排查发现原因是Token过期了(应该没到token过期时间,返回的过期时间是3600s不知道怎么回事~~有点懵逼-_- ),重新查阅文档发现,上面调用https://www.googleapis.com/oauth2/v4/token
接口返回的 refresh_token
是调用 刷新Token 接口(两个是同一个接口只不过传参不同)。
具体解释见下图(网页翻译了一下)具体说明了传参以及示例。
注意:参数
grant_type
的值变成了refresh_token
小结:
上面通过Google Play Console、Google API 控制台,生成OAuth2客户端,主要是为了验证授权用户,对于我们来说就是为了获取 code、access_token、refresh_token ,为调用下面的 校验接口 做铺垫。
注意,坑!!!!:
- code:获取需要网页打开,需用户登录Google账号授权,code值生成一次,保存在项目即可!
- access_token :获取需要使用上面获得的code,不然各种401 404错误。
- 接口请求如果出现问题,请认真仔细对比 接口参数 是否有误!
Google Play 校验接口
Api - Purchases.products官方地址
到这里,才是真正的调用 校验接口,这个接口提供了两个方法,不过返回值都一样,先说一下返回值代表意义
{
"kind": "androidpublisher#productPurchase",
"purchaseTimeMillis": long,
"purchaseState": integer,
"consumptionState": integer,
"developerPayload": string,
"orderId": string,
"purchaseType": integer,
"acknowledgementState": integer
}
参数 | 类型 | 解释 |
---|---|---|
kind | String | 这种类型代表androidpublisher服务中的inappPurchase对象。 |
purchaseTimeMillis | long | 购买产品的时间,自纪元(1970年1月1日)以来的毫秒数。 |
purchaseState | integer | 订单的购买状态; 0:购买 1:取消 2:挂起(待支付) |
developerPayload | String | 开发人员指定的字符串,包含有关订单的补充信息。 |
orderId | String | 与购买inapp产品相关联的订单ID。 |
purchaseType | integer | 购买inapp产品的类型。仅当未使用标准应用内结算流程进行此购买时,才会设置此字段。可能的值是:0. 测试(即从许可证测试帐户购买)1. 促销(即使用促销代码购买)2. 奖励(即观看视频广告而非付费) |
acknowledgementState | integer | inapp产品的确认状态。0:待确认 1:已确认 |
consumptionState | integer | inapp消费状态。0:未消费 1:已消费 |
Acknowledge - 确认购买了一个inapp项目。
1,调用确认接口前,需要调用授权接口(其实就是需要传入授权的access_token
)
post 请求: https://www.googleapis.com/auth/androidpublisher
该接口需要传递参数
参数 | 类型 | 解释 |
---|---|---|
developerPayload | String | 有效负载附加到购买,该值在 商品详情 会有返回 |
access_token | String | 授权token,上面获得的token |
2,然后调用 确认授权接口
POST https://www.googleapis.com/androidpublisher/v3/applications/你的应用包名/purchases/products/商品id/tokens/商品token:acknowledge
这个请求,需要注意替换三个地方,上面我也标记出来了, 包名、商品的productId、token(这里指的是商品购买返回的商品token) 注意后面有一个:acknowledge
, 还需要加上 参数:access_token
Get - 检查inapp项目购买和消费状态
1,需要调用授权接口(其实就是需要传入授权的access_token
)
https://www.googleapis.com/auth/androidpublisher
2,Get方法调用 ,检查inapp项目的购买和消费状态接口
Get方法 https://www.googleapis.com/androidpublisher/v3/applications/你的应用包名/purchases/products/商品id/tokens/商品token
这个请求,需要注意替换三个地方,上面我也标记出来了, 包名、商品的productId、token(这里指的是商品购买返回的商品token) 注意不同于上面,后面没acknowledge, 还需要加上参数: access_token。
总结:
服务器验证这步骤,折腾了好久,开始一直是接口调用不通(400 401错误),中间也是没少踩坑,如果出问题请仔细检查下面几项
- 配置检测,如:自己的应用包名是否跟Google Play Console 一致、Google Api Oauth创建等配置是否有误。
- 接口参数,如:Google Api 后台获取的
client_id、secret_id
是否正确,是否授权获取到code(仅调一次,保存即可),接口调用是否传递了access_token
以及是否过期 - 如果校验步骤遇到400(接口返回信息: Invalid Value),建议去查一下购买的商品在Google Play Console 上是否处于 有效 状态,不要使用Google提供的订单测试商品。
附:https://github.com/paihuai00/GooglePayTest