From 3b407c0bd6fa8f1adcd1742dead9f13d5c11256d Mon Sep 17 00:00:00 2001
From: max
Date: Mon, 8 Jul 2024 17:57:55 +0800
Subject: [PATCH] =?UTF-8?q?feat:=E5=88=9D=E6=AD=A5=E5=AE=9E=E7=8E=B0H5?=
=?UTF-8?q?=E5=94=A4=E8=B5=B7=E6=94=AF=E4=BB=98=E9=80=BB=E8=BE=91=EF=BC=88?=
=?UTF-8?q?=E4=B8=8D=E5=AE=8C=E5=96=84=EF=BC=8C=E7=94=A8=E4=BA=8E=E6=89=93?=
=?UTF-8?q?=E5=86=85=E6=B5=8B=E5=8C=85=E9=AA=8C=E8=AF=81=EF=BC=89?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../java/com/chwl/app/application/App.java | 4 +-
.../chwl/app/ui/setting/SettingActivity.kt | 9 +-
.../app/ui/wallet/payment/GPaymentClient.kt | 221 ++++++++++++++++++
.../app/ui/wallet/payment/IPaymentClient.kt | 33 +++
.../app/ui/wallet/payment/PaymentIntent.kt | 4 +
.../app/ui/wallet/payment/PaymentResult.kt | 12 +
.../app/ui/webview/CommonWebViewActivity.java | 7 +-
.../app/ui/webview/CommonWebViewFragment.java | 14 +-
.../com/chwl/app/ui/webview/JSInterface.java | 85 ++++++-
9 files changed, 376 insertions(+), 13 deletions(-)
create mode 100644 app/src/main/java/com/chwl/app/ui/wallet/payment/GPaymentClient.kt
create mode 100644 app/src/main/java/com/chwl/app/ui/wallet/payment/IPaymentClient.kt
create mode 100644 app/src/main/java/com/chwl/app/ui/wallet/payment/PaymentIntent.kt
create mode 100644 app/src/main/java/com/chwl/app/ui/wallet/payment/PaymentResult.kt
diff --git a/app/src/main/java/com/chwl/app/application/App.java b/app/src/main/java/com/chwl/app/application/App.java
index 87ab47c2b..9282a9aed 100644
--- a/app/src/main/java/com/chwl/app/application/App.java
+++ b/app/src/main/java/com/chwl/app/application/App.java
@@ -325,7 +325,9 @@ public class App extends BaseApp {
BasicConfig.INSTANCE.setVoiceDir(Constants.VOICE_DIR);
BasicConfig.INSTANCE.setCacheDir(Constants.CACHE_DIR);
BasicConfig.INSTANCE.setImageDir(Constants.IMAGE_CACHE_DIR);
- com.example.lib_utils.log.LogUtil.INSTANCE.setConsolePrinterEnabled(BuildConfig.DEBUG);
+ // TODO 临时调整
+ com.example.lib_utils.log.LogUtil.INSTANCE.setConsolePrinterEnabled(true);
+// com.example.lib_utils.log.LogUtil.INSTANCE.setConsolePrinterEnabled(BuildConfig.DEBUG);
}
/**
diff --git a/app/src/main/java/com/chwl/app/ui/setting/SettingActivity.kt b/app/src/main/java/com/chwl/app/ui/setting/SettingActivity.kt
index 181ba5e63..92530abad 100644
--- a/app/src/main/java/com/chwl/app/ui/setting/SettingActivity.kt
+++ b/app/src/main/java/com/chwl/app/ui/setting/SettingActivity.kt
@@ -84,11 +84,12 @@ class SettingActivity : BaseViewBindingActivity(), View.
binding.tvLanugage.setOnClickListener(this)
binding.rlyPayPwd.setOnClickListener(this)
- if (BuildConfig.DEBUG) {
+ // TODO 临时调整
+// if (BuildConfig.DEBUG) {
binding.titleBar.setOnTitleClickListener {
debug()
}
- }
+// }
}
@SuppressLint("CheckResult")
@@ -222,8 +223,8 @@ class SettingActivity : BaseViewBindingActivity(), View.
}
private fun debug() {
- startActivity(Intent(this, DebugActivity::class.java))
-// CommonWebViewActivity.start(this,"https://api.molistar.xyz/molistar/activity/2024-invitationFission/index.html")
+// startActivity(Intent(this, DebugActivity::class.java))
+ CommonWebViewActivity.start(this,"http://beta.api.molistar.xyz/molistar/modules/order/index.html")
// PublicChatRoomMessageActivity.start(this)
// MyDecorationActivity.start(this,0)
}
diff --git a/app/src/main/java/com/chwl/app/ui/wallet/payment/GPaymentClient.kt b/app/src/main/java/com/chwl/app/ui/wallet/payment/GPaymentClient.kt
new file mode 100644
index 000000000..ccc3896ac
--- /dev/null
+++ b/app/src/main/java/com/chwl/app/ui/wallet/payment/GPaymentClient.kt
@@ -0,0 +1,221 @@
+package com.chwl.app.ui.wallet.payment
+
+import android.app.Activity
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.LifecycleEventObserver
+import androidx.lifecycle.LifecycleOwner
+import com.chwl.app.R
+import com.chwl.app.common.widget.dialog.DialogManager
+import com.chwl.core.pay.PayModel
+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.IProductDetails
+import com.example.module_base.support.billing.IPurchase
+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 {
+
+ private var compositeDisposable: CompositeDisposable? = null
+ private var _billingService: IBillingService? = null
+ private val dialogManager = DialogManager(activity)
+
+ private var paymentIntent: PaymentIntent? = null
+ private var productItem: IProductDetails? = null
+ private var orderId: String? = null
+
+ init {
+ dialogManager.setCanceledOnClickOutside(false)
+ dialogManager.setCanceledOnClickBackKey(false)
+ (activity as? LifecycleOwner)?.lifecycle?.addObserver(this)
+ }
+
+ private fun getBillingService(): IBillingService? {
+ if (_billingService == null) {
+ _billingService = IGoogleService.newBillingService(activity, this)
+ }
+ return _billingService
+ }
+
+ override fun launchPayment(intent: PaymentIntent) {
+ logD("launchPayment() intent:${intent.productId}")
+ if (paymentIntent != null) {
+ SingleToastUtil.showToast(R.string.avroom_activity_roomblacklistactivity_015)
+ return
+ }
+ dialogManager.showProgressDialog(activity)
+ this.paymentIntent = intent
+ tryLaunch()
+ }
+
+ private fun tryLaunch() {
+ val productId = paymentIntent?.productId
+ val productItem = productItem
+ logD("tryLaunch() productId:$productId productItem:$productItem")
+ if (productId == null) {
+ return
+ }
+ if (getBillingService()?.isServiceConnected() != true) {
+ logD("tryLaunch() isServiceConnected = false")
+ return
+ }
+ if (productItem == null) {
+ getBillingService()?.querySkuDetailsAsync(listOf(productId), this)
+ } else {
+ placeOrder(productItem)
+ }
+ }
+
+ private fun placeOrder(productItem: IProductDetails) {
+ logD("placeOrder() productItem:${productItem.getProductId()}")
+ addDisposable(PayModel.get().placeOrder(productItem.getProductId())
+ .subscribe(
+ { recordId: PayRecordId ->
+ if (paymentIntent?.productId == productItem.getProductId()) {
+ orderId = recordId.recordId
+ getBillingService()?.initiatePurchaseFlow(
+ productItem,
+ recordId.recordId
+ )
+ } else {
+ logE("placeOrder() 意图发生改变")
+ }
+ }
+ ) { throwable: Throwable ->
+ callFailed(IPaymentClient.CODE_PLACE_ORDER_FAILED, throwable)
+ })
+ }
+
+ override fun onBillingClientSetupFinished() {
+ logD("onBillingClientSetupFinished()")
+ tryLaunch()
+ }
+
+ override fun onPurchasesUpdated(purchases: List) {
+ 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 onConsumeFinished(token: String?, result: Int) {
+ logD("onConsumeFinished() token:${token} result:$result")
+ val orderId = orderId
+ if (orderId != null) {
+ callSuccess(orderId)
+ }
+ }
+
+ override fun onFailedHandle(result: Int) {
+ logD("onFailedHandle() result:${result}")
+ callFailed(IPaymentClient.CODE_OTHER)
+ }
+
+ override fun onProductDetailsResponse(
+ billingResult: IBillingResult,
+ productDetails: List
+ ) {
+ logD("onProductDetailsResponse() billingResult:${billingResult.getResponseCode()} productDetails:${productDetails.size}")
+ if (billingResult.isResponseOk()) {
+ val item = productDetails.firstOrNull {
+ it.getProductId() == paymentIntent?.productId
+ }
+ productItem = item
+ if (item != null) {
+ tryLaunch()
+ } else {
+ callFailed(IPaymentClient.CODE_NOT_FOUND)
+ }
+ } else {
+ callFailed(IPaymentClient.CODE_NOT_FOUND)
+ }
+ }
+
+ private fun callSuccess(orderRecordId: String) {
+ logD("callSuccess() orderRecordId:${orderRecordId} productId:${paymentIntent?.productId}")
+ paymentIntent?.let {
+ it.listener.onResponse(PaymentResult.PaymentSuccess(it.productId, orderRecordId))
+ }
+ paymentIntent = null
+ dialogManager.dismissDialog()
+ }
+
+ private fun callFailed(code: Int, throwable: Throwable? = null) {
+ throwable?.printStackTrace()
+ logD("callFailed() code:${code} throwable:${throwable?.message}")
+ throwable?.let {
+ SingleToastUtil.showToast(
+ it.message
+ )
+ }
+ paymentIntent?.let {
+ it.listener.onResponse(PaymentResult.PaymentFailed(it.productId, code, throwable))
+ }
+ paymentIntent = null
+ dialogManager.dismissDialog()
+ }
+
+ private fun getCompositeDisposable(): CompositeDisposable {
+ var disposable = compositeDisposable
+ if (disposable == null) {
+ disposable = CompositeDisposable()
+ compositeDisposable = disposable
+ }
+ return disposable
+ }
+
+ private fun addDisposable(disposable: Disposable) {
+ getCompositeDisposable().add(disposable)
+ }
+
+ override fun onCleared() {
+ logD("onCleared()")
+ paymentIntent = null
+ compositeDisposable?.dispose()
+ compositeDisposable = null
+ dialogManager.dismissDialog()
+ }
+
+ 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()
+ }
+
+ else -> {
+
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/chwl/app/ui/wallet/payment/IPaymentClient.kt b/app/src/main/java/com/chwl/app/ui/wallet/payment/IPaymentClient.kt
new file mode 100644
index 000000000..6d0e8b10e
--- /dev/null
+++ b/app/src/main/java/com/chwl/app/ui/wallet/payment/IPaymentClient.kt
@@ -0,0 +1,33 @@
+package com.chwl.app.ui.wallet.payment
+
+import com.example.lib_utils.ICleared
+
+interface IPaymentClient : ICleared {
+ companion object {
+ // 支付成功
+ const val CODE_SUCCESS = 200
+
+ // 未知异常原因
+ const val CODE_OTHER = 0
+
+ // 服务不可用
+ const val CODE_UNAVAILABLE = 1
+
+ // 查询订单信息失败
+ const val CODE_NOT_FOUND = 2
+
+ // 预下单失败
+ const val CODE_PLACE_ORDER_FAILED = 3
+
+ // 验证订单失败
+ const val CODE_VERIFY_ORDER_FAILED = 4
+ }
+
+ fun launchPayment(intent: PaymentIntent)
+
+ override fun onCleared()
+
+ interface Listener {
+ fun onResponse(result: PaymentResult)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/chwl/app/ui/wallet/payment/PaymentIntent.kt b/app/src/main/java/com/chwl/app/ui/wallet/payment/PaymentIntent.kt
new file mode 100644
index 000000000..38911660e
--- /dev/null
+++ b/app/src/main/java/com/chwl/app/ui/wallet/payment/PaymentIntent.kt
@@ -0,0 +1,4 @@
+package com.chwl.app.ui.wallet.payment
+
+class PaymentIntent(val productId: String, val listener: IPaymentClient.Listener) {
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/chwl/app/ui/wallet/payment/PaymentResult.kt b/app/src/main/java/com/chwl/app/ui/wallet/payment/PaymentResult.kt
new file mode 100644
index 000000000..839869072
--- /dev/null
+++ b/app/src/main/java/com/chwl/app/ui/wallet/payment/PaymentResult.kt
@@ -0,0 +1,12 @@
+package com.chwl.app.ui.wallet.payment
+
+sealed class PaymentResult {
+
+ data class PaymentSuccess(val productId: String, val orderId: String) : PaymentResult()
+
+ data class PaymentFailed(
+ val productId: String,
+ val code: Int,
+ val exception: Throwable? = null
+ ) : PaymentResult()
+}
diff --git a/app/src/main/java/com/chwl/app/ui/webview/CommonWebViewActivity.java b/app/src/main/java/com/chwl/app/ui/webview/CommonWebViewActivity.java
index be902be58..f268015f3 100644
--- a/app/src/main/java/com/chwl/app/ui/webview/CommonWebViewActivity.java
+++ b/app/src/main/java/com/chwl/app/ui/webview/CommonWebViewActivity.java
@@ -91,6 +91,8 @@ public class CommonWebViewActivity extends BaseActivity {
private static final String POSITION = "position";
private int mPosition;
+ private JSInterface jsInterface;
+
public static void start(Context context, String url) {
Intent intent = new Intent(context, CommonWebViewActivity.class);
intent.putExtra("url", url);
@@ -194,7 +196,7 @@ public class CommonWebViewActivity extends BaseActivity {
webView.getSettings().setMixedContentMode(WebSettings.MIXED_CONTENT_COMPATIBILITY_MODE);
}
webView.getSettings().setTextZoom(100);
- JSInterface jsInterface = new JSInterface(webView, this);
+ jsInterface = new JSInterface(webView, this);
jsInterface.setPosition(mPosition);
webView.addJavascriptInterface(jsInterface, "androidJsObj");
webView.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE);
@@ -441,6 +443,9 @@ public class CommonWebViewActivity extends BaseActivity {
@Override
protected void onDestroy() {
+ if (jsInterface != null) {
+ jsInterface.onCleared();
+ }
EventBus.getDefault().unregister(this);
if (webViewCallBack != null) {
diff --git a/app/src/main/java/com/chwl/app/ui/webview/CommonWebViewFragment.java b/app/src/main/java/com/chwl/app/ui/webview/CommonWebViewFragment.java
index 193145e14..a327d7270 100644
--- a/app/src/main/java/com/chwl/app/ui/webview/CommonWebViewFragment.java
+++ b/app/src/main/java/com/chwl/app/ui/webview/CommonWebViewFragment.java
@@ -1,8 +1,6 @@
package com.chwl.app.ui.webview;
import android.content.DialogInterface;
-import android.content.Intent;
-import android.net.Uri;
import android.net.http.SslError;
import android.os.Build;
import android.text.TextUtils;
@@ -16,7 +14,6 @@ import androidx.appcompat.app.AlertDialog;
import com.orhanobut.logger.Logger;
import com.chwl.app.R;
import com.chwl.app.base.BaseBindingFragment;
-import com.chwl.app.common.widget.dialog.BaseAlertDialogBuilder;
import com.chwl.app.databinding.FragmentCommonWebViewBinding;
import com.chwl.library.annatation.ActLayoutRes;
import com.chwl.library.utils.ResUtil;
@@ -26,6 +23,7 @@ public class CommonWebViewFragment extends BaseBindingFragment html js 与webview 交互接口
* Created by ${user} on 2017/11/6.
*/
-public class JSInterface {
+public class JSInterface implements ICleared {
private static final String TAG = JSInterface.class.getSimpleName();
private WebView mWebView;
private CommonWebViewActivity mActivity;
@@ -75,6 +83,7 @@ public class JSInterface {
private MediaRecorder recorder;
private File myRecAudioFile;
private ExtAudioRecorder extAudioRecorder;
+ private GPaymentClient paymentClient;
public JSInterface(WebView webView, CommonWebViewActivity activity) {
mWebView = webView;
@@ -87,6 +96,68 @@ public class JSInterface {
this.context = context;
}
+ private void loadUrl(String url) {
+ com.example.lib_utils.log.LogUtil.d("JSInterface", "loadUrl url:" + url, false);
+ if (Looper.myLooper() == Looper.getMainLooper()) {
+ if (mWebView != null) {
+ mWebView.loadUrl(url);
+ }
+ } else {
+ if (mActivity != null) {
+ mActivity.runOnUiThread(() -> {
+ if (mWebView != null) {
+ mWebView.loadUrl(url);
+ }
+ });
+ }
+ }
+ }
+
+ private void callJsWithJson(String name, Object params) {
+ if (name == null) {
+ return;
+ }
+ if (params != null) {
+ String jsonStr = JsonUtils.toJson(params);
+ loadUrl("javascript:" + name + "(" + jsonStr + ")");
+ } else {
+ loadUrl("javascript:" + name + "()");
+ }
+ }
+
+ /**
+ * 拉起本地支付
+ */
+ @JavascriptInterface
+ public void openPayment(String productId) {
+ com.example.lib_utils.log.LogUtil.d("JSInterface", "openPayment productId:" + productId, false);
+ if (mActivity == null || TextUtils.isEmpty(productId)) {
+ return;
+ }
+ mActivity.runOnUiThread(() -> {
+ if (paymentClient == null) {
+ paymentClient = new GPaymentClient(mActivity);
+ }
+ PaymentIntent paymentIntent = new PaymentIntent(productId, new IPaymentClient.Listener() {
+ @Override
+ public void onResponse(@NonNull PaymentResult result) {
+ HashMap map = new HashMap<>();
+ if (result instanceof PaymentResult.PaymentSuccess) {
+ map.put("orderId", ((PaymentResult.PaymentSuccess) result).getOrderId());
+ map.put("productId", ((PaymentResult.PaymentSuccess) result).getProductId());
+ map.put("code", 200);
+ } else if (result instanceof PaymentResult.PaymentFailed) {
+ map.put("code", ((PaymentResult.PaymentFailed) result).getCode());
+ map.put("productId", ((PaymentResult.PaymentFailed) result).getProductId());
+ }
+ callJsWithJson("openPaymentCallback", map);
+ }
+ });
+ paymentClient.launchPayment(paymentIntent);
+ });
+ }
+
+
/**
* 调转个人主页
*
@@ -122,7 +193,7 @@ public class JSInterface {
map.put(IReportConstants.MODULE, IReportConstants.MOLISTAR_PAY);
ReportManager.get().reportEvent(IReportConstants.PAYPAGE_SHOW, map);
// if (AppMetaDataUtil.getChannelID().equals(Constants.GOOGLE)) {
- ChargeActivity.start(context);
+ ChargeActivity.start(context);
// } else {
// CommonWebViewActivity.start(
// context, UriProvider.getOfficialPay(
@@ -175,7 +246,7 @@ public class JSInterface {
if (activity == null) {
return;
}
- ShareInviteInfo info = new Gson().fromJson(json,ShareInviteInfo.class);
+ ShareInviteInfo info = new Gson().fromJson(json, ShareInviteInfo.class);
if (info.getType() != null) {
if (info.getType() == 1) {
activity.runOnUiThread(() -> {
@@ -556,4 +627,12 @@ public class JSInterface {
PraiseModel.get().praise(Long.parseLong(uid), true).subscribe();
NimP2PMessageActivity.start(context, uid);
}
+
+ @Override
+ public void onCleared() {
+ ICleared.super.onCleared();
+ if (paymentClient != null) {
+ paymentClient.onCleared();
+ }
+ }
}