From af6398354cabb3ab37bfcdf392ef243a839866c0 Mon Sep 17 00:00:00 2001 From: gongduoxiang Date: Tue, 6 Aug 2024 10:28:19 +0800 Subject: [PATCH] =?UTF-8?q?=E8=B0=B7=E6=AD=8C=E6=94=AF=E4=BB=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yunbao/common/http/CommonHttpConsts.java | 2 +- .../yunbao/common/http/CommonHttpUtil.java | 7 +- .../yunbao/common/pay/google/GooglePlay.java | 297 ++++++++++++++++++ config.gradle | 6 +- .../yunbao/main/activity/GoogleFragment.java | 64 ++-- .../main/activity/MyWalletActivity.java | 63 +--- 6 files changed, 332 insertions(+), 107 deletions(-) create mode 100644 common/src/main/java/com/yunbao/common/pay/google/GooglePlay.java diff --git a/common/src/main/java/com/yunbao/common/http/CommonHttpConsts.java b/common/src/main/java/com/yunbao/common/http/CommonHttpConsts.java index 396a8f719..5e650eaf7 100644 --- a/common/src/main/java/com/yunbao/common/http/CommonHttpConsts.java +++ b/common/src/main/java/com/yunbao/common/http/CommonHttpConsts.java @@ -20,7 +20,7 @@ public class CommonHttpConsts { public static final String DOWNLOAD_GIF = "downloadGif"; public static final String GET_BALANCE = "getBalance"; public static final String CHECK_TOKEN_INVALID = "checkTokenInvalid"; - public static final String NOTIFY_GOOGLE = "Charge.google_pay"; + public static final String NOTIFY_GOOGLE = "Charge.goole_validate_panduola"; public static final String COMMUNITY_SETREPORT = "Community.setReport"; public static final String GET_USER_HOME = "getUserHome"; diff --git a/common/src/main/java/com/yunbao/common/http/CommonHttpUtil.java b/common/src/main/java/com/yunbao/common/http/CommonHttpUtil.java index 348558d19..0f5a98c86 100644 --- a/common/src/main/java/com/yunbao/common/http/CommonHttpUtil.java +++ b/common/src/main/java/com/yunbao/common/http/CommonHttpUtil.java @@ -419,13 +419,10 @@ public class CommonHttpUtil { .execute(callback); } - public static void notifyGoogle(String purchaseToken, String orderNo, String tradeNo, String allData, String gps_adid, HttpCallback callback) { + public static void notifyGoogle(String purchaseToken, String productId, HttpCallback callback) { HttpClient.getInstance().get(CommonHttpConsts.NOTIFY_GOOGLE, CommonHttpConsts.NOTIFY_GOOGLE) .params("purchaseToken", purchaseToken) - .params("orderno", orderNo) - .params("trade_no", tradeNo) - .params("allData", allData) - .params("gps_adid", gps_adid) + .params("productId", productId) .params("package_name", "com.pandora.sy") .execute(callback); } diff --git a/common/src/main/java/com/yunbao/common/pay/google/GooglePlay.java b/common/src/main/java/com/yunbao/common/pay/google/GooglePlay.java new file mode 100644 index 000000000..db5fec7e9 --- /dev/null +++ b/common/src/main/java/com/yunbao/common/pay/google/GooglePlay.java @@ -0,0 +1,297 @@ +package com.yunbao.common.pay.google; + +import android.app.Activity; +import android.util.Log; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.android.billingclient.api.BillingClient; +import com.android.billingclient.api.BillingClientStateListener; +import com.android.billingclient.api.BillingFlowParams; +import com.android.billingclient.api.BillingResult; +import com.android.billingclient.api.ConsumeParams; +import com.android.billingclient.api.ProductDetails; +import com.android.billingclient.api.Purchase; +import com.android.billingclient.api.PurchasesUpdatedListener; +import com.android.billingclient.api.QueryProductDetailsParams; +import com.android.billingclient.api.QueryPurchasesParams; +import com.google.android.gms.ads.identifier.AdvertisingIdClient; +import com.google.android.gms.common.ConnectionResult; +import com.google.android.gms.common.GoogleApiAvailability; +import com.google.common.collect.ImmutableList; +import com.yunbao.common.CommonAppContext; +import com.yunbao.common.R; +import com.yunbao.common.http.CommonHttpUtil; +import com.yunbao.common.http.HttpCallback; + +import java.util.ArrayList; +import java.util.List; + +//谷歌支付 +public class GooglePlay implements PurchasesUpdatedListener { + + private String TAG = "mLog"; + private BillingClient billingClient; + private GoogleBillingListener billingListener; + + private GooglePlay() { + init(); + } + + private boolean init() { + if (getGoogleService() && billingClient == null) { + billingClient = BillingClient.newBuilder(CommonAppContext.sInstance) + .setListener(this) + .enablePendingPurchases() + .build(); + startConnection(); + return true; + } + if (billingClient != null && !billingClient.isReady()) {//没有连接的话去连接 + startConnection(); + } + if (billingClient == null) + return false; + return true; + } + + private void startConnection() { + if (!billingClient.isReady()) { + //请求连接到GooglePay + billingClient.startConnection(new BillingClientStateListener() { + @Override + public void onBillingSetupFinished(@NonNull BillingResult billingResult) { + int code = billingResult.getResponseCode(); + if (code != BillingClient.BillingResponseCode.OK) { + String msg = billingResult.getDebugMessage(); + Log.e(TAG, "连接到GooglePay失败 code = " + code + " msg = " + msg); + return; + } + Log.e(TAG, "连接到GooglePay成功"); + } + + //连接失败 + @Override + public void onBillingServiceDisconnected() { + Log.e(TAG, "连接到GooglePay失败,请重试"); + } + }); + } + } + + + //点击商品,先查询商品 然后出来支付界面,调用下单 + public void purchase(Activity activity, String orderNumber, String id) { + if (!init()) { + return; + } + ImmutableList productList = ImmutableList.of(QueryProductDetailsParams.Product.newBuilder() + .setProductId(id) + .setProductType(BillingClient.ProductType.INAPP) + .build()); + QueryProductDetailsParams queryProductDetailsParams = + QueryProductDetailsParams.newBuilder() + .setProductList(productList) + .build(); + billingClient.queryProductDetailsAsync( + queryProductDetailsParams, + (billingResult, list) -> { + //查询商品成功 + int code = billingResult.getResponseCode(); + if (code != BillingClient.BillingResponseCode.OK || list == null || list.isEmpty()) { + String msg = billingResult.getDebugMessage(); + Log.e(TAG, "查询商品失败 code = " + code + " msg = " + msg); + return; + } + Log.e(TAG, "查询商品成功"); + buyIt(activity, orderNumber, list.get(0)); + } + ); + } + + //开始下单,准备生成订单了 + private void buyIt(Activity activity, String orderNumber, ProductDetails productDetails) { + List productDetailsParamsList = new ArrayList<>(); + productDetailsParamsList.add(BillingFlowParams.ProductDetailsParams.newBuilder() + // retrieve a value for "productDetails" by calling queryProductDetailsAsync() + .setProductDetails(productDetails) + // For one-time products, "setOfferToken" method shouldn't be called. + // For subscriptions, to get an offer token, call + // ProductDetails.subscriptionOfferDetails() for a list of offers + // that are available to the user. + //一次性商品不需要传token +// .setOfferToken(selectedOfferToken) + .build()); + + BillingFlowParams billingFlowParams = BillingFlowParams.newBuilder() + .setProductDetailsParamsList(productDetailsParamsList) + .setObfuscatedAccountId(orderNumber)//好像是账号id + .build(); + + BillingResult billingResult = billingClient.launchBillingFlow(activity, billingFlowParams); + int code = billingResult.getResponseCode(); + if (code != BillingClient.BillingResponseCode.OK) { + String msg = billingResult.getDebugMessage(); + Log.e(TAG, "购买商品失败 code = " + code + " msg = " + msg); +// ToastUtil.show(getString(R.string.pay_suc)); + return; + } + Log.e(TAG, "购买商品 " + productDetails.toString()); + } + + //消耗商品 支付成功之后,调用我们后台下发商品成功之后,调用消耗 + public void consume(List list) { + if (!init()) { + return; + } + for (Purchase purchase : list) { + getConsumeGoods(purchase); + } + } + + /** + * 消耗所有商品 + */ + public void consumeAll() { + if (!init()) { + return; + } + //以下示例展示了如何提取用户的订阅购买交易。请注意,queryPurchasesAsync() 仅返回有效订阅和非消耗型一次性购买交易。 + QueryPurchasesParams inAppPurchasesQuery = QueryPurchasesParams.newBuilder().setProductType(BillingClient.ProductType.INAPP).build(); + billingClient.queryPurchasesAsync(inAppPurchasesQuery, (billingResult, list) -> { + if (BillingClient.BillingResponseCode.OK == billingResult.getResponseCode()) { + for (Purchase purchase : list) { + //0:PurchaseState.UNSPECIFIED_STATE:未知状态 + //1:PurchaseState.PURCHASED:付款完成 + //2:PurchaseState.PENDING:购买正在等待付款完成。 + if (Purchase.PurchaseState.PURCHASED == purchase.getPurchaseState()) { + //调用google去消费 + //如果之后还出现谷歌掉单的行为在来处理 + CommonHttpUtil.notifyGoogle(purchase.getPurchaseToken(), + purchase.getProducts().get(0), new HttpCallback() { + @Override + public void onSuccess(int code, String msg, String[] info) { + if (code == 0) { + getConsumeGoods(purchase); + } + } + }); + } + } + } + }); + } + + /** + * 公共消费商品接口 + */ + private void getConsumeGoods(Purchase purchase) { + if (purchase != null) { + Log.i(TAG, "-----开始消耗商品:" + purchase.toString()); + ConsumeParams.Builder consumeParams = ConsumeParams.newBuilder(); + consumeParams.setPurchaseToken(purchase.getPurchaseToken()); + //调用消耗商品方法 + consumeAsync(consumeParams.build(), purchase); + } + } + + /** + * 消耗商品 + * int SERVICE_TIMEOUT = -3; //服务超时 + * int FEATURE_NOT_SUPPORTED = -2; //不支持功能 + * int SERVICE_DISCONNECTED = -1; //服务单元已断开 + * int OK = 0; //成功 + * int USER_CANCELED = 1; //用户按上一步或取消对话框 + * int SERVICE_UNAVAILABLE = 2; //网络连接断开 + * int BILLING_UNAVAILABLE = 3; //所请求的类型不支持 Google Play 结算服务 AIDL 版本 + * int ITEM_UNAVAILABLE = 4; //请求的商品已不再出售。 + * int DEVELOPER_ERROR = 5; //提供给 API 的参数无效。此错误也可能说明应用未针对结算服务正确签名或设置,或者在其清单中缺少必要的权限。 + * int ERROR = 6; //API 操作期间出现严重错误 + * int ITEM_ALREADY_OWNED = 7; //未能购买,因为已经拥有此商品 + * int ITEM_NOT_OWNED = 8; //未能消费,因为尚未拥有此商品 + */ + private void consumeAsync(ConsumeParams consumeParams, Purchase purchase) { + if (!init()) { + return; + } + billingClient.consumeAsync(consumeParams, (billingResult, purchaseToken) -> { + if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) { + Log.i(TAG, "-----消耗商品成功"); + } else { + Log.i(TAG, "-----消耗商品失败" + billingResult.toString() + "---" + purchaseToken + "--code:" + billingResult.getResponseCode()); + } + }); + } + + @Override + public void onPurchasesUpdated(@NonNull BillingResult billingResult, @Nullable List purchases) { + if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK + && purchases != null) { + //支付成功 + if (billingListener != null)//消耗掉商品放到外面调用我们服务器成功的时候去消耗 todo 暂时注释掉 这样可以模拟掉单的问题 + billingListener.onPaySuccess(purchases); + /* + * 一旦您验证了购买交易,您的应用就可以向用户授予使用权了。若要确认与购买交易相关联的用户账号, + * 您可以使用 Purchases.products:get 返回的 ProductPurchase.obfuscatedExternalAccountId(适用于应用内商品的购买交易) + * 和 Purchases.subscriptions:get 返回的 SubscriptionPurchase.obfuscatedExternalAccountId(适用于服务器端的订阅), + * 或者 Purchase.getAccountIdentifiers() 在客户端返回的 obfuscatedAccountId(如果在交易时已使用 setObfuscatedAccountId 设置该 ID)。 + * */ +// purchases.get(0).getAccountIdentifiers() + for (Purchase purchase : purchases) { + Log.d("mLog", "谷歌支付的回调 " + purchase); + } + } else if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.USER_CANCELED) { + //取消支付了 + if (billingListener != null) + billingListener.onPayFailed(CommonAppContext.sInstance.getString(R.string.pay_cancel)); + } else { + //支付失败 + if (billingListener != null) + billingListener.onPayFailed(CommonAppContext.sInstance.getString(R.string.pay_fail)); + } + } + + /** + * 检测GooglePlay服务是否可用(需要导入包api "com.google.android.gms:play-services-location:11.8.0",也可以不检查,跳过这个代码) + */ + public boolean getGoogleService() { + GoogleApiAvailability googleApiAvailability = GoogleApiAvailability.getInstance(); + if (googleApiAvailability != null) { + int resultCode = googleApiAvailability.isGooglePlayServicesAvailable(CommonAppContext.sInstance); + return resultCode == ConnectionResult.SUCCESS; + } + return false; + } + + public String getAdId() { + try { + return AdvertisingIdClient.getAdvertisingIdInfo(CommonAppContext.sInstance).getId(); + } catch (Exception e) { + e.printStackTrace(); + Log.e("GooglePlay", "获取谷歌的id错误了"); + } + return "google_default_id"; + } + + public void setBillingListener(GoogleBillingListener listener) { + billingListener = listener; + } + + /** + * 定义接口返回支付结果 + */ + public interface GoogleBillingListener { + void onPaySuccess(List purchases); + + void onPayFailed(String msg); + } + + public static class GooglePlayHelper { + static GooglePlay googlePlay = new GooglePlay(); + } + + public static GooglePlay getInstance() { + return GooglePlayHelper.googlePlay; + } +} diff --git a/config.gradle b/config.gradle index 00d103a4d..dcffef54a 100644 --- a/config.gradle +++ b/config.gradle @@ -10,9 +10,9 @@ ext { ] manifestPlaceholders = [ //正式、 - serverHost : "https://napi.yaoulive.com", +// serverHost : "https://napi.yaoulive.com", // 测试 -// serverHost : " https://ceshi.yaoulive.com", + serverHost : " https://ceshi.yaoulive.com", buildTime : new Date().format("MM-dd HH:mm", TimeZone.getTimeZone("GMT+8")), //百度语音识别 @@ -23,7 +23,7 @@ ext { // true表示谷歌支付 false // isGooglePlay : false, // true表示谷歌支付 false 0 链接包 1 谷歌包 2华为包 - isGooglePlay : 0, + isGooglePlay : 1, //是否上报异常日志 isUploadLog : true, diff --git a/main/src/main/java/com/yunbao/main/activity/GoogleFragment.java b/main/src/main/java/com/yunbao/main/activity/GoogleFragment.java index 3c2ddda23..c0519899e 100644 --- a/main/src/main/java/com/yunbao/main/activity/GoogleFragment.java +++ b/main/src/main/java/com/yunbao/main/activity/GoogleFragment.java @@ -1,8 +1,6 @@ package com.yunbao.main.activity; -import static com.yunbao.main.activity.MyWalletActivity.dis; - import android.annotation.SuppressLint; import android.os.Bundle; import android.os.Handler; @@ -16,15 +14,17 @@ import android.webkit.WebView; import androidx.fragment.app.Fragment; -import com.facebook.appevents.AppEventsConstants; +import com.android.billingclient.api.Purchase; import com.yunbao.common.http.CommonHttpUtil; import com.yunbao.common.http.HttpCallback; -import com.yunbao.common.utils.GoogleUtils; +import com.yunbao.common.pay.google.GooglePlay; import com.yunbao.common.utils.StringUtil; import com.yunbao.common.utils.ToastUtil; import com.yunbao.main.R; import com.yunbao.main.views.TestWebViewClient; +import java.util.List; + @SuppressLint("ValidFragment") public class GoogleFragment extends Fragment { @@ -38,7 +38,7 @@ public class GoogleFragment extends Fragment { private String url; String adid = null; - GoogleUtils googleUtils; + private GooglePlay googlePlay; boolean isGoogleService = true; @@ -62,17 +62,16 @@ public class GoogleFragment extends Fragment { Log.e("ttt", url); rlWebview.loadUrl(url); - googleUtils = new GoogleUtils(getActivity()); + googlePlay = GooglePlay.getInstance(); // 验证是否已在此设备上安装并启用Google Play服务,以及此设备上安装的旧版本是否为此客户端所需的版本 - if (googleUtils.getGoogleService()) { + if (googlePlay.getGoogleService()) { isGoogleService = true; // 支持Google服务 - initGooglePay(); new Thread() { @Override public void run() { - adid = googleUtils.getAdid(); + adid = googlePlay.getAdId(); } }.start(); } @@ -100,11 +99,6 @@ public class GoogleFragment extends Fragment { String TAG = "GooglePay"; - private void initGooglePay() { - googleUtils = new GoogleUtils(getActivity()); - googleUtils.initGooglePay(); - } - private Handler payHandler = new Handler(); //js调用原生 @@ -117,51 +111,31 @@ public class GoogleFragment extends Fragment { mProductId = ProductId; mOrderid = OrderNumber; MoneyUsds = MoneyUsd; - - googleUtils.setBillingListener(new GoogleUtils.GoogleBillingListener() { + googlePlay.setBillingListener(new GooglePlay.GoogleBillingListener() { @Override - public void onPaySuccess(String token, String orderId) { - payHandler.post(new Runnable() { - @Override - public void run() { - CommonHttpUtil.notifyGoogle(token, orderId, mProductId, mOrderid, adid, new HttpCallback() { + public void onPaySuccess(List purchases) { + Log.i("mLog", "调用谷歌支付成功了 " + purchases.toString()); + CommonHttpUtil.notifyGoogle(purchases.get(0).getPurchaseToken(), + purchases.get(0).getProducts().get(0), new HttpCallback() { @Override public void onSuccess(int code, String msg, String[] info) { if (code == 0) { - Bundle params = new Bundle(); - params.putString("currency", "HKD"); - params.putString("money", MoneyUsds); - Bundle fb_params = new Bundle(); - fb_params.putString(AppEventsConstants.EVENT_PARAM_CURRENCY, "HKD"); - fb_params.putString(AppEventsConstants.EVENT_PARAM_CONTENT_ID, mProductId); - //Google官方充值通知 - Bundle google_params = new Bundle(); - google_params.putString("currency", "HKD"); - google_params.putString("product_id", mProductId); - google_params.putString("transaction_id", mOrderid); - google_params.putString("value", MoneyUsds); - google_params.putString("price", MoneyUsds); - google_params.putString("quantity", "1"); - dis(); + googlePlay.consume(purchases); + getActivity().finish(); ToastUtil.show(getString(R.string.pay_suc)); + } else { + ToastUtil.show(msg); } } }); - } - }); } @Override public void onPayFailed(String msg) { - payHandler.post(new Runnable() { - @Override - public void run() { - ToastUtil.show(msg); - } - }); + ToastUtil.show(msg); } }); - googleUtils.purchase(mProductId); + googlePlay.purchase(getActivity(), mOrderid, mProductId); } lastClickTime = currentTime; diff --git a/main/src/main/java/com/yunbao/main/activity/MyWalletActivity.java b/main/src/main/java/com/yunbao/main/activity/MyWalletActivity.java index fef7cdf9b..28851e4f5 100644 --- a/main/src/main/java/com/yunbao/main/activity/MyWalletActivity.java +++ b/main/src/main/java/com/yunbao/main/activity/MyWalletActivity.java @@ -18,17 +18,18 @@ import androidx.fragment.app.FragmentPagerAdapter; import androidx.viewpager.widget.ViewPager; import com.alibaba.android.arouter.facade.annotation.Route; -import com.yunbao.common.utils.MobclickAgent; import com.yunbao.common.CommonAppConfig; import com.yunbao.common.activity.AbsActivity; import com.yunbao.common.fragment.LoadingDialog; import com.yunbao.common.http.CommonHttpUtil; import com.yunbao.common.http.HttpCallback; import com.yunbao.common.manager.IMLoginManager; +import com.yunbao.common.pay.google.GooglePlay; import com.yunbao.common.pay.hw.HwBuilder; import com.yunbao.common.pay.samsung.SamsungUtil; import com.yunbao.common.utils.GoogleUtils; import com.yunbao.common.utils.L; +import com.yunbao.common.utils.MobclickAgent; import com.yunbao.common.utils.RouteUtil; import com.yunbao.common.utils.ToastUtil; import com.yunbao.main.R; @@ -62,7 +63,7 @@ public class MyWalletActivity extends AbsActivity { public static String orderId; HwBuilder hwBuilder; - GoogleUtils googleUtils; + private GooglePlay googlePlay; LoadingDialog loadingDialog; SamsungUtil samsungUtil; @@ -78,17 +79,15 @@ public class MyWalletActivity extends AbsActivity { mw = MyWalletActivity.this; setTitle(mContext.getString(R.string.wallet)); - if (CommonAppConfig.IS_GOOGLE_PLAY == 1) { - googleUtils = new GoogleUtils(mContext); - googleUtils.initGooglePay(); - } else if (CommonAppConfig.IS_GOOGLE_PLAY == 2) { + if (CommonAppConfig.IS_GOOGLE_PLAY == 2) { hwBuilder = new HwBuilder(MyWalletActivity.this); } else if (CommonAppConfig.IS_GOOGLE_PLAY == 3) { samsungUtil = SamsungUtil.newInstance(mContext); samsungUtil.init(); - }else{ - googleUtils = new GoogleUtils(mContext); - googleUtils.initGooglePay(); + } else { + googlePlay = GooglePlay.getInstance(); + //消耗所有商品 + googlePlay.consumeAll(); } @@ -104,50 +103,8 @@ public class MyWalletActivity extends AbsActivity { loadingDialog.setShowText(getString(R.string.order_query)); if (CommonAppConfig.IS_GOOGLE_PLAY == 1) { - googleUtils.setQueryPurchaseListener(mContext, new GoogleUtils.QueryPurchasesListener() { - @Override - public void onResult(JSONObject obj) { - try { - int code = obj.getInt("querySize"); - if (code == 0) { - payHandler.post(runnable1); - payHandler.postDelayed(runnable2, 1000); - } else { - JSONArray tokenList = obj.getJSONArray("tokenList"); - JSONArray orderList = obj.getJSONArray("orderList"); - String tradeNo = obj.getString("tradeNo"); - - for (int i = 0; i < tokenList.length(); i++) { - int finalI = i; - payHandler.post(new Runnable() { - @Override - public void run() { - //谷歌掉单处理 - try { - CommonHttpUtil.Google_sec_pay(tokenList.getString(finalI), orderList.getString(finalI), tradeNo, new HttpCallback() { - @Override - public void onSuccess(int code, String msg, String[] info) { - if (finalI == tokenList.length() - 1) { - loadingDialog.setShowText(getString(R.string.order_query_success)); - loadingDialog.dismiss(); - } - ToastUtil.show("充值已到账"); - finish(); - } - }); - } catch (JSONException e) { - throw new RuntimeException(e); - } - } - }); - } - } - } catch (JSONException e) { - throw new RuntimeException(e); - } - } - }); - googleUtils.queryPurchasesAsync(); + //消耗所有商品 + googlePlay.consumeAll(); } else if (CommonAppConfig.IS_GOOGLE_PLAY == 2) { hwBuilder.consume(); payHandler.post(runnable1);