Android Google Play 服務(wù)器驗(yàn)證

概要: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ì)解釋:

GooglePlay 訂單校驗(yàn)過(guò)程.png

官方地址:https://developer.android.com/google/play/billing/billing_library_overview .png

前提

  • Google Api
  • Google Play Console
  • 測(cè)試App程序
  • 最好使用自己應(yīng)用內(nèi)創(chuàng)建的商品(不建議使用Google提供的測(cè)試商品)

Google 文檔:Google Play Developer APIApi使用入門

Google Api

由于這里是向Google服務(wù)器驗(yàn)證,需要使用調(diào)用相關(guān)的 Google Api 進(jìn)行相關(guān)操作 :


Google Play Developer API使用.png

這里我選擇的是 OAuth客戶端 ,OAuth客戶端需要在Google Play Console ---> 設(shè)置 -----> 開(kāi)發(fā)者賬號(hào) -----> Api 權(quán)限 進(jìn)行創(chuàng)建,如下圖:

OAuth客戶端.png

創(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添加即可如下圖:

OAuth同意屏幕.png

添加憑據(jù),并添加


image.png

注意,右側(cè)下載按鈕,下載出來(lái)的json,包含后續(xù)所需要的參數(shù),如下圖:


下載的json包含憑據(jù)全部信息json.png
1,獲取授權(quán) Api 調(diào)用

OAuth 2.0 for Mobile & Desktop Apps 官網(wǎng)地址

授權(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

  1. 頁(yè)面訪問(wèn)url后,首先需要進(jìn)行授權(quán):


    授權(quán)頁(yè)面.png
  2. 確認(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ō)明了傳參以及示例。

refresh_token.png

注意:參數(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)接口

Api - Purchases.products官方地址

到這里,才是真正的調(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è)試商品。

附:https://github.com/paihuai00/GooglePayTest

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容