谷歌Google Play内购支付后端指南
2023-12-05 :
谷歌内购相关流程今时不同往日,本文大部分内容对比实际情况已经产生偏离,请谨慎参考!
2021-08-19 10:22 更新
今天公司项目进行迁移了,所以更新几张图片,整理流程没有变化
2021-05-18 16:06 更新
最近好多人来问怎么对接谷歌的接口。
如果贵项目服务器是在海外,我建议是直接使用谷歌的SDK。
如果跟我一样,项目服务器在国内,需要代理,那么就必须自己编写请求。
我把我的代码整理了出来,供大家参考,方便快速入手谷歌API对接,希望可以对您有所帮助。
https://github.com/Lichmaker/google-api-demo/blob/main/GoogleIAPService.php
文章内有一些图片,因为谷歌的更新,UI有变化,所以看起来会不一样。但是流程大致上没什么变化。
前言
前段时间在公司负责与Android对接了Google Play支付,国内大部分的文章都是介绍前端(APP)的对接,后端的处理讲解少之又少,所以决定整理出来。
本篇只会介绍Google Play中一次性商品的对接,订阅类商品没有接触过,但是差别应该只在最后的订阅扣费(看了一下文档瞎猜的),前面大部分应该都是两者共同需要的。
如果你的业务机器是海外服务器,可以直接连通谷歌的服务,那么我建议你简单阅读本篇,了解大概流程之后直接上谷歌提供的SDK,非常的方便。
如果你跟我一样,是国内的服务器,但是不得不使用谷歌服务,可以跟我一样全程自己撸码,然后使用 代理转发 等技术在另一台海外机器中做代理。
账号配置
与 Google Play
绑定
首先,要触发 Google API Console
和 Google Play Console
触发绑定。
我尝试了2个账号,发现绑定的唯一方法,是在 Google Play Console
中触发生成 OAuth 凭证,此时会跳转到 Google API Console
中,若当前项目的名称,变成有 Google Play
字样,则为绑定成功。
注: 后续的操作,务必要在 Google Play
的项目中完成,否则调用 API 的时候会提示未于 Google Play
进行绑定
启用 API
点击 "库" 或者 "+启用API和服务" , 搜索 androidpublisher
, 点击进去并进行启用
生成后端使用的凭证
网域验证
这个没什么好说的,根据谷歌的指引走,配置一下 DNS ,一下子就可以弄好
OAuth 同意屏幕设置
这里设置主要需要注意配置好 已授权网域
,用于 OAuth 中设置 callback url
创建新的 OAuth 凭证
选择 “Web 应用” 进行 OAuth 凭证创建,设置好重定向URI并且为刚才设置的 已授权网域
下的URI
获取 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 差不了太多。
本作品采用 知识共享署名-相同方式共享 4.0 国际许可协议 进行许可。
AndroidPublisher.Purchases.Products.Consume consumeProduct = publisher.purchases().products().consume(dto.getPackageName(), dto.getProductId(), dto.getPurchaseToken()),调用谷歌的商品消耗接口,再次查询的时候仍然是未消耗状态 0 ,有遇到这种情况的吗?
大佬,要接入Google paly应用内商品购买,需要申请Google Pay API吗?
请问下客户端支付成功,有没有可以通过谷歌平台回调给商户java后端服务器的通知
您好,Google Cloud Platform里有一个Pub/Sub订阅模块,可以订阅相关的topic,然后可以收到对应的消息。 但是我对这块了解不多,建议可以看一下类似的文章参考一下 : https://juejin.cn/post/7186943152261955643
好的
请教下,文档看了,我们业务是安卓APP接入google内购。比如安卓应用内支付完成后发送或者google通知我服务器,我要获取订单信息需要access_token,那是不是用户必须要通过google先登录?
我的问题是如果用户直接用googleplay下载app用其他方式登录,那app支付成功了是不是也没法去获取google的access_token
已经看懂了
感觉大佬 ,参考这个配合google sdk搞定了
当用户在 APP 中完成支付后,前端可以从谷歌手上拿到一个 token,这个是怎么支付的呀
用户支付完成之后, 前端从谷歌手上拿到的token, 丢给后端与谷歌进行核销处理。
嗯嗯 了解。只是想知道用户的支付相关接口
谷歌退单有回调么
https://developer.android.com/google/play/billing/rtdn-reference?hl=zh-cn#one-time
有购买成功和取消购买的
想问下谷歌的api有没有获取用户实际支付金额的啊
没有,因为商品的金额都是固定设置好的。所以对于订单来说,订单金额就是 商品的金额 * 购买数量 。
实际操作后发现 应该是有各种平台优惠的叠加 使得支付金额和订单和金额并不相同 这种情况没有办法得到用户真实支付的金额么
找到办法了吗,我也遇到这个问题
找到办法了吗,我也遇到这个问题
您指的是促销活动和promo相关么? 这块我确实没怎么了解过非常抱歉 :( 。 但是我能找到谷歌这边的文档,希望有帮助 https://developer.android.com/google/play/billing/promo
服务器成功拿到access_token,但调用purchases.products.get时,返回401错误:The current user has insufficient permissions to perform the requested operation
配置好之后,能定时成功拿到access_token,但在据AccessToken来验证订单时,google返回了错误信息,具体如下:
Method: purchases.products.get
"code": 401, "message": "The current user has insufficient permissions to perform the requested operation.", "errors": [ { "domain": "androidpublisher", "message": "The current user has insufficient permissions to perform the requested operation.", "reason": "permissionDenied" } ]我使用purchase_token和access_token拼成get请求,后google发起请求:
https://androidpublisher.googleapis.com/androidpublisher/v3/applications/{GooglePlay_App_PackageName}/purchases/products/{product_id}/tokens/{Purchase_token}?access_token={AccessToken},
google返回如下错误:
"error": {
}
}
请问可能是哪里配置错误,或是有别的什么解决方案,期待你们的帮助,谢谢
The current user has insufficient permissions to perform the requested operation.
这个一般是在 refresh_token 生成环节,跳转到Google登陆进行授权时,是否了非管理员账号进行授权导致的。
只要更换成管理员账号,重新进行一次 refresh_token 生成就可以解决问题。
直接使用谷歌的SDK,还需要申请assess_token吗?
没使用过谷歌的SDK.. 但我之前看过文档,印象中SDK是会自己维护这个access_token的过期
你好,这个查询订单提示需要登录是什么问题
您是指 https://androidpublisher.googleapis.com/androidpublisher/v3/applications/{packageName}/purchases/products/{productId}/tokens/{token} 这个接口吗? 具体是返回了什么错误码呢?
是的,提示401, "message": "Request is missing required authentication credential. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project.",
我也出现了这个问题,请问 问题解决了吗
我也出现了这个问题,请问 问题解决了吗
我也出现了这个问题,请问 问题解决了吗
一般是acceess_token不正确导致的
需要先拿到 access_token , 然后组成参数。
例如这样:
$url = "https://www.googleapis.com/androidpublisher/v3/applications/{$packageName}/purchases/products/{$productId}/tokens/{$token}?access_token={$accessToken}";
最后再GET这个url
是的,就是这样,请问你那边不会有这个问题么?
请问大神,现在我用token来查询订单信息,能返回订单号,但是developerPayload却返回为空,导致没法进行下一步订单确认,请问这个developerPayload怎样才会返回正常呢?
你好,请问你指的是这个里的 developerPayload 吗 https://developers.google.com/android-publisher/api-ref/rest/v3/purchases.products#resource:-productpurchase
是的,现在已经知道这个字段谷歌已经废弃掉了,谢谢大神的回复呢
你好,可以请教一下你是如何解决的吗? 我查阅过谷歌的文档,被弃用的developerPayload是在Android APK内的,应该跟服务端API内无关才对
更新了一个demo~ 供大家参考 https://github.com/Lichmaker/google-api-demo/blob/main/GoogleIAPService.php
秃头了,大佬可以联系下 指导一下吗?
邮箱或者微信都可以找到我~
https://www.wuguozhang.com/about-me.html
感谢大佬啊,搞得可头秃了
楼上搞定了没?