概要:Google 建議在完成支付后依據(jù)服務(wù)器返回訂單結(jié)果為準(zhǔn)所以才有了這篇文章。本文針對(duì)訂單支付完成后 驗(yàn)證購(gòu)買交易 過(guò)程、踩坑記錄。開(kāi)始前,先有一個(gè)大致的過(guò)程,流程圖大概說(shuō)明了 向Google服務(wù)器驗(yàn)證訂單的過(guò)程,其中具體的過(guò)程下文會(huì)詳細(xì)解釋:
前提
- Google Api
- Google Play Console
- 測(cè)試App程序
- 最好使用自己應(yīng)用內(nèi)創(chuàng)建的商品(不建議使用Google提供的測(cè)試商品)
Google 文檔:Google Play Developer API、Api使用入門
Google Api
由于這里是向Google服務(wù)器驗(yàn)證,需要使用調(diào)用相關(guān)的 Google Api 進(jìn)行相關(guān)操作 :
這里我選擇的是 OAuth客戶端 ,OAuth客戶端需要在Google Play Console ---> 設(shè)置 -----> 開(kāi)發(fā)者賬號(hào) -----> Api 權(quán)限 進(jìn)行創(chuàng)建,如下圖:
創(chuàng)建完成后,點(diǎn)擊 在Google Developers Console中查看 , 進(jìn)入到 Api 控制臺(tái) ,需要新建項(xiàng)目,創(chuàng)建項(xiàng)目完成,點(diǎn)擊 OAuth同意屏幕 配置驗(yàn)證信息,比如:我使用到了../androidpublisher
Api添加即可如下圖:
添加憑據(jù),并添加
注意,右側(cè)下載按鈕,下載出來(lái)的json,包含后續(xù)所需要的參數(shù),如下圖:
1,獲取授權(quán) Api 調(diào)用
授權(quán)接口:https://accounts.google.com/o/oauth2/v2/auth
調(diào)用,這里解釋一下 必填 參數(shù)(全部可以參考上面鏈接查看)
參數(shù) | 解釋 |
---|---|
client_id | api控制臺(tái)獲取,上圖也有 |
redirect_uri | api控制臺(tái)獲取,上圖也有,比如:urn:ietf:wg:oauth:2.0:oob
|
response_type | 固定值:code 。(確定Google OAuth 2.0端點(diǎn)是否返回授權(quán)碼。code為已安裝的應(yīng)用程序設(shè)置參數(shù)值。) |
scope | 我這里填入的是:https://www.googleapis.com/auth/androidpublisher 。范圍指的是應(yīng)用程序可以訪問(wèn)的Api范圍,附:OAuth2.0 Api范圍
|
這里的的接口,需要在瀏覽器調(diào)用 (需要你的Google賬號(hào)進(jìn)行授權(quán)) ,例如我在瀏覽器調(diào)用下面的接口(需要將里面的id參數(shù)替換為自己的參數(shù)):
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
-
頁(yè)面訪問(wèn)url后,首先需要進(jìn)行授權(quán):
授權(quán)頁(yè)面.png -
確認(rèn)選擇、結(jié)果頁(yè)面
確認(rèn)選擇頁(yè)面.png
結(jié)果頁(yè)面.png
上面的結(jié)果,就是下面所需要的 code 值,注意,這里調(diào)用一次,保存在項(xiàng)目即可,不需要每次都進(jìn)行該步驟!?。?!坑?。?p>
2,獲取access_token api調(diào)用
post 請(qǐng)求: https://www.googleapis.com/oauth2/v4/token
參數(shù) | 解釋 |
---|---|
code |
https://accounts.google.com/o/oauth2/v2/auth 接口返回的值,就是上面授權(quán)后獲得的值 |
client_id | api控制臺(tái)獲取,上面也有 |
client_secret | api控制臺(tái)獲取,上面json中也有 |
redirect_uri | api控制臺(tái)獲取,上面也有,比如:urn:ietf:wg:oauth:2.0:oob
|
grant_type | 固定值:authorization_code
|
比如我的網(wǎng)絡(luò)請(qǐng)求,請(qǐng)求成功返回結(jié)果如下:
/**
* 獲取access_token : 每個(gè)請(qǐng)求,都需要拼接到后面,例如:?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后臺(tái)拿到
.addParams("redirect_uri",redirect_uri) //GoogleApi后臺(tái)拿到
.addParams("grant_type","authorization_code")//固定值
.addParams("code",code)//上面獲取,只需要調(diào)用一次
.addParams("client_secret",client_secret)////GoogleApi后臺(tái)拿到
.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) {
//返回的結(jié)果都在 response 包含
Log.d(TAG, "onResponse: ");//返回,GoogleAccsessTokenBean.java 相關(guān)內(nèi)容
}
});
********************** 返回結(jié)果 ***********************************
/**
* 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,下面會(huì)解釋refresh_token用途
- 這里返回的
access_token
就是每次調(diào)用Api,需要拼接的參數(shù)?。?!坑,這個(gè)access_token
必須正確(不然會(huì)報(bào)400 401錯(cuò)誤)!!
refresh_token
測(cè)試階段過(guò)了一會(huì)發(fā)現(xiàn)接口無(wú)法調(diào)通,排查發(fā)現(xiàn)原因是Token過(guò)期了(應(yīng)該沒(méi)到token過(guò)期時(shí)間,返回的過(guò)期時(shí)間是3600s不知道怎么回事~~有點(diǎn)懵逼-_- ),重新查閱文檔發(fā)現(xiàn),上面調(diào)用https://www.googleapis.com/oauth2/v4/token
接口返回的 refresh_token
是調(diào)用 刷新Token 接口(兩個(gè)是同一個(gè)接口只不過(guò)傳參不同)。
具體解釋見(jiàn)下圖(網(wǎng)頁(yè)翻譯了一下)具體說(shuō)明了傳參以及示例。
注意:參數(shù)
grant_type
的值變成了refresh_token
小結(jié):
上面通過(guò)Google Play Console、Google API 控制臺(tái),生成OAuth2客戶端,主要是為了驗(yàn)證授權(quán)用戶,對(duì)于我們來(lái)說(shuō)就是為了獲取 code、access_token、refresh_token ,為調(diào)用下面的 校驗(yàn)接口 做鋪墊。
注意,坑!?。。。?/strong>
- code:獲取需要網(wǎng)頁(yè)打開(kāi),需用戶登錄Google賬號(hào)授權(quán),code值生成一次,保存在項(xiàng)目即可!
- access_token :獲取需要使用上面獲得的code,不然各種401 404錯(cuò)誤。
- 接口請(qǐng)求如果出現(xiàn)問(wèn)題,請(qǐng)認(rèn)真仔細(xì)對(duì)比 接口參數(shù) 是否有誤!
Google Play 校驗(yàn)接口
到這里,才是真正的調(diào)用 校驗(yàn)接口,這個(gè)接口提供了兩個(gè)方法,不過(guò)返回值都一樣,先說(shuō)一下返回值代表意義
{
"kind": "androidpublisher#productPurchase",
"purchaseTimeMillis": long,
"purchaseState": integer,
"consumptionState": integer,
"developerPayload": string,
"orderId": string,
"purchaseType": integer,
"acknowledgementState": integer
}
參數(shù) | 類型 | 解釋 |
---|---|---|
kind | String | 這種類型代表androidpublisher服務(wù)中的inappPurchase對(duì)象。 |
purchaseTimeMillis | long | 購(gòu)買產(chǎn)品的時(shí)間,自紀(jì)元(1970年1月1日)以來(lái)的毫秒數(shù)。 |
purchaseState | integer | 訂單的購(gòu)買狀態(tài); 0:購(gòu)買 1:取消 2:掛起(待支付) |
developerPayload | String | 開(kāi)發(fā)人員指定的字符串,包含有關(guān)訂單的補(bǔ)充信息。 |
orderId | String | 與購(gòu)買inapp產(chǎn)品相關(guān)聯(lián)的訂單ID。 |
purchaseType | integer | 購(gòu)買inapp產(chǎn)品的類型。僅當(dāng)未使用標(biāo)準(zhǔn)應(yīng)用內(nèi)結(jié)算流程進(jìn)行此購(gòu)買時(shí),才會(huì)設(shè)置此字段。可能的值是:0. 測(cè)試(即從許可證測(cè)試帳戶購(gòu)買)1. 促銷(即使用促銷代碼購(gòu)買)2. 獎(jiǎng)勵(lì)(即觀看視頻廣告而非付費(fèi)) |
acknowledgementState | integer | inapp產(chǎn)品的確認(rèn)狀態(tài)。0:待確認(rèn) 1:已確認(rèn) |
consumptionState | integer | inapp消費(fèi)狀態(tài)。0:未消費(fèi) 1:已消費(fèi) |
Acknowledge - 確認(rèn)購(gòu)買了一個(gè)inapp項(xiàng)目。
1,調(diào)用確認(rèn)接口前,需要調(diào)用授權(quán)接口(其實(shí)就是需要傳入授權(quán)的access_token
)
post 請(qǐng)求: https://www.googleapis.com/auth/androidpublisher
該接口需要傳遞參數(shù)
參數(shù) | 類型 | 解釋 |
---|---|---|
developerPayload | String | 有效負(fù)載附加到購(gòu)買,該值在 商品詳情 會(huì)有返回 |
access_token | String | 授權(quán)token,上面獲得的token |
2,然后調(diào)用 確認(rèn)授權(quán)接口
POST https://www.googleapis.com/androidpublisher/v3/applications/你的應(yīng)用包名/purchases/products/商品id/tokens/商品token:acknowledge
這個(gè)請(qǐng)求,需要注意替換三個(gè)地方,上面我也標(biāo)記出來(lái)了, 包名、商品的productId、token(這里指的是商品購(gòu)買返回的商品token) 注意后面有一個(gè):acknowledge
, 還需要加上 參數(shù):access_token
Get - 檢查inapp項(xiàng)目購(gòu)買和消費(fèi)狀態(tài)
1,需要調(diào)用授權(quán)接口(其實(shí)就是需要傳入授權(quán)的access_token
)
https://www.googleapis.com/auth/androidpublisher
2,Get方法調(diào)用 ,檢查inapp項(xiàng)目的購(gòu)買和消費(fèi)狀態(tài)接口
Get方法 https://www.googleapis.com/androidpublisher/v3/applications/你的應(yīng)用包名/purchases/products/商品id/tokens/商品token
這個(gè)請(qǐng)求,需要注意替換三個(gè)地方,上面我也標(biāo)記出來(lái)了, 包名、商品的productId、token(這里指的是商品購(gòu)買返回的商品token) 注意不同于上面,后面沒(méi)acknowledge, 還需要加上參數(shù): access_token。
總結(jié):
服務(wù)器驗(yàn)證這步驟,折騰了好久,開(kāi)始一直是接口調(diào)用不通(400 401錯(cuò)誤),中間也是沒(méi)少踩坑,如果出問(wèn)題請(qǐng)仔細(xì)檢查下面幾項(xiàng)
- 配置檢測(cè),如:自己的應(yīng)用包名是否跟Google Play Console 一致、Google Api Oauth創(chuàng)建等配置是否有誤。
- 接口參數(shù),如:Google Api 后臺(tái)獲取的
client_id、secret_id
是否正確,是否授權(quán)獲取到code(僅調(diào)一次,保存即可),接口調(diào)用是否傳遞了access_token
以及是否過(guò)期 - 如果校驗(yàn)步驟遇到400(接口返回信息: Invalid Value),建議去查一下購(gòu)買的商品在Google Play Console 上是否處于 有效 狀態(tài),不要使用Google提供的訂單測(cè)試商品。