admin管理员组文章数量:1604650
前端
这里要接入的是google应用内支付
1.在app模块下的build.gradle模块下引入最新版本google billing 4.0版本,顺便引入google服务,如下
implementation 'com.google.android.gms:play-services-wallet:19.0.0'
implementation 'com.android.support:appcompat-v7:24.1.1'
implementation 'com.android.billingclient:billing:4.0.0'
2.在app模块下的AndroidManifest.xml加入谷歌商店应用内购买结算需要的权限
<uses-permission android:name="com.android.vending.BILLING" />
<uses-permission android:name="com.farsitel.bazaar.permission.PAY_THROUGH_BAZAAR" />
com.android.vending.BILLING权限在我们上传包到google后台的时候需要用到
前端流程
1.连接到google支付服务,如果不能连接到,请检查以下:
- 连接的网络不能使用国内的,可以使用港澳台漫游网络,vpn有时候也不顶用
- 使用的海外手机,并且安装有google服务套件(google play ,google sever)
- 登录的google账号得是海外账号(港澳台的也行),必须海外注册的账号,不然不可用
- 可以登录google支付商店查看付费项能否正常显示
2.查询上次未消费的商品,如果有未消费的商品通知服务器,然后消费掉。因为国外的支付环境和国内不一样,他们可以线上下单,然后到便利店去支付,所以有未消费的这种情况。
3.使用google play console后台配置的商品id发起支付
4.支付完成通知后端查询结果,验证完后消费商品
前端核心代码
1.初始化BillingClient,并注册商品变动监听 商品状态发生变化都会走这个监听
public BillingClient mBillingclient;
mBillingclient=BillingClient.newBuilder(context).setListener(mPurchasesUpdatedListener).enablePendingPurchases().build();
private PurchasesUpdatedListener mPurchasesUpdatedListener=new PurchasesUpdatedListener() {
@Override
public void onPurchasesUpdated(@NonNull BillingResult billingResult, @Nullable List<Purchase> list) {
String debugMessage = billingResult.getDebugMessage();
if (list != null && list.size() > 0) {
if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) {
for (Purchase purchase : list) {
if(purchase == null || purchase.getPurchaseState() != Purchase.PurchaseState.PURCHASED) continue;
//通知服务器支付成功,服务端验证后,消费商品
//TODO客户端同步回调支付成功
}
}
} else {
switch (billingResult.getResponseCode()) {
case BillingClient.BillingResponseCode.SERVICE_TIMEOUT: //服务连接超时
break;
case BillingClient.BillingResponseCode.FEATURE_NOT_SUPPORTED:
break;
case BillingClient.BillingResponseCode.SERVICE_DISCONNECTED: //服务未连接
break;
case BillingClient.BillingResponseCode.USER_CANCELED: //取消
break;
case BillingClient.BillingResponseCode.SERVICE_UNAVAILABLE: //服务不可用
break;
case BillingClient.BillingResponseCode.BILLING_UNAVAILABLE: //购买不可用
break;
case BillingClient.BillingResponseCode.ITEM_UNAVAILABLE: //商品不存在
break;
case BillingClient.BillingResponseCode.DEVELOPER_ERROR: //提供给 API 的无效参数
break;
case BillingClient.BillingResponseCode.ERROR: //错误
break;
case BillingClient.BillingResponseCode.ITEM_ALREADY_OWNED: //未消耗掉
queryPurchases();
break;
case BillingClient.BillingResponseCode.ITEM_NOT_OWNED: //不可购买
break;
}
}
}
};
2.支付操作,支付前查询商品详情
cpOrder:这里用的是我们服务端生成的订单号,可不传
productId:这是在google后台填的商品id
public void pay(final String cpOrder, final String productId) {
if(mBillingclient == null || !mBillingclient.isReady()){
//TODO客户端同步回调支付失败,原因是为链接到google或者google的支付服务不能使用
mBillingclient.startConnection(new BillingClientStateListener() { //重新连接
@Override
public void onBillingServiceDisconnected() {
//尝试重新启动连接的下一个请求
//谷歌通过调用startConnection()方法进行播放。
}
@Override
public void onBillingSetupFinished(@NonNull BillingResult billingResult) {
if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) {
//BillingClient已经准备好。 你可以在这里查询购买情况。
querySkuDetailsAsync(cpOrder, productId);
}
}
});
return;
}
//查询商品详情
querySkuDetailsAsync(cpOrder, productId);
}
3.查询商品详情
void querySkuDetailsAsync(final String cpOrder, final String productId){
List<String> skuList = new ArrayList<>();
skuList.add(productId);
SkuDetailsParams.Builder params = SkuDetailsParams.newBuilder();
params.setSkusList(skuList).setType(BillingClient.SkuType.INAPP);
mBillingclient.querySkuDetailsAsync(params.build(),
new SkuDetailsResponseListener() {
@Override
public void onSkuDetailsResponse(BillingResult billingResult,
List<SkuDetails> skuDetailsList) {
if (skuDetailsList != null && billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK){
for(SkuDetails skuDetails : skuDetailsList){
if(productId.equals(skuDetails.getSku())){
//发起支付
launchBillingFlow(cpOrder, skuDetails);
}
}
}
}
});
}
4.发起支付
/**
* 拉取google支付页面
* @param cpOrder 你自己的订单号或者用户id,用于关联到对应的用户,发放道具时使用
* @param skuDetails
*/
void launchBillingFlow(String cpOrder, SkuDetails skuDetails){
mBillingclient.launchBillingFlow(
(Activity) context,
BillingFlowParams
.newBuilder()
.setSkuDetails(skuDetails)
.setObfuscatedAccountId(cpOrder)//这里本来的意思存放用户信息,类似于国内的透传参数,我这里传的我们的订单号。老版本使用DeveloperPayload字段,最新版本中这个字段已不可用了
.build()
);
}
5.消耗商品
public void consumePurchase(final Purchase purchase){
if(mBillingclient == null || purchase == null || purchase.getPurchaseState() != Purchase.PurchaseState.PURCHASED) return;
Log.i("Tag","消耗商品:商品id:" + purchase.getSkus() + "商品OrderId:" + purchase.getOrderId() + "token:" + purchase.getPurchaseToken());
ConsumeParams consumeParams = ConsumeParams.newBuilder()
.setPurchaseToken(purchase.getPurchaseToken())
.build();
ConsumeResponseListener listener = new ConsumeResponseListener() {
@Override
public void onConsumeResponse(BillingResult billingResult, String purchaseToken) {
if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.ERROR) {
//消费失败将商品重新放入消费队列
return;
}
Log.i("TAG", "消费成功: ");
}
};
mBillingclient.consumeAsync(consumeParams, listener);
}
6.补单操作
/**
* 补单操作 查询已支付的商品,并通知服务器后消费(google的支付里面,没有消费的商品,不能再次购买)
*/
private void queryPurchases(){
PurchasesResponseListener mPurchasesResponseListener = new PurchasesResponseListener() {
@Override
public void onQueryPurchasesResponse(@NonNull BillingResult billingResult, @NonNull List<Purchase> purchasesResult) {
if(billingResult.getResponseCode() != BillingClient.BillingResponseCode.OK || purchasesResult == null) return;
for (Purchase purchase : purchasesResult) {
if(purchase!=null){
consumePurchase(purchase);
}
if(purchase == null || purchase.getPurchaseState() != Purchase.PurchaseState.PURCHASED) continue;
//这里处理已经支付过的订单,通知服务器去验证 并消耗商品
}
}
};
mBillingclient.queryPurchasesAsync(BillingClient.SkuType.INAPP, mPurchasesResponseListener);
}
以上大致就是客户端核心流程,接下来就是后端查询订单验证的过程了
服务端
1.Gooale Play Console 后台创建应用 传送门:https://play.google/console
2.Google Cloud Platform创建api项目 传送门:https://console.cloud.google/
3.Google Play Console后台的API权限那里进入并关联到这个api项目
4.Google Play Android Developer API启用
5.设置oauth同意屏幕
6.创建web应用的oauth2.0客户端ID
7.拉起授权页面,使用google开发者账号给项目授权,得到code
8.通过code,拿到refreshToken,这个token只有第一次才会返回需要永久储存(这个refreshtoken很重要,需要保存下来),如果弄丢,只有重新创建一个oauth客户端ID,然后重复步骤6,7,拿到新的refreshtoken
9.刷新refreshToken, 得到accessToken,通过accesstoken就可以去查询订单状态了,这里的accessToken一般只有5分钟左右,5分钟后需要重新用refreshToken换取新的accessToken
具体参考这篇博客:https://wwwblogs/xiaogou/p/15568393.html
查询
1.获取code
地址:https://accounts.google/o/oauth2/auth?scope=https://www.googleapis/auth/androidpublisher&response_type=code&access_type=offline&redirect_uri={填写的重定向地址}&client_id={创建的clientId}
将上面的{XX}替换成创建api项目时填写的重定向地址,和clientId,然后将连接放到浏览器中打开,就会吊起授权界面,使用你的开发者账号授权登录
请求方式:浏览器中打开
请求完重定向地址上有两个参数code和scope,我们只需要code就行了
2.获取refreshToken
使用code换取refreshToken
地址:https://accounts.google/o/oauth2/token
请求方式:post
参数:grant_type=authorization_code
code=获取到的code(需要看看code中是否有%号,如果有需要urldecode)
client_id=创建api项目是的clientId(客户端ID)
client_secret=创建api项目时的clientSecret(客户端密钥)
redirect_uri=创建api项目时的重定向地址
3.查询订单状态
https://androidpublisher.googleapis/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
注意
1.接好sdk后打个app bundle上传到Gooale Play Console后台的内部测试,添加测试人员,发送邀请和测试链接,即可使用沙盒测试。
2.支付无法拉起请检查下面:
- 连接的网络不能使用国内的,可以使用港澳台漫游网络,vpn有时候也不顶用
- 使用的海外手机,并且安装有google服务套件(google play ,google sever)
- 登录的google账号得是海外账号(港澳台的也行),必须海外注册的账号,不然不可用
- 可以登录google支付商店查看付费项能否正常显示
常见报错(FAQ)
1.In-app Billing API version is less than 3
检查google play 是否最新,使用的账号是否是海外账号,连接网络不能使用国内网络,可以使用港澳台漫游
2.查询订单报错:The current user has insufficient permissions to perform the requested operation
这是因为上面获得refreshToken的账号没有被授予Sevvice Account权限,进入Google Cloud Platform创建服务账号,并授予权限,用获得refreshToken的账号添加角色,并授予Sevvice Account权限即可查询订单
3.An internal error occurred
可能是网络问题,检查网络是否能上网,然后看其他付费应用能否拉取google支付
官方文档:https://developer.android.google/google/play/billing/integrate
版权声明:本文标题:Android Google Play 支付SDK接入指南 内容由热心网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:https://m.elefans.com/dongtai/1728465604a1159413.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论