Google Pay主要支付流程:
1.手机端向服务端发起支付,生成预订单,给手机端返回生成的订单号
2.手机端向Google发起支付(传入本地服务器生成的订单号)
3.Google服务器将支付结果返回给手机端(因这边用到的是消耗型的产品,所以购买后必须要通知gp我已经消耗了这次交易)
4.手机端向服务端发送校验请求,校验通过后即可处理订单(服务端重试校验,发货,保证订单正常发货成功)
当客户端支付成功后,客户端将支付订单的token 传给服务端,服务端进行再次校验,服务端校验订单有两种方式:
1.引入google apis 调取Google Api 进行验证
2.直接调用Google 提供的API接口去验证
两种验证方式都需要一些配置和相应参数,下面具体讲解
验证方式 一 : 引入google apis 调取Google Api 进行验证
developer文档地址:https://developers.google.com/identity/protocols/oauth2/service-account?hl=zh-cn#delegatingauthority
1.去Google Play Console 选择设置中的API 权限:https://play.google.com/console/u/0/developers/6365974680746954105/api-access
2.第一次进来没有 Google Play Console Developer,这个时候就需要去Google Cloud Platform 后台创建服务账号.首先去Google Cloud 后台https://console.cloud.google.com/ 搜索:Google Play Console Developer 点击启用即可,然后去创建服务账号:
到这里就把Google Play Console Developer创建好了,最后一步也拿到了对应的json了
3.回到Google Play Console 后台 把刚才创建的Google Play Console Developer的服务账号也加入到用户和权限中
然后将服务账号权限,可以直接给管理员admin permission 也可以给 财务权限:
点击API权限中的 查看Play管理中心权限,可以查看应用权限和账号权限,切记要给与对应Project的permission
4.上面三步Google Play Console Developer的环境配置好了,下面就开始实现服务端订单的校验了,Java服务端处理
首先将google apis 接入到项目:
<project>
<dependencies>
<dependency>
<groupId>com.google.apis</groupId>
<artifactId>google-api-services-androidpublisher</artifactId>
<version>v3-rev20211125-1.32.1</version>
</dependency>
</dependencies>
</project>
校验代码:
@RestController
public class GoogleController {
// packageName为应用程序包名、productId商品id、purchaseToken谷歌返回的收据
@PostMapping("/")
public ProductPurchase checkOrder(@RequestBody GooglePayDto googlePayDto,
HttpServletRequest requestDto) throws IOException, GeneralSecurityException {
//使用服务帐户Json文件获取Google凭据
List<String> scopes = new ArrayList<>();
scopes.add(AndroidPublisherScopes.ANDROIDPUBLISHER);
ResourceLoader resourceLoader = new DefaultResourceLoader();
Resource resource = resourceLoader.getResource("classpath:static/刚下载的json文件,这里放到了static目录下");
GoogleCredential credential = GoogleCredential.fromStream(resource.getInputStream())
.createScoped(scopes);
// 使用谷歌凭据和收据从谷歌获取购买信息
HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport();
JacksonFactory jsonFactory = new JacksonFactory();
AndroidPublisher publisher = new AndroidPublisher.Builder(httpTransport, jsonFactory, credential)
.setApplicationName("应用程序名").build();
AndroidPublisher.Purchases purchases = publisher.purchases();
final AndroidPublisher.Purchases.Products.Get request = purchases.products().get(googlePayDto.getPackageName(), googlePayDto.getProductId(),googlePayDto.getPurchaseToken());
System.out.println("==============="+request+"================");
final ProductPurchase purchase = request.execute();
//处理业务
Integer purchaseState = purchase.getPurchaseState();
if (!GooglePayStatus.PURCHASED.getValue().equals(purchaseState) &&!GoogleConsumptionStatus.YET_TO_BE_CONSUMED.getValue().equals(purchase.getConsumptionState())) {
log.info("==========>订单校验【成功】");
} else {
log.info("==========>订单校验【失败】");
}
return purchase;
}
}
public class GooglePayDto {
String packageName;
String productId;
String purchaseToken;
public String getPackageName() {
return packageName;
}
public void setPackageName(String packageName) {
this.packageName = packageName;
}
public String getProductId() {
return productId;
}
public void setProductId(String productId) {
this.productId = productId;
}
public String getPurchaseToken() {
return purchaseToken;
}
public void setPurchaseToken(String purchaseToken) {
this.purchaseToken = purchaseToken;
}
}
最后开始Test:
传入三个参数
packageName:包名
productId:商品id
purchaseToken:支付凭证
运行结果:
验证方式 二 : 使用API接口直接验证,developer文档地址:https://developers.google.com/android-publisher/authorization?hl=zh-cn
整体步骤:
-
创建api项目这个和登录用的项目不是同一个
-
开启Google Play Android Developer API
-
设置oauth同意屏幕(就是拉起开发者授权账号登录时的登录页面)
-
创建web应用的oauth客户端ID
-
google play开发者后台,API权限菜单中关联刚刚创建的项目,一个google play账号只需要也只能关联一个api项目就行了,这个项目可以查询关联账号中的所有应用的订单
-
拉起授权页面,使用google开发者账号给项目授权,得到code
-
通过code,拿到refreshToken,这个token只有第一次才会返回需要永久储存(这个refreshtoken很重要,需要保存下来),如果弄丢,只有重新创建一个oauth客户端ID,然后重复步骤6,7,拿到新的refreshtoken
-
刷新refreshToken, 得到accessToken,通过accesstoken就可以去查询订单状态了,这里的accessToken一般只有5分钟左右,5分钟后需要重新用refreshToken换取新的accessToken
详细步骤:setp1:
setp2:开启Google Play Android Developer API
搜索“Google Play Android Developer API”,并开启
setp3:开启OAuth同意屏幕
setp4 : 创建OAuth 客户端ID:
创建页面和创建成功后的修改页面可以获取到clientId和clientSecret:
到这里api项目就已经创建好了
setp5: Google Play 后台关联API项目:
setp6:获取code
地址:https://accounts.google.com/o/oauth2/auth?scope=https://www.googleapis.com/auth/androidpublisher&response_type=code&access_type=offline&redirect_uri={填写的重定向地址}&client_id={创建的clientId}
将上面的{XX}替换成创建api项目时填写的重定向地址,和clientId,然后将连接放到浏览器中打开,就会吊起授权界面,使用你的开发者账号授权登录
请求方式:浏览器中打开 授权,URL会重定向,这个时候可以拿到code:
这里可以看到,重定向地址上有两个参数code和scope,我们只需要code就行了,这里的code是urlencode后的,使用时需要decode
setp7:使用code获取refreshToken 这一步可以用Postman发起一个post请求:
url:https://accounts.google.com/o/oauth2/token
请求方式:post
参数:grant_type=authorization_code
code=获取到的code(需要看看code中是否有%号,如果有需要urldecode)
client_id=创建api项目是的clientId(客户端ID)
client_secret=创建api项目时的clientSecret(客户端密钥)
redirect_uri=创建api项目时的重定向地址
这里就获取到refreshToken了,重点重点重点,refreshToken保存下来,它只会在第一次请求中返回,后续用在发一样的请求不会返回refreshtoken,如果不慎弄丢了,需要去重新创建一个WebClientId ,这里切记哈
如果后续再次调用这个接口结果为:
Step 8:使用refreshToken获取accessToken
地址:https://accounts.google.com/o/oauth2/token
请求方式:post
参数:grant_type=refresh_token
refresh_token=刚刚获取到的refreshToken
client_id=创建api项目是的clientId(客户端ID)
client_secret=创建api项目时的clientSecret(客户端密钥)
setp9:这一步也是最后一步了 就是查询订单状态:
查询订单状态
https://androidpublisher.googleapis.com/androidpublisher/v3/applications/{packageName}/purchases/products/{productId}/tokens/{token}?access_token={access_token}
packageName:app包名,必须是创建登录api项目时,创建android客户端Id使用包名
productId:对应购买商品的商品ID
token:购买成功后Purchase对象的getPurchaseToken()
access_token:上面咋们获取到的accessToken
请求方式:get
返回值解释:
{
"purchaseTimeMillis": "16239806",//购买产品的时间,自纪元(1970 年 1 月 1 日)以来的毫秒数。
"purchaseState": 0,//订单的购买状态。可能的值为:0. 已购买 1. 已取消 2. 待定
"consumptionState": 0,//产品的消费状态。可能的值为: 0. 尚未消耗 1. 已消耗
"developerPayload": "",
"orderId": "GPA.XXXXXXX8",//google订单号 "purchaseType": 0,
"acknowledgementState": 0,
"kind": "androidpublisher#productPurchase",
"obfuscatedExternalAccountId": "SDK2106180944530041",//上面客户支付时的透传字段,google指导是用来存放用户信息的,不能过长,否则客户端不能支付
"obfuscatedExternalProfileId": "",
"regionCode": "HK"
}
其实服务端判断consumptionState就够了,如果是1 已经消费就可以实现后续逻辑了,比如发放金币,开启VIP等。
~~to: Ly