feat:适配BillingService2,完善支付回调
This commit is contained in:
@@ -84,7 +84,6 @@ import com.chwl.library.common.file.FileHelper;
|
||||
import com.chwl.library.net.rxnet.RxNet;
|
||||
import com.chwl.library.net.rxnet.converter.GsonConverterPlugins;
|
||||
import com.chwl.library.utils.AppMetaDataUtil;
|
||||
import com.chwl.library.utils.AppUtils;
|
||||
import com.chwl.library.utils.DeviceUuidFactory;
|
||||
import com.chwl.library.utils.ResUtil;
|
||||
import com.chwl.library.utils.SingleToastUtil;
|
||||
@@ -419,7 +418,7 @@ public class App extends BaseApp {
|
||||
httpParams.put("netType", String.valueOf(SystemUtils.getNetworkType(context)));
|
||||
httpParams.put("model", SystemUtils.getPhoneModel());
|
||||
httpParams.put("appVersion", VersionUtil.getLocalName(context));
|
||||
httpParams.put("appVersionCode", String.valueOf(AppUtils.getVersionCode(context)));
|
||||
httpParams.put("appVersionCode", String.valueOf(VersionUtil.getVersionCode(context)));
|
||||
httpParams.put("deviceId", DeviceUuidFactory.getDeviceId(context));
|
||||
httpParams.put("androidId", MD5Utils.getMD5String(Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID)));
|
||||
httpParams.put("channel", AppMetaDataUtil.getChannelID());
|
||||
|
@@ -11,18 +11,22 @@ import com.chwl.core.pay.bean.PayRecordId
|
||||
import com.chwl.library.utils.SingleToastUtil
|
||||
import com.example.lib_utils.log.ILog
|
||||
import com.example.module_base.support.billing.IBillingResult
|
||||
import com.example.module_base.support.billing.IBillingService
|
||||
import com.example.module_base.support.billing.IBillingService2
|
||||
import com.example.module_base.support.billing.IProductDetails
|
||||
import com.example.module_base.support.billing.IPurchase
|
||||
import com.example.module_base.support.billing.OnBillingClientStateListener
|
||||
import com.example.module_base.support.billing.OnConsumeResponseListener
|
||||
import com.example.module_base.support.billing.OnProductDetailsResponseListener
|
||||
import com.example.module_base.support.billing.OnPurchasesResponseListener
|
||||
import com.example.module_base.support.google.IGoogleService
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
import io.reactivex.disposables.Disposable
|
||||
|
||||
class GPaymentClient(val activity: Activity) : IPaymentClient, IBillingService.Listener,
|
||||
IBillingService.ProductDetailsResponseListener, LifecycleEventObserver, ILog {
|
||||
class GPaymentClient(val activity: Activity) : IPaymentClient, IBillingService2.Listener,
|
||||
OnProductDetailsResponseListener, LifecycleEventObserver, ILog, OnBillingClientStateListener {
|
||||
|
||||
private var compositeDisposable: CompositeDisposable? = null
|
||||
private var _billingService: IBillingService? = null
|
||||
private var _billingService: IBillingService2? = null
|
||||
private val dialogManager = DialogManager(activity)
|
||||
|
||||
private var paymentIntent: PaymentIntent? = null
|
||||
@@ -35,9 +39,11 @@ class GPaymentClient(val activity: Activity) : IPaymentClient, IBillingService.L
|
||||
(activity as? LifecycleOwner)?.lifecycle?.addObserver(this)
|
||||
}
|
||||
|
||||
private fun getBillingService(): IBillingService? {
|
||||
private fun getBillingService(): IBillingService2? {
|
||||
if (_billingService == null) {
|
||||
_billingService = IGoogleService.newBillingService(activity, this)
|
||||
_billingService = IGoogleService.newBillingService2(activity, this)
|
||||
_billingService?.setLogEnabled(true)
|
||||
_billingService?.startConnection(this)
|
||||
}
|
||||
return _billingService
|
||||
}
|
||||
@@ -54,6 +60,14 @@ class GPaymentClient(val activity: Activity) : IPaymentClient, IBillingService.L
|
||||
}
|
||||
|
||||
private fun tryLaunch() {
|
||||
val billingService = getBillingService()
|
||||
if (billingService == null) {
|
||||
callFailed(
|
||||
IPaymentClient.CODE_NONSUPPORT,
|
||||
PaymentException(activity.getString(R.string.bean_response_serviceresult_015))
|
||||
)
|
||||
return
|
||||
}
|
||||
val productId = paymentIntent?.productId
|
||||
val productItem = productItem
|
||||
logD("tryLaunch() productId:$productId productItem:$productItem")
|
||||
@@ -78,7 +92,7 @@ class GPaymentClient(val activity: Activity) : IPaymentClient, IBillingService.L
|
||||
{ recordId: PayRecordId ->
|
||||
if (paymentIntent?.productId == productItem.getProductId()) {
|
||||
orderId = recordId.recordId
|
||||
getBillingService()?.initiatePurchaseFlow(
|
||||
getBillingService()?.launchBillingFlow(
|
||||
productItem,
|
||||
recordId.recordId
|
||||
)
|
||||
@@ -91,47 +105,94 @@ class GPaymentClient(val activity: Activity) : IPaymentClient, IBillingService.L
|
||||
})
|
||||
}
|
||||
|
||||
override fun onBillingClientSetupFinished() {
|
||||
logD("onBillingClientSetupFinished()")
|
||||
tryLaunch()
|
||||
override fun onBillingSetupFinished(billingResult: IBillingResult) {
|
||||
if (billingResult.isResponseOk()) {
|
||||
logD("onBillingClientSetupFinished()")
|
||||
getBillingService()?.queryPurchases(object : OnPurchasesResponseListener {
|
||||
override fun onQueryPurchasesResponse(
|
||||
billingResult: IBillingResult,
|
||||
purchases: List<IPurchase>
|
||||
) {
|
||||
if (billingResult.isResponseOk() && purchases.isNotEmpty()) {
|
||||
purchases.forEach {
|
||||
handlePurchases(false, it)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
tryLaunch()
|
||||
} else {
|
||||
callFailed(
|
||||
IPaymentClient.CODE_UNAVAILABLE
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPurchasesUpdated(purchases: List<IPurchase>) {
|
||||
logD("onPurchasesUpdated() purchases:${purchases.size}")
|
||||
purchases.forEach {
|
||||
logD("onPurchasesUpdated() item.state:${it.getPurchaseState()}")
|
||||
logD("onPurchasesUpdated() item.orderId:${it.getOrderId()}")
|
||||
logD("onPurchasesUpdated() item.token:${it.getPurchaseToken()}")
|
||||
logD("onPurchasesUpdated() item.data:${it.getData()}")
|
||||
val identifiers = it.getAccountIdentifiers()
|
||||
if (it.isPurchasedState() && identifiers != null) {
|
||||
addDisposable(
|
||||
PayModel.get().verifyOrder(
|
||||
identifiers.getObfuscatedAccountId(),
|
||||
it.getProducts().firstOrNull(),
|
||||
it.getPackageName(),
|
||||
it.getPurchaseToken()
|
||||
).subscribe({
|
||||
getBillingService()?.consumeAsync(it)
|
||||
}, {
|
||||
callFailed(IPaymentClient.CODE_VERIFY_ORDER_FAILED, it)
|
||||
})
|
||||
)
|
||||
override fun onPurchasesUpdated(billingResult: IBillingResult, purchases: List<IPurchase>?) {
|
||||
logD("onPurchasesUpdated() billingResult:${billingResult.getResponseCode()} purchases:${purchases?.size}")
|
||||
if (billingResult.isResponseOk() && !purchases.isNullOrEmpty()) {
|
||||
purchases.forEach {
|
||||
handlePurchases(true, it)
|
||||
}
|
||||
} else {
|
||||
callFailed(IPaymentClient.CODE_PURCHASE_FAILED)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onConsumeFinished(token: String?, result: Int) {
|
||||
logD("onConsumeFinished() token:${token} result:$result")
|
||||
val orderId = orderId
|
||||
if (orderId != null) {
|
||||
callSuccess(orderId)
|
||||
private fun handlePurchases(isCurrentPaying: Boolean, purchases: IPurchase) {
|
||||
logD("handlePurchases state:${purchases.getPurchaseState()}")
|
||||
logD("handlePurchases orderId:${purchases.getOrderId()}")
|
||||
logD("handlePurchases token:${purchases.getPurchaseToken()}")
|
||||
logD("handlePurchases data:${purchases.getData()}")
|
||||
logD(
|
||||
"handlePurchases obfuscatedAccountId:${
|
||||
purchases.getAccountIdentifiers()?.getObfuscatedAccountId()
|
||||
}"
|
||||
)
|
||||
logD(
|
||||
"handlePurchases obfuscatedProfileId:${
|
||||
purchases.getAccountIdentifiers()?.getObfuscatedProfileId()
|
||||
}"
|
||||
)
|
||||
val identifiers = purchases.getAccountIdentifiers()
|
||||
if (purchases.isPurchasedState() && identifiers != null) {
|
||||
logD("handlePurchases() verifyOrder")
|
||||
addDisposable(
|
||||
PayModel.get().verifyOrder(
|
||||
identifiers.getObfuscatedAccountId(),
|
||||
purchases.getProducts().firstOrNull(),
|
||||
purchases.getPackageName(),
|
||||
purchases.getPurchaseToken()
|
||||
).subscribe({
|
||||
logD("handlePurchases() verifyOrder consumeAsync")
|
||||
consumeAsync(isCurrentPaying, it)
|
||||
}, {
|
||||
logD("handlePurchases() error:${it.message}")
|
||||
if (isCurrentPaying) {
|
||||
callFailed(IPaymentClient.CODE_VERIFY_ORDER_FAILED, it)
|
||||
}
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFailedHandle(result: Int) {
|
||||
logD("onFailedHandle() result:${result}")
|
||||
callFailed(IPaymentClient.CODE_OTHER)
|
||||
private fun consumeAsync(isCurrentPaying: Boolean, token: String) {
|
||||
logD("consumeAsync() isCurrentPaying:${isCurrentPaying} token:$token")
|
||||
getBillingService()?.consumeAsync(token, object : OnConsumeResponseListener {
|
||||
override fun onConsumeResponse(billingResult: IBillingResult, purchaseToken: String) {
|
||||
logD("consumeAsync() onConsumeResponse billingResult:${billingResult} purchaseToken:$purchaseToken")
|
||||
if (isCurrentPaying) {
|
||||
if (billingResult.isResponseOk()) {
|
||||
val orderId = orderId
|
||||
if (orderId != null) {
|
||||
callSuccess(orderId)
|
||||
}
|
||||
} else {
|
||||
callFailed(IPaymentClient.CODE_CONSUME_ORDER_FAILED)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
override fun onProductDetailsResponse(
|
||||
@@ -147,10 +208,10 @@ class GPaymentClient(val activity: Activity) : IPaymentClient, IBillingService.L
|
||||
if (item != null) {
|
||||
tryLaunch()
|
||||
} else {
|
||||
callFailed(IPaymentClient.CODE_NOT_FOUND)
|
||||
callFailed(IPaymentClient.CODE_PRODUCT_NOT_FOUND)
|
||||
}
|
||||
} else {
|
||||
callFailed(IPaymentClient.CODE_NOT_FOUND)
|
||||
callFailed(IPaymentClient.CODE_PRODUCT_NOT_FOUND)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -163,10 +224,20 @@ class GPaymentClient(val activity: Activity) : IPaymentClient, IBillingService.L
|
||||
dialogManager.dismissDialog()
|
||||
}
|
||||
|
||||
private fun callFailed(code: Int, throwable: Throwable? = null) {
|
||||
throwable?.printStackTrace()
|
||||
logD("callFailed() code:${code} throwable:${throwable?.message}")
|
||||
throwable?.let {
|
||||
private fun callFailed(code: Int) {
|
||||
callFailed(
|
||||
code,
|
||||
PaymentException(
|
||||
code,
|
||||
message = activity.getString(R.string.common_operation_prompt_format).format(code)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private fun callFailed(code: Int, throwable: Throwable) {
|
||||
throwable.printStackTrace()
|
||||
logD("callFailed() code:${code} throwable:${throwable.message}")
|
||||
throwable.let {
|
||||
SingleToastUtil.showToast(
|
||||
it.message
|
||||
)
|
||||
@@ -202,12 +273,6 @@ class GPaymentClient(val activity: Activity) : IPaymentClient, IBillingService.L
|
||||
override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
|
||||
logD("onStateChanged() event:$event")
|
||||
when (event) {
|
||||
Lifecycle.Event.ON_RESUME -> {
|
||||
if (_billingService?.isServiceConnected() == true) {
|
||||
_billingService?.onQueryPurchases()
|
||||
}
|
||||
}
|
||||
|
||||
Lifecycle.Event.ON_DESTROY -> {
|
||||
(activity as? LifecycleOwner)?.lifecycle?.removeObserver(this)
|
||||
onCleared()
|
||||
|
@@ -10,17 +10,26 @@ interface IPaymentClient : ICleared {
|
||||
// 未知异常原因
|
||||
const val CODE_OTHER = 0
|
||||
|
||||
// 服务不可用
|
||||
const val CODE_UNAVAILABLE = 1
|
||||
// 不支持该功能
|
||||
const val CODE_NONSUPPORT = 1
|
||||
|
||||
// 查询订单信息失败
|
||||
const val CODE_NOT_FOUND = 2
|
||||
// 服务暂不可用
|
||||
const val CODE_UNAVAILABLE = 2
|
||||
|
||||
// 未查询到购买信息
|
||||
const val CODE_PRODUCT_NOT_FOUND = 3
|
||||
|
||||
// 预下单失败
|
||||
const val CODE_PLACE_ORDER_FAILED = 3
|
||||
const val CODE_PLACE_ORDER_FAILED = 4
|
||||
|
||||
// 购买失败
|
||||
const val CODE_PURCHASE_FAILED = 5
|
||||
|
||||
// 验证订单失败
|
||||
const val CODE_VERIFY_ORDER_FAILED = 4
|
||||
const val CODE_VERIFY_ORDER_FAILED = 6
|
||||
|
||||
// 核消订单失败
|
||||
const val CODE_CONSUME_ORDER_FAILED = 7
|
||||
}
|
||||
|
||||
fun launchPayment(intent: PaymentIntent)
|
||||
|
@@ -0,0 +1,13 @@
|
||||
package com.chwl.app.ui.wallet.payment
|
||||
|
||||
import androidx.annotation.Keep
|
||||
|
||||
@Keep
|
||||
class PaymentException : Exception {
|
||||
var code = 0
|
||||
|
||||
constructor(message: String) : super(message)
|
||||
constructor(code: Int, message: String) : super(message) {
|
||||
this.code = code
|
||||
}
|
||||
}
|
@@ -59,7 +59,6 @@ import com.chwl.library.record.AuditRecorderConfiguration;
|
||||
import com.chwl.library.record.ExtAudioRecorder;
|
||||
import com.chwl.library.rxbus.RxBus;
|
||||
import com.chwl.library.utils.AppMetaDataUtil;
|
||||
import com.chwl.library.utils.AppUtils;
|
||||
import com.chwl.library.utils.DeviceUuidFactory;
|
||||
import com.chwl.library.utils.SystemUtils;
|
||||
import com.chwl.library.utils.VersionUtil;
|
||||
@@ -545,7 +544,7 @@ public class JSInterface implements ICleared {
|
||||
jsonObject.put("netType", String.valueOf(SystemUtils.getNetworkType(context)));
|
||||
jsonObject.put("model", SystemUtils.getPhoneModel());
|
||||
jsonObject.put("appVersion", VersionUtil.getLocalName(context));
|
||||
jsonObject.put("appVersionCode", String.valueOf(AppUtils.getVersionCode(context)));
|
||||
jsonObject.put("appVersionCode", String.valueOf(VersionUtil.getVersionCode(context)));
|
||||
jsonObject.put("deviceId", DeviceUtil.getDeviceId(context));
|
||||
jsonObject.put("channel", AppMetaDataUtil.getChannelID());
|
||||
jsonObject.put("Accept-Language", LanguageHelper.INSTANCE.getCurrentLanguageType());
|
||||
@@ -630,7 +629,6 @@ public class JSInterface implements ICleared {
|
||||
|
||||
@Override
|
||||
public void onCleared() {
|
||||
ICleared.super.onCleared();
|
||||
if (paymentClient != null) {
|
||||
paymentClient.onCleared();
|
||||
}
|
||||
|
@@ -12,7 +12,6 @@ import com.tencent.vasdolly.helper.ChannelReaderUtil;
|
||||
import com.chwl.app.application.App;
|
||||
import com.chwl.core.XConstants;
|
||||
import com.chwl.core.Constants;
|
||||
import com.chwl.library.utils.AppUtils;
|
||||
import com.chwl.library.utils.VersionUtil;
|
||||
|
||||
/**
|
||||
@@ -108,7 +107,7 @@ public class SimpleJSInterface {
|
||||
jsonObject.put("os", "android");
|
||||
jsonObject.put("app", XConstants.APP_MARK);
|
||||
jsonObject.put("appVersion", VersionUtil.getLocalName(context));
|
||||
jsonObject.put("appVersionCode", String.valueOf(AppUtils.getVersionCode(context)));
|
||||
jsonObject.put("appVersionCode", String.valueOf(VersionUtil.getVersionCode(context)));
|
||||
jsonObject.put("channel", getChannel());
|
||||
Log.e(TAG, "getDeviceInfo: " + jsonObject);
|
||||
return jsonObject.toJSONString();
|
||||
|
@@ -683,4 +683,5 @@
|
||||
<string name="parameter_error">خطأ في المعلمة</string>
|
||||
|
||||
<string name="pk_refuse">رفض الطرف الآخر طلب الـ PK</string>
|
||||
<string name="common_operation_prompt_format">操作失敗 (%s)</string>
|
||||
</resources>
|
||||
|
@@ -670,4 +670,6 @@
|
||||
<string name="parameter_error">參數錯誤</string>
|
||||
|
||||
<string name="pk_refuse">對方拒絕你的PK請求</string>
|
||||
|
||||
<string name="common_operation_prompt_format">操作失敗 (%s)</string>
|
||||
</resources>
|
||||
|
@@ -665,5 +665,6 @@
|
||||
|
||||
|
||||
<string name="pk_refuse">The opponent rejected your PK request</string>
|
||||
<string name="common_operation_prompt_format">操作失敗 (%s)</string>
|
||||
</resources>
|
||||
|
||||
|
@@ -1,22 +0,0 @@
|
||||
package com.chwl.library.utils;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
|
||||
/**
|
||||
* <p> </p>
|
||||
*
|
||||
* @author jiahui
|
||||
* date 2018/2/28
|
||||
*/
|
||||
public class AppUtils {
|
||||
|
||||
public static int getVersionCode(Context context) {
|
||||
try {
|
||||
return context.getPackageManager().getPackageInfo(context.getPackageName(), 0).versionCode;
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
@@ -4,7 +4,9 @@ package com.example.module_base.support.billing
|
||||
* Created by Max on 2023/11/22 17:44
|
||||
* Desc:支付
|
||||
**/
|
||||
@Deprecated("逐步迁移到IBillingService2")
|
||||
interface IBillingService {
|
||||
fun setLogEnabled(enabled: Boolean)
|
||||
|
||||
fun isServiceConnected(): Boolean
|
||||
|
||||
@@ -28,7 +30,5 @@ interface IBillingService {
|
||||
fun onFailedHandle(result: Int)
|
||||
}
|
||||
|
||||
interface ProductDetailsResponseListener {
|
||||
fun onProductDetailsResponse(billingResult: IBillingResult, productDetails: List<IProductDetails>)
|
||||
}
|
||||
interface ProductDetailsResponseListener : OnProductDetailsResponseListener
|
||||
}
|
@@ -0,0 +1,31 @@
|
||||
package com.example.module_base.support.billing
|
||||
|
||||
/**
|
||||
* Created by Max on 2023/11/22 17:44
|
||||
* Desc:支付
|
||||
**/
|
||||
interface IBillingService2 {
|
||||
|
||||
fun setLogEnabled(enabled: Boolean)
|
||||
|
||||
fun startConnection(listener: OnBillingClientStateListener)
|
||||
|
||||
fun isServiceConnected(): Boolean
|
||||
|
||||
fun queryPurchases(listener: OnPurchasesResponseListener)
|
||||
|
||||
fun querySkuDetailsAsync(
|
||||
productIdList: List<String>,
|
||||
listener: OnProductDetailsResponseListener
|
||||
)
|
||||
|
||||
fun consumeAsync(purchaseToken: String, listener: OnConsumeResponseListener)
|
||||
|
||||
fun launchBillingFlow(productDetails: IProductDetails, recordId: String)
|
||||
|
||||
fun destroy()
|
||||
|
||||
interface Listener {
|
||||
fun onPurchasesUpdated(billingResult: IBillingResult, purchases: List<IPurchase>?)
|
||||
}
|
||||
}
|
@@ -0,0 +1,5 @@
|
||||
package com.example.module_base.support.billing
|
||||
|
||||
interface OnBillingClientStateListener {
|
||||
fun onBillingSetupFinished(billingResult: IBillingResult)
|
||||
}
|
@@ -0,0 +1,8 @@
|
||||
package com.example.module_base.support.billing
|
||||
|
||||
interface OnConsumeResponseListener {
|
||||
fun onConsumeResponse(
|
||||
billingResult: IBillingResult,
|
||||
purchaseToken: String
|
||||
)
|
||||
}
|
@@ -0,0 +1,8 @@
|
||||
package com.example.module_base.support.billing
|
||||
|
||||
interface OnProductDetailsResponseListener {
|
||||
fun onProductDetailsResponse(
|
||||
billingResult: IBillingResult,
|
||||
productDetails: List<IProductDetails>
|
||||
)
|
||||
}
|
@@ -0,0 +1,5 @@
|
||||
package com.example.module_base.support.billing
|
||||
|
||||
interface OnPurchasesResponseListener {
|
||||
fun onQueryPurchasesResponse(billingResult: IBillingResult, purchases: List<IPurchase>)
|
||||
}
|
@@ -4,6 +4,7 @@ import android.app.Activity
|
||||
import com.alibaba.android.arouter.facade.template.IProvider
|
||||
import com.alibaba.android.arouter.launcher.ARouter
|
||||
import com.example.module_base.support.billing.IBillingService
|
||||
import com.example.module_base.support.billing.IBillingService2
|
||||
import com.example.module_base.support.login.ILoginService
|
||||
|
||||
/**
|
||||
@@ -26,6 +27,13 @@ interface IGoogleService : IProvider {
|
||||
): IBillingService? {
|
||||
return instance?.newBillingService(activity, listener)
|
||||
}
|
||||
|
||||
fun newBillingService2(
|
||||
activity: Activity,
|
||||
listener: IBillingService2.Listener
|
||||
): IBillingService2? {
|
||||
return instance?.newBillingService2(activity, listener)
|
||||
}
|
||||
}
|
||||
|
||||
fun newLoginService(): ILoginService
|
||||
@@ -34,4 +42,9 @@ interface IGoogleService : IProvider {
|
||||
activity: Activity,
|
||||
listener: IBillingService.Listener
|
||||
): IBillingService
|
||||
|
||||
fun newBillingService2(
|
||||
activity: Activity,
|
||||
listener: IBillingService2.Listener
|
||||
): IBillingService2
|
||||
}
|
Reference in New Issue
Block a user