前言

前段时间在公司负责与Android对接了Google Play支付,国内大部分的文章都是介绍前端(APP)的对接,后端的处理讲解少之又少,所以决定整理出来。

本篇只会介绍Google Play中一次性商品的对接,订阅类商品没有接触过,但是差别应该只在最后的订阅扣费(看了一下文档瞎猜的),前面大部分应该都是两者共同需要的。

如果你的业务机器是海外服务器,可以直接连通谷歌的服务,那么我建议你简单阅读本篇,了解大概流程之后直接上谷歌提供的SDK,非常的方便。

如果你跟我一样,是国内的服务器,但是不得不使用谷歌服务,可以跟我一样全程自己撸码,然后使用 transmit 等技术在另一台海外机器中做代理。

账号配置

Google Play 绑定

首先,要触发 Google API ConsoleGoogle Play Console 触发绑定。

我尝试了2个账号,发现绑定的唯一方法,是在 Google Play Console 中触发生成 OAuth 凭证,此时会跳转到 Google API Console 中,若当前项目的名称,变成有 Google Play 字样,则为绑定成功。

001

注: 后续的操作,务必要在 Google Play 的项目中完成,否则调用 API 的时候会提示未于 Google Play 进行绑定

启用 API

点击 "库" 或者 "+启用API和服务" , 搜索 androidpublisher , 点击进去并进行启用

004

005

生成后端使用的凭证

网域验证

这个没什么好说的,根据谷歌的指引走,配置一下 DNS ,一下子就可以弄好

OAuth 同意屏幕设置

这里设置主要需要注意配置好 已授权网域,用于 OAuth 中设置 callback url

002

创建新的 OAuth 凭证

选择 “Web 应用” 进行 OAuth 凭证创建,设置好重定向URI并且为刚才设置的 已授权网域 下的URI

003

获取 refresh token

refresh token 很关键,是用于后端生成 access_token 的唯一凭证,生成之后必须妥善保管。

参考文档: https://developers.google.com/android-publisher/authorization#generating_a_refresh_token

首先,构建url,直接在浏览器访问,然后登陆Google账号并授权允许。 之后就会携带参数跳转到指定的重定向URI

https://accounts.google.com/o/oauth2/auth?client_id={你的OAuth client id}&scope={授权范围}&response_type=code&redirect_uri={重定向URI}&access_type=offline

注意,access_type=offline 是必须的,如果不带这个,将不会生成出 refresh_token
内购需要的授权范围为 https://www.googleapis.com/auth/androidpublisher ,如果你有其他的业务需要授权(如推送相关的 Firebase 服务,则需要使用英文空格进行分隔)。 完整例子如下:

https://accounts.google.com/o/oauth2/auth?client_id=我的CLIENT不给你看&scope=https://www.googleapis.com/auth/firebase.messaging&response_type=code&redirect_uri=http://mywebsite.com/myuri&access_type=offline

授权完成后,谷歌会携带参数跳转到你的重定向URI中。其中包含了最重要 code 字段,拿这个 code 去进行下一步操作,获取 refresh_token

HTTP POST

URL:
https://accounts.google.com/o/oauth2/token

POST BODY:
code:刚才拿到的code值
client_id:OAuth 凭证中的 client_id
client_secret:OAuth 凭证中的 client_secret
redirect_uri:跟上一个url构建中的重定向uri一致
grant_type:authorization_code

请求完成后,会返回 json respond ,例:

{
"access_token" : "ya29.ZStBkRnGyZ2mUYOLgls7QVBxOg82XhBCFo8UIT5gM",
"token_type" : "Bearer",
"expires_in" : 3600,
"refresh_token" : "1/zaaHNytlC3SEBX7F2cfrHcqJEa3KoAHYeXES6nmho"
}

请务必妥善保管好 refresh_token ,以免泄漏。

获取 access_token

使用上一步获取到的 refresh_token ,通过 HTTP POST 获取 access_token

HTTP POST
    
URL:

https://accounts.google.com/o/oauth2/token

POST BODY:

grant_type:refresh_token
client_id:OAuth 凭证中的 client_id
client_secret:OAuth 凭证中的 client_secret
refresh_token:上一步拿到的 refresh_token

请求成功后,在 json respond 中可以拿到 access_token,且有过期时间。

{
  "access_token" : "ya29.AHES3ZQ_MbZCwac9TBWIbjW5ilJkXvLTeSl530Na2",
  "token_type" : "Bearer",
  "expires_in" : 3600,
}

支付流程

获取用户支付订单信息

接口文档: https://developers.google.com/android-publisher/api-ref/purchases/products/get

当用户在 APP 中完成支付后,前端可以从谷歌手上拿到一个 token ,该 token 上报给后端服务可以用来查询订单状态,并进行订单消费处理。

具体的请求说明可以参考文档,这里给出一个完整的例子:

HTTP GET

URL:

https://www.googleapis.com/androidpublisher/v3/applications/安卓apk包名/purchases/products/在谷歌后台定义的商品id/tokens/安卓上报的token?access_token=上一步拿到的access_token

https://www.googleapis.com/androidpublisher/v3/applications/{$packageName}/purchases/products/{$productId}/tokens/{$token}?access_token={$accessToken}

请求成功后,在 json respond 中,获取到订单信息,具体内容说明可以查看文档: https://developers.google.com/android-publisher/api-ref/purchases/products#resource-representations
其中有以下几个比较重要:

purchaseState : 仅为 0 时,为已支付状态
acknowledgementState : 是否已确认。 确认操作可以由后端接口处理,下一步会介绍到

consumptionState : 是否已核销,商品核销只能由安卓处理,务必与安卓沟通好,确认 acknowledgementState 为 1 的时候才进行核销处理。 如果一次性商品不及时进行核销,用户无法操作第二次购买。

developerPayload : 载荷用于下一步的确认操作,请妥善保管。

purchaseType : 该字段有三个值,非必传字段,具体可以看文档。 比较重要的是为0时是沙箱(超级账号)支付,用户实际上是没有付款的。

orderId : 谷歌订单号,必须妥善保管

确认订单

上一步中拿到的 developerPayload , 可以用于确认订单。一个订单只能确认一次,确认之后无法再次操作。 可以作为服务端确认凭证。

例如,我们有一个游戏装备商品,用户支付后,安卓上报 token ,后端确认 token ,记录好订单信息、做完业务处理之后处理确认订单,安卓再次跟谷歌确认订单是否为已确认(即acknowledgementState=1),然后安卓做装备发放处理并核销订单(即consumptionState=1),完成一次消费。

接口文档 : https://developers.google.com/android-publisher/api-ref/purchases/products/acknowledge

HTTP POST

URL:
https://www.googleapis.com/androidpublisher/v3/applications/{$packageName}/purchases/products/{$productId}/tokens/{$token}:acknowledge?access_token={$accessToken}

POST BODY:
developerPayload:上一步中拿到的 developerPayload

请求成功后,HTTP 状态码为 204 ,没有 respond

至此,一次商品购买就完成了,辛苦了!

订单退款

// todo

说点废话

四月的小目标终于完成了... 本来想着写一篇有关 JWT 的使用介绍和demo的,但是突然公司这边谷歌内购的任务下来,就想着赶紧趁热把本篇撸出来了。 其实我还对接了 Firebase 的推送服务,也可以单独拉出来讲一讲。但是其实 Firebase 的对接也差不多内样,只是在 API Authorise 有一点坑,因为有几个接口谷歌都没有做更新,都是用的老版本,我苦读英文读了很长时间才搞懂... 其他就都还好,跟 Apple 的 APNS 差不了太多。