關(guān)于查看google play退款訂單的前提,首先,需要獲取Google API的訪問權(quán)限,從獲取API訪問權(quán)限上來看,大致分為兩種方法,第一種是通過OAuth 客戶端訪問,需要客戶端用戶來授權(quán),才能獲取Google API的訪問權(quán)限,然后進(jìn)行用戶訂單詳情的查詢,第二種是不需要用戶來授權(quán)的,我相信這種方法也是服務(wù)端比較喜歡的,畢竟用戶授權(quán)這種事情你是沒辦法確定能拿到權(quán)限的。對(duì)于代表非人類機(jī)器人運(yùn)行的服務(wù)器應(yīng)用(如持續(xù)集成系統(tǒng)),建議使用服務(wù)帳號(hào)。對(duì)于直接代表人類用戶運(yùn)行的客戶端應(yīng)用(如 IDE 插件),則可以使用 OAuth 客戶端。我目前的項(xiàng)目比較適合服務(wù)賬號(hào),所以,這里我們就只介紹第二種方法,利用google play開發(fā)者賬號(hào)建立服務(wù)賬號(hào),直接對(duì)其授權(quán),然后再進(jìn)行對(duì)Google API的訪問。
前言
這篇文章我們從創(chuàng)建 Google Play 開發(fā)者帳號(hào)說起,因?yàn)槲易罱鼮榱薵oogle退款訂單詳情的查詢踩了不少的坑,也許是英語太差,所以為了更好的理解和開發(fā)google退款的流程,我盡量詳細(xì)介紹,每一個(gè)參數(shù)。全憑自己理解,不喜勿噴,歡迎大神指點(diǎn)批評(píng)。
1. 創(chuàng)建賬號(hào)以及關(guān)聯(lián)API服務(wù)
首先我們需要有 Google Play 開發(fā)者帳號(hào),這個(gè)賬號(hào)首先你要有自己的google賬號(hào),然后到Google Play Console進(jìn)行開發(fā)者賬號(hào)的注冊(cè)開通,這里是需要支付 $25 的注冊(cè)費(fèi)用的,注冊(cè)完成之后就要?jiǎng)?chuàng)建新的API項(xiàng)目(就是創(chuàng)建一個(gè)你的應(yīng)用項(xiàng)目):
在 Google Play 管理中心轉(zhuǎn)到 API 訪問權(quán)限頁面。
接受服務(wù)條款。
點(diǎn)擊創(chuàng)建新項(xiàng)目。
如果您已是 Google Play Developer API 的用戶,則可以執(zhí)行以下這些步驟來關(guān)聯(lián)到您現(xiàn)有的 API 項(xiàng)目。如果您想關(guān)聯(lián)的 API 項(xiàng)目未列出,請(qǐng)確認(rèn)您的 Google Play 管理中心帳號(hào)是否已指定為“所有者”,且 Google Play Developer API 已啟用。
在 Google Play 管理中心轉(zhuǎn)到 API 訪問權(quán)限頁面。
接受 API 服務(wù)條款。
選擇您想關(guān)聯(lián)的項(xiàng)目。
點(diǎn)擊關(guān)聯(lián)。
到這里您的 Google Play 管理中心現(xiàn)已關(guān)聯(lián)到 API 項(xiàng)目。一般開始寫退款接口的時(shí)候google賬號(hào)都已經(jīng)是部署好的了應(yīng)該,所以前面的步驟這里就不細(xì)說了
2. 創(chuàng)建服務(wù)賬號(hào)
上邊已經(jīng)創(chuàng)建項(xiàng)目并且也關(guān)聯(lián)了API,下面就可以直接
1.在 Google Play 管理中心轉(zhuǎn)到 API 訪問權(quán)限頁面。
2.點(diǎn)擊開發(fā)者賬號(hào)
3.點(diǎn)擊API權(quán)限
4.點(diǎn)擊創(chuàng)建服務(wù)賬號(hào),按照頁面上的說明創(chuàng)建您的服務(wù)帳號(hào)。
5.在 Google Developers Console 中創(chuàng)建服務(wù)帳號(hào)后,請(qǐng)點(diǎn)擊完成。API 訪問權(quán)限頁面會(huì)自動(dòng)刷新,您的服務(wù)帳號(hào)將隨即列出。
創(chuàng)建服務(wù)賬號(hào).jpg
6.創(chuàng)建完服務(wù)賬號(hào)需要生成一下密鑰,公鑰生成.json格式或者P12文件都行,我這里用的時(shí).json文件,后面代碼中要用到
6.在用戶和權(quán)限頁面可以看到剛創(chuàng)建的服務(wù)賬號(hào),接下來只要進(jìn)行授權(quán)就可以使用了
設(shè)置賬號(hào)的訪問權(quán)限.jpg
3. 調(diào)用Google API查詢退款訂單詳情
到了這一步就開始寫接口了,我這里用的是Spring boot+cloud的框架,下面就不做解釋了,首先調(diào)用google API需要引入依賴:
<dependency>
<groupId>com.google.apis</groupId>
<artifactId>google-api-services-androidpublisher</artifactId>
<version>v3-rev95-1.25.0</version>
</dependency>
然后就是服務(wù)賬號(hào)如何獲取訪問google API的權(quán)限,經(jīng)過我的個(gè)人理解和google官方文檔總結(jié)了一下,把整個(gè)代碼給摘分開來了,第一部分是獲取服務(wù)賬號(hào)訪問權(quán)限,創(chuàng)建一個(gè)訪問谷歌api的GoogleCredential 相當(dāng)于一個(gè)權(quán)限令牌
private GoogleCredential getAndroidPublisherScopesOfGoogleCredential()throws Exception{
//這里是建立服務(wù)賬號(hào)后生成的.json文件,這里這樣寫需要把.json文件放到相應(yīng)模塊的resources下,想要換一個(gè)目錄可以隨意,但不要忘了改文件路徑
ClassPathResource classPathResource = new ClassPathResource("xxx-xxxx-xxxxxx.json");
GoogleCredential credential = GoogleCredential.fromStream(classPathResource.getInputStream())
.createScoped(AndroidPublisherScopes.all());//createScoped給令牌訪問權(quán)限設(shè)置使用的權(quán)限范圍
if(credential!=null){
return credential;
}else{
throw new Exception("Get GoogleCredential fails");
}
}
因?yàn)槲倚枰{(diào)用的接口在AndroidPublisher下,所以這里的權(quán)限范圍設(shè)置成了AndroidPublisherScopes.all(),這里的具體API權(quán)限范圍需要自己去查閱相關(guān)文檔進(jìn)行了解,這里不再詳細(xì)說明。
上面拿到了令牌,下面就build一個(gè)要調(diào)用的google api的對(duì)應(yīng)工具類
private AndroidPublisher getAndroidPublisher()throws Exception{
GoogleCredential credential = this.getAndroidPublisherScopesOfGoogleCredential();
NetHttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport();//其中這兩個(gè)參數(shù)最終也沒去搞明白,不知道具體的用處,目測(cè)可能是調(diào)用googleAPI發(fā)送請(qǐng)求用的
JacksonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance();//
return new AndroidPublisher.Builder(httpTransport, JSON_FACTORY, credential).build();
}
拿到了我們要用的工具類后,下面就可以調(diào)用接口了,下面這個(gè)接口是我在google官方文檔找的,具體連接是:https://developers.google.com/android-publisher/api-ref/purchases/voidedpurchases/list
下面的代碼中會(huì)經(jīng)常用到一個(gè)參數(shù)com.cn.aaaa是項(xiàng)目的完全限定軟件包名稱,就是應(yīng)用名稱下面的灰色小字,根據(jù)自己的設(shè)置進(jìn)行填寫
/**
* 獲取所有退款訂單的PurchaseToken(google 采購成功的唯一標(biāo)識(shí))
* @return
* @throws Exception
*/
private List<VoidedPurchase> getPurchaseToken()throws Exception{
boolean isExistData = true;
AndroidPublisher publisher = this.getAndroidPublisher();
AndroidPublisher.Purchases.Voidedpurchases voidedpurchases = publisher.purchases().voidedpurchases();
//后面還可以跟.setMaxResults 設(shè)置返回結(jié)果最大值默認(rèn)1000 .setToken查詢更多結(jié)果時(shí)設(shè)置(下一頁nextPageToken)
AndroidPublisher.Purchases.Voidedpurchases.List refundInfo = voidedpurchases.list("com.cn.aaaa");
VoidedPurchasesListResponse refundList = refundInfo.execute();//執(zhí)行調(diào)用動(dòng)作,返回結(jié)果
List<VoidedPurchase> voidedPurchases = refundList.getVoidedPurchases();
//獲取分頁token,若退款訂單當(dāng)前頁沒有傳完,則返回參數(shù)中會(huì)有NextPageToken,用來循環(huán)請(qǐng)求下一頁的退款訂單
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;
}
這里終于拿到了您的應(yīng)用中所有的產(chǎn)生退款的訂單的PurchaseToken,具體的返回參數(shù)解釋官方文檔卻比較詳細(xì),可以用上面的連接進(jìn)行查閱,但是這個(gè)返回結(jié)果中除了PurchaseToken并沒有訂單號(hào),而可恨的是我們的庫里面根本沒有存google的這個(gè)采購成功的唯一標(biāo)識(shí)PurchaseToken,然后我就繼續(xù)開始翻google的官網(wǎng)文檔終于找到了一個(gè)不太方便的方法,目前我只能找到這一個(gè)解決辦法。(有那位大神知道其他的簡(jiǎn)單的方法的話,求指教,留言)
/**
* 獲取所有退款訂單詳情
* @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("您的應(yīng)用在google中設(shè)置的產(chǎn)品ID");
......
list.add("您的應(yīng)用在google中設(shè)置的產(chǎn)品ID");
//這里之所以寫這個(gè)list是因?yàn)槲覀冎荒玫搅薖urchaseToken,但調(diào)用GET產(chǎn)品詳情的接口參數(shù)中包括這一訂單的產(chǎn)品ID,
//但是我們并不知道哪個(gè)訂單是退款訂單,更不知道是買的那個(gè)產(chǎn)品被退款,所以這里只能拿所有產(chǎn)品ID進(jìn)行輪詢
for (String id : list) {
AndroidPublisher.Purchases.Products.Get products = publisher.purchases().products().get(pakgeName, id, purchaseToken);
try {
//這里的詳細(xì)返回參數(shù)解釋查看官方文檔:[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) {
//這里在異常中處理是因?yàn)楫?dāng)參數(shù)中的product ID與PurchaseToken代表的訂單的product ID不一致時(shí)會(huì)拋錯(cuò),所以在這里捕捉后進(jìn)行后續(xù)處理
String error = e.getMessage();
if (error.indexOf("The purchase token does not match the product ID") > 0) {
log.warn("產(chǎn)品ID與Token中的不一致");
}else{
log.error("查詢退款訂單詳情異常:{}",error);
}
}
}
}
return MessageResult.success(infoList);
}
到這里就已經(jīng)結(jié)束了,退款訂單的所有詳情已獲取。
注:對(duì)于googleAPI的調(diào)用,必須放到國外的服務(wù)器進(jìn)行接口的調(diào)用,否則國內(nèi)的網(wǎng)絡(luò)無法聯(lián)通,其他任何方法不適用