前言
這篇文章很早就想寫了,由于時間關系一直拖到現在,我相信這篇文章對大多數想要接入Goole Play支付的小夥伴來說,會少走許多坑的,在這裡說明一下,筆者在內建過程中踩了不少坑,所有請大家盡情享用成果,廢話不多說直接切入正題。
注意事項及準備工作
- 建立一個非國内的Google賬号(這步很重要,國内賬号不支援支付)
- 手機端開啟VPN,選擇Google賬号同一個國家的VPN,否則可能導緻支付失敗
- 手機端下載下傳Google Play App并登入
- Google Play賬号綁定國外銀行或者購買禮品卡,用于支付(建議沒有國外銀行卡的小夥伴購買禮品卡來用于支付,不知道購買管道的筆者可以幫忙,聯系方式QQ:643614219)
開始內建
閱讀文檔
- 建議大家在內建之前先通讀一遍文檔,這樣有助于大家更高效的內建文檔,官方文檔位址:https://developer.android.com/google/play/billing/billing_library_overview
支付大緻流程
- 建立商品:使用 Google Play 管理中心配置應用内商品
- APP端根據建立的商品Id,擷取商品詳情
- 根據商品資訊進行支付
- 驗證支付結果
開始內建
引入倉庫
AndroidManifest.xml檔案添權重限
與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 = null
LogPrinter.e("onBillingDisconnected", "連接配接失敗了")
}
})
查詢商品資訊
//查詢應用内商品詳情
fun querySkuDetails(googleProductId: String) {
val skuList = ArrayList<String>()
skuList.add(googleProductId)
// skuList.add("unlock_face")//商品id
val 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.sku
val price = skuDetailsItem.price
Log.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
我這裡示例是到伺服器去驗證,