google play 退款订单详情获取

关于查看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项目(就是创建一个你的应用项目):

  1. 在 Google Play 管理中心转到 API 访问权限页面。
  2. 接受服务条款。
  3. 点击创建新项目

如果您已是 Google Play Developer API 的用户,则可以执行以下这些步骤来关联到您现有的 API 项目。如果您想关联的 API 项目未列出,请确认您的 Google Play 管理中心帐号是否已指定为“所有者”,且 Google Play Developer API 已启用。

  1. 在 Google Play 管理中心转到 API 访问权限页面。
  2. 接受 API 服务条款。
  3. 选择您想关联的项目。
  4. 点击关联

到这里您的 Google Play 管理中心现已关联到 API 项目。一般开始写退款接口的时候google账号都已经是部署好的了应该,所以前面的步骤这里就不细说了

2. 创建服务账号

上边已经创建项目并且也关联了API,下面就可以直接
1.在 Google Play 管理中心转到 API 访问权限页面。
2.点击开发者账号
3.点击API权限
4.点击创建服务账号,按照页面上的说明创建您的服务帐号。
5.在 Google Developers Console 中创建服务帐号后,请点击完成API 访问权限页面会自动刷新,您的服务帐号将随即列出。

创建服务账号.jpg

6.创建完服务账号需要生成一下密钥,公钥生成.json格式或者P12文件都行,我这里用的时.json文件,后面代码中要用到
6.在用户和权限页面可以看到刚创建的服务账号,接下来只要进行授权就可以使用了
设置账号的访问权限.jpg

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的调用,必须放到国外的服务器进行接口的调用,否则国内的网络无法联通,其他任何方法不适用

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容

  • 本篇文章是官网中文版。有外网的小伙伴可以直接访问官网地址和代码示例 https://developer.andro...
    钢镚koala阅读 3,657评论 0 0
  • 什么是Google Play? 受国内政策影响,大部分android用户是没有接触过google play的。Go...
    空同定翁阅读 4,814评论 5 10
  • 简述 公司业务出海接入 google play支付渠道时,往往不知道该如何在google play侧配置。业务在g...
    空同定翁阅读 11,438评论 3 7
  • 十里乡村一日走,菜花逊比美人愁。铁牛俯首迎宾客,欢喜肥鹅结伴游。 注:战友小李,绝佳美女,难得闲暇,一日之旅,乡村...
    孙悟空也姓孙阅读 403评论 3 8
  • 天空乌云密布 灰暗,沉闷 压得人喘不上气来 在这样的天气中 树木青翠也难以遮掩地 蒙上灰白的憔悴 海浪烦躁地拍打着...
    柒珩阅读 367评论 1 2