关于查看google play退款订单的前提,首先,需要获取Google API的访问权限,从获取API访问权限上来看,大致分为两种方法,第一种是通过OAuth 客户端访问,需要客户端用户来授权,才能获取Google API的访问权限,然后进行用户订单详情的查询,第二种是不需要用户来授权的,我相信这种方法也是服务端比较喜欢的,毕竟用户授权这种事情你是没办法确定能拿到权限的。对于代表非人类机器人运行的服务器应用(如持续集成系统),建议使用服务帐号。对于直接代表人类用户运行的客户端应用(如 IDE 插件),则可以使用 OAuth 客户端。我目前的项目比较适合服务账号,所以,这里我们就只介绍第二种方法,利用google play开发者账号建立服务账号,直接对其授权,然后再进行对Google API的访问。
前言
这篇文章我们从创建 Google Play 开发者帐号说起,因为我最近为了google退款订单详情的查询踩了不少的坑,也许是英语太差,所以为了更好的理解和开发google退款的流程,我尽量详细介绍,每一个参数。全凭自己理解,不喜勿喷,欢迎大神指点批评。
1. 创建账号以及关联API服务
首先我们需要有 Google Play 开发者帐号,这个账号首先你要有自己的google账号,然后到Google Play Console进行开发者账号的注册开通,这里是需要支付 $25 的注册费用的,注册完成之后就要创建新的API项目(就是创建一个你的应用项目):
- 在 Google Play 管理中心转到 API 访问权限页面。
- 接受服务条款。
- 点击创建新项目。
如果您已是 Google Play Developer API 的用户,则可以执行以下这些步骤来关联到您现有的 API 项目。如果您想关联的 API 项目未列出,请确认您的 Google Play 管理中心帐号是否已指定为“所有者”,且 Google Play Developer API 已启用。
- 在 Google Play 管理中心转到 API 访问权限页面。
- 接受 API 服务条款。
- 选择您想关联的项目。
- 点击关联。
到这里您的 Google Play 管理中心现已关联到 API 项目。一般开始写退款接口的时候google账号都已经是部署好的了应该,所以前面的步骤这里就不细说了
2. 创建服务账号
上边已经创建项目并且也关联了API,下面就可以直接
1.在 Google Play 管理中心转到 API 访问权限页面。
2.点击开发者账号
3.点击API权限
4.点击创建服务账号,按照页面上的说明创建您的服务帐号。
5.在 Google Developers Console 中创建服务帐号后,请点击完成。API 访问权限页面会自动刷新,您的服务帐号将随即列出。
6.创建完服务账号需要生成一下密钥,公钥生成.json格式或者P12文件都行,我这里用的时.json文件,后面代码中要用到
6.在用户和权限页面可以看到刚创建的服务账号,接下来只要进行授权就可以使用了
3. 调用Google API查询退款订单详情
到了这一步就开始写接口了,我这里用的是Spring boot+cloud的框架,下面就不做解释了,首先调用google API需要引入依赖:
<dependency>
<groupId>com.google.apis</groupId>
<artifactId>google-api-services-androidpublisher</artifactId>
<version>v3-rev95-1.25.0</version>
</dependency>
然后就是服务账号如何获取访问google API的权限,经过我的个人理解和google官方文档总结了一下,把整个代码给摘分开来了,第一部分是获取服务账号访问权限,创建一个访问谷歌api的GoogleCredential 相当于一个权限令牌
private GoogleCredential getAndroidPublisherScopesOfGoogleCredential()throws Exception{
//这里是建立服务账号后生成的.json文件,这里这样写需要把.json文件放到相应模块的resources下,想要换一个目录可以随意,但不要忘了改文件路径
ClassPathResource classPathResource = new ClassPathResource("xxx-xxxx-xxxxxx.json");
GoogleCredential credential = GoogleCredential.fromStream(classPathResource.getInputStream())
.createScoped(AndroidPublisherScopes.all());//createScoped给令牌访问权限设置使用的权限范围
if(credential!=null){
return credential;
}else{
throw new Exception("Get GoogleCredential fails");
}
}
因为我需要调用的接口在AndroidPublisher下,所以这里的权限范围设置成了AndroidPublisherScopes.all(),这里的具体API权限范围需要自己去查阅相关文档进行了解,这里不再详细说明。
上面拿到了令牌,下面就build一个要调用的google api的对应工具类
private AndroidPublisher getAndroidPublisher()throws Exception{
GoogleCredential credential = this.getAndroidPublisherScopesOfGoogleCredential();
NetHttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport();//其中这两个参数最终也没去搞明白,不知道具体的用处,目测可能是调用googleAPI发送请求用的
JacksonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance();//
return new AndroidPublisher.Builder(httpTransport, JSON_FACTORY, credential).build();
}
拿到了我们要用的工具类后,下面就可以调用接口了,下面这个接口是我在google官方文档找的,具体连接是:https://developers.google.com/android-publisher/api-ref/purchases/voidedpurchases/list
下面的代码中会经常用到一个参数com.cn.aaaa是项目的完全限定软件包名称,就是应用名称下面的灰色小字,根据自己的设置进行填写
/**
* 获取所有退款订单的PurchaseToken(google 采购成功的唯一标识)
* @return
* @throws Exception
*/
private List<VoidedPurchase> getPurchaseToken()throws Exception{
boolean isExistData = true;
AndroidPublisher publisher = this.getAndroidPublisher();
AndroidPublisher.Purchases.Voidedpurchases voidedpurchases = publisher.purchases().voidedpurchases();
//后面还可以跟.setMaxResults 设置返回结果最大值默认1000 .setToken查询更多结果时设置(下一页nextPageToken)
AndroidPublisher.Purchases.Voidedpurchases.List refundInfo = voidedpurchases.list("com.cn.aaaa");
VoidedPurchasesListResponse refundList = refundInfo.execute();//执行调用动作,返回结果
List<VoidedPurchase> voidedPurchases = refundList.getVoidedPurchases();
//获取分页token,若退款订单当前页没有传完,则返回参数中会有NextPageToken,用来循环请求下一页的退款订单
TokenPagination tokenPagination = refundList.getTokenPagination();
while (isExistData) {
if(tokenPagination!=null){
AndroidPublisher.Purchases.Voidedpurchases.List nextRefundInfo = voidedpurchases.list("com.cn.aaaa").setToken(tokenPagination.getNextPageToken());
VoidedPurchasesListResponse nextRefundLists = nextRefundInfo.execute();
List<VoidedPurchase> nextVoidedPurchasess = nextRefundLists.getVoidedPurchases();
tokenPagination = nextRefundLists.getTokenPagination();
voidedPurchases.addAll(nextVoidedPurchasess);
}else{
isExistData = false;
}
}
return voidedPurchases;
}
这里终于拿到了您的应用中所有的产生退款的订单的PurchaseToken,具体的返回参数解释官方文档却比较详细,可以用上面的连接进行查阅,但是这个返回结果中除了PurchaseToken并没有订单号,而可恨的是我们的库里面根本没有存google的这个采购成功的唯一标识PurchaseToken,然后我就继续开始翻google的官网文档终于找到了一个不太方便的方法,目前我只能找到这一个解决办法。(有那位大神知道其他的简单的方法的话,求指教,留言)
/**
* 获取所有退款订单详情
* @return
* @throws Exception
*/
public MessageResult getOrder() throws Exception {
List<VoidedPurchase> purchaseTokenList = this.getPurchaseToken();
String pakgeName = "com.cn.aaaa";
List<ProductPurchase> infoList = new ArrayList<>();
for(VoidedPurchase voidedPurchase : purchaseTokenList) {
String purchaseToken = voidedPurchase.getPurchaseToken();
AndroidPublisher publisher = this.getAndroidPublisher();
List<String> list = new ArrayList<>();
list.add("您的应用在google中设置的产品ID");
......
list.add("您的应用在google中设置的产品ID");
//这里之所以写这个list是因为我们只拿到了PurchaseToken,但调用GET产品详情的接口参数中包括这一订单的产品ID,
//但是我们并不知道哪个订单是退款订单,更不知道是买的那个产品被退款,所以这里只能拿所有产品ID进行轮询
for (String id : list) {
AndroidPublisher.Purchases.Products.Get products = publisher.purchases().products().get(pakgeName, id, purchaseToken);
try {
//这里的详细返回参数解释查看官方文档:[https://developers.google.com/android-publisher/api-ref/inappproducts/get](https://developers.google.com/android-publisher/api-ref/inappproducts/get)
ProductPurchase info = products.execute();
if(info!=null){
infoList.add(info);
}
} catch (Exception e) {
//这里在异常中处理是因为当参数中的product ID与PurchaseToken代表的订单的product ID不一致时会抛错,所以在这里捕捉后进行后续处理
String error = e.getMessage();
if (error.indexOf("The purchase token does not match the product ID") > 0) {
log.warn("产品ID与Token中的不一致");
}else{
log.error("查询退款订单详情异常:{}",error);
}
}
}
}
return MessageResult.success(infoList);
}
到这里就已经结束了,退款订单的所有详情已获取。
注:对于googleAPI的调用,必须放到国外的服务器进行接口的调用,否则国内的网络无法联通,其他任何方法不适用