前言
这篇文章很早就想写了,由于时间关系一直拖到现在,我相信这篇文章对大多数想要接入Goole Play支付的小伙伴来说,会少走许多坑的,在这里说明一下,笔者在集成过程中踩了不少坑,所有请大家尽情享用成果,废话不多说直接切入正题。
注意事项及准备工作
- 创建一个非国内的Google账号(这步很重要,国内账号不支持支付)
- 手机端开启VPN,选择Google账号同一个国家的VPN,否则可能导致支付失败
- 手机端下载Google Play App并登录
- Google Play账号绑定国外银行或者购买礼品卡,用于支付(建议没有国外银行卡的小伙伴购买礼品卡来用于支付,不知道购买渠道的笔者可以帮忙,联系方式QQ:643614219)
- 保证 versionCode 和版本号与你上传的apk的包的一样。
- 保证后台和你传入的购买商品的 id 一致。
- 确保你所使用的账号是在测试人员里。(在"APK"页面里,有一个“选择使用网址”,把这个网址给你的测试人员,让你的测试人员用他的google账号点进去,点那个“成为测试人员”(前提是你把他加进了测试人员列表), 只有这样才能测试商品支付)
开始集成
阅读文档
- 建议大家在集成之前先通读一遍文档,这样有助于大家更高效的集成文档,官方文档地址:https://developer.android.com/google/play/billing/billing_library_overview
支付大致流程
- 创建商品:使用 Google Play 管理中心配置应用内商品
- APP端根据创建的商品Id,获取商品详情
- 根据商品信息进行支付
- 验证支付结果
开始集成
引入仓库
implementation 'com.android.billingclient:billing:2.1.0'
AndroidManifest.xml文件添加权限
<uses-permission android:name="com.android.vending.BILLING" />
与Google Play建立连接
billingClient?.startConnection(object : BillingClientStateListener {override fun onBillingSetupFinished(billingResult: BillingResult) {statusData.value = StatusInfo(ActionCode.TYPE_ACTION_LOADED)if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {// The BillingClient is ready. You can query purchases here.LogPrinter.e("onBillingSetupFinished", "连接成功")//查询商品详情querySkuDetails(googleProductId)} else {LogPrinter.e("onBillingSetupFinished","连接失败了:responseCode ${billingResult.responseCode}")}}override fun onBillingServiceDisconnected() {billingClient = nullLogPrinter.e("onBillingDisconnected", "连接失败了")}})
查询商品信息
//查询应用内商品详情fun querySkuDetails(googleProductId: String) {val skuList = ArrayList<String>()skuList.add(googleProductId)
// skuList.add("unlock_face")//商品idval params = SkuDetailsParams.newBuilder()params.setSkusList(skuList).setType(BillingClient.SkuType.INAPP)billingClient?.querySkuDetailsAsync(params.build()) { billingResult, skuDetailsList ->if (billingResult!!.responseCode == BillingClient.BillingResponseCode.OK && skuDetailsList != null) {//查找商品详情for (skuDetailsItem in skuDetailsList) {val sku = skuDetailsItem.skuval price = skuDetailsItem.priceLog.e("skuDetails", "$sku $price")if (googleProductId == sku) {skuDetails = skuDetailsItem}}} }}
发起支付
private fun doGooPlayPay() {val flowParams = BillingFlowParams.newBuilder().setSkuDetails(skuDetails).build()billingClient?.launchBillingFlow(context, flowParams)}
支付成功后确认购买交易
如果您使用的是 Google Play 结算库版本 2.0 或更高版本,则必须在三天内确认所有购买交易。如果没能正确确认,将导致系统对相应购买交易按退款处理。
Google Play 支持从您的应用内部(应用内)或外部(应用外)购买商品。为了确保无论用户在哪里购买您的商品,Google Play 都能提供一致的购买体验,您必须在授予用户权利后尽快确认通过 Google Play 结算库收到的所有处于 SUCCESS 状态的购买交易。如果您在三天内未确认购买交易,则用户会自动收到退款,并且 Google Play 会撤消该购买交易。对于待处理的交易,该三天期限不包含购买交易处于 PENDING 状态的时间,而是从购买交易改为 SUCCESS 状态时算起。
您可以使用以下方法之一确认购买交易:
对于消耗型商品,请使用客户端 API 中的 consumeAsync()。
对于非消耗型商品,请使用客户端 API 中的 acknowledgePurchase()。
还可以使用服务器 API 中新增的 acknowledge() 方法。
对于消耗型商品,consumeAsync() 接受包含开发者载荷字段的 ConsumeParams 对象,如以下示例中所示:
val client: BillingClient = ...
fun consumePurchase() {val consumeParams =ConsumeParams.newBuilder().setPurchaseToken(/* token */).setDeveloperPayload(/* payload */).build()val consumeResult = withContext(Dispatchers.IO) {client.consumePurchase(consumeParams)}
}
下面是我代码里的示例
override fun onPurchasesUpdated(billingResult: BillingResult,purchases: MutableList<Purchase>?) {statusData.value = StatusInfo(ActionCode.TYPE_ACTION_LOADED)if (billingResult.responseCode == BillingClient.BillingResponseCode.OK && purchases != null) {for (purchase in purchases) {if (purchase.purchaseState == Purchase.PurchaseState.PURCHASED) {if (!purchase.isAcknowledged) {//没有确认去确认Log.e("去确认购买","${purchase.purchaseToken} ${purchase.developerPayload} ${purchase}")consumePurchase(purchase)} else {Log.d("onPurchasesUpdated", "purchaseState 商品已经购买 $purchase")}} else {Log.d("onPurchasesUpdated", "purchaseState ${purchase.purchaseState}")}}} else if (billingResult.responseCode == BillingClient.BillingResponseCode.USER_CANCELED) {// Handle an error caused by a user cancelling the purchase flow.statusData.value = StatusInfo(ActionCode.TYPE_ACTION_MESSAGE, "用户取消购买了")} else {// Handle any other error codes.statusData.value = StatusInfo(ActionCode.TYPE_ACTION_MESSAGE,"购买失败 responseCode:${billingResult.responseCode} Message:${billingResult.debugMessage} ")}Log.e("onPurchasesUpdated","购买结果 ${billingResult.responseCode} ${billingResult.debugMessage} purchases $purchases")}/*** 对于消耗型商品*/private fun consumePurchase(purchase: Purchase) {statusData.value= StatusInfo(ActionCode.TYPE_ACTION_LOADING_DIALOG)val consumeParams =ConsumeParams.newBuilder().setPurchaseToken(purchase.purchaseToken).setDeveloperPayload(paymentCode).build()billingClient?.consumeAsync(consumeParams) { billingResult, p1 ->if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {val body = GooglePayResultDto(commonRepository.getUserInfo()!!.id, purchase.orderId, purchase.packageName, paymentCode, purchase.sku, purchase.purchaseToken, commonRepository.getUserInfo()!!.uuid)commonRepository.googlePayCall(body).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(object : BaseObserver<BaseResponse<Any>>() {override fun onRequestStart() {}override fun onRequestEnd() {statusData.value=StatusInfo(ActionCode.TYPE_ACTION_LOADED)}override fun onSuccessful(data: BaseResponse<Any>?) {queryPayResult()}override fun onFailure(failureInfo: StatusInfo) {queryPayResult()}})}Log.e("consumePurchase","responseCode:${billingResult.responseCode} ${billingResult.debugMessage}")}}
验证购买交易
每次向用户提供他们所购买的商品的访问权限之前,您都应该验证购买交易是否处于 PURCHASED 状态,并验证应用在 onPurchasesUpdated() 中收到的其他购买详情。
验证购买交易分为分为两种方式:
详情请点击链接查看https://developer.android.com/google/play/billing/billing_library_overview
我这里示例是到服务器去验证,