feat:初步搭建google隔离架构

This commit is contained in:
Max
2023-11-22 21:35:05 +08:00
parent 7291b61e44
commit a7ba26a85b
114 changed files with 1510 additions and 501 deletions

View File

@@ -303,6 +303,8 @@ dependencies {
implementation 'com.contrarywind:wheelview:4.1.0' implementation 'com.contrarywind:wheelview:4.1.0'
implementation 'tech.sud.mgp:SudMGP-static:1.3.3.1158' implementation 'tech.sud.mgp:SudMGP-static:1.3.3.1158'
implementation project(':modules:module_google')
} }
channel { channel {

View File

@@ -14,8 +14,9 @@ import android.util.Log;
import androidx.multidex.MultiDex; import androidx.multidex.MultiDex;
import com.alibaba.android.arouter.launcher.ARouter;
import com.bumptech.glide.request.target.ViewTarget; import com.bumptech.glide.request.target.ViewTarget;
import com.chuhai.utils.LanguageUtils; import com.example.lib_utils.LanguageUtils;
import com.coorchice.library.utils.LogUtils; import com.coorchice.library.utils.LogUtils;
import com.facebook.stetho.Stetho; import com.facebook.stetho.Stetho;
import com.hjq.toast.ToastUtils; import com.hjq.toast.ToastUtils;
@@ -208,6 +209,13 @@ public class XChatApplication extends BaseApp {
initEnv(); initEnv();
// ARouter
if (isDebug()) { // These two lines must be written before init, otherwise these configurations will be invalid in the init process
ARouter.openLog(); // Print log
ARouter.openDebug(); // Turn on debugging mode (If you are running in InstantRun mode, you must turn on debug mode! Online version needs to be closed, otherwise there is a security risk)
}
ARouter.init(application); // As early as possible, it is recommended to initialize in the Application
//延迟初始化云信 //延迟初始化云信
NIMClient.init(context, null, options()); NIMClient.init(context, null, options());

View File

@@ -16,18 +16,18 @@ import android.view.WindowManager
import android.widget.PopupWindow import android.widget.PopupWindow
import android.widget.TextView import android.widget.TextView
import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.GridLayoutManager
import com.android.billingclient.api.BillingClient
import com.android.billingclient.api.BillingResult
import com.android.billingclient.api.ProductDetails
import com.android.billingclient.api.Purchase
import com.appsflyer.AFInAppEventParameterName import com.appsflyer.AFInAppEventParameterName
import com.appsflyer.AFInAppEventType import com.appsflyer.AFInAppEventType
import com.appsflyer.AppsFlyerLib import com.appsflyer.AppsFlyerLib
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 com.netease.nim.uikit.common.util.sys.ScreenUtil import com.netease.nim.uikit.common.util.sys.ScreenUtil
import com.yizhuan.habu.R import com.yizhuan.habu.R
import com.yizhuan.habu.base.BaseViewBindingActivity import com.yizhuan.habu.base.BaseViewBindingActivity
import com.yizhuan.habu.databinding.DialogFirstChargeBinding import com.yizhuan.habu.databinding.DialogFirstChargeBinding
import com.yizhuan.habu.ui.pay.BillingManager
import com.yizhuan.habu.ui.setting.ModifyPwdActivity import com.yizhuan.habu.ui.setting.ModifyPwdActivity
import com.yizhuan.habu.ui.webview.CommonWebViewActivity import com.yizhuan.habu.ui.webview.CommonWebViewActivity
import com.yizhuan.habu.ui.widget.magicindicator.buildins.UIUtil import com.yizhuan.habu.ui.widget.magicindicator.buildins.UIUtil
@@ -56,14 +56,14 @@ import org.greenrobot.eventbus.ThreadMode
* desc: 限时首充 * desc: 限时首充
*/ */
class FirstChargeDialog : BaseViewBindingActivity<DialogFirstChargeBinding>(), class FirstChargeDialog : BaseViewBindingActivity<DialogFirstChargeBinding>(),
BillingManager.BillingUpdatesListener { IBillingService.Listener {
private var goodsList: List<FirstChargeGoods>? = null private var goodsList: List<FirstChargeGoods>? = null
private var currGoods: FirstChargeGoods? = null private var currGoods: FirstChargeGoods? = null
private lateinit var helpPopupWindow: PopupWindow private lateinit var helpPopupWindow: PopupWindow
private var billingManager: BillingManager? = null private var billingManager: IBillingService? = null
private var position = -1 private var position = -1
private val mReward2Adapter by lazy { Reward2Adapter() } private val mReward2Adapter by lazy { Reward2Adapter() }
@@ -220,7 +220,7 @@ class FirstChargeDialog : BaseViewBindingActivity<DialogFirstChargeBinding>(),
} }
private fun initBilling() { private fun initBilling() {
billingManager = BillingManager(this, this) billingManager = IGoogleService.newBillingService(this,this)
} }
@SuppressLint("CheckResult") @SuppressLint("CheckResult")
@@ -234,50 +234,53 @@ class FirstChargeDialog : BaseViewBindingActivity<DialogFirstChargeBinding>(),
for (bean in goodsList) { for (bean in goodsList) {
productKeys.add(bean.chargeProdId) productKeys.add(bean.chargeProdId)
} }
billingManager?.querySkuDetailsAsync(productKeys) { billingResult: BillingResult, productDetails: MutableList<ProductDetails> -> billingManager?.querySkuDetailsAsync(productKeys,object :IBillingService.ProductDetailsResponseListener{
if (billingResult.responseCode != BillingClient.BillingResponseCode.OK) { override fun onProductDetailsResponse(
Log.w( billingResult: IBillingResult,
TAG, productDetails: List<IProductDetails>
"Unsuccessful query for type: " + BillingClient.ProductType.INAPP + ". Error code: " + billingResult.responseCode ) {
) if (!billingResult.isResponseOk()) {
return@querySkuDetailsAsync Log.w(
} TAG,
if (productDetails.isNotEmpty()) { "Unsuccessful query for Error code: " + billingResult.getResponseCode()
for (chargeBean in goodsList) { )
for (skuDetails in productDetails) { }else if (productDetails.isNotEmpty()) {
if (skuDetails.productId == chargeBean.chargeProdId) { for (chargeBean in goodsList) {
chargeBean.productDetails = skuDetails for (skuDetails in productDetails) {
break if (skuDetails.getProductId() == chargeBean.chargeProdId) {
chargeBean.productDetails = skuDetails
break
}
} }
} }
} }
} }
} })
} }
/*商品更新回调*/ /*商品更新回调*/
@SuppressLint("CheckResult") @SuppressLint("CheckResult")
override fun onPurchasesUpdated(purchases: List<Purchase>) { override fun onPurchasesUpdated(purchases: List<IPurchase>) {
for (purchase in purchases) { for (purchase in purchases) {
if (purchase.purchaseState == Purchase.PurchaseState.PURCHASED && if (purchase.isPurchasedState() &&
purchase.accountIdentifiers != null purchase.getAccountIdentifiers() != null
) { ) {
PayModel.get().verifyOrder( PayModel.get().verifyOrder(
purchase.accountIdentifiers!!.obfuscatedAccountId, purchase.getAccountIdentifiers()!!.getObfuscatedAccountId(),
purchase.products[0], purchase.getProducts()[0],
purchase.packageName, purchase.getPackageName(),
purchase.purchaseToken purchase.getPurchaseToken()
) )
.compose(bindToLifecycle()) .compose(bindToLifecycle())
.subscribe( .subscribe(
{ token: String? -> { token: String ->
//L.i("token=" + token); //L.i("token=" + token);
billingManager?.consumeAsync(token) billingManager?.consumeAsync(token)
var skuDetails: ProductDetails? = null var skuDetails: IProductDetails? = null
val goodList = goodsList val goodList = goodsList
if (!goodList.isNullOrEmpty()) { if (!goodList.isNullOrEmpty()) {
for (datum in goodList) { for (datum in goodList) {
if (datum.chargeProdId == purchase.products[0]) { if (datum.chargeProdId == purchase.getProducts()[0]) {
skuDetails = datum.productDetails skuDetails = datum.productDetails
break break
} }
@@ -288,12 +291,14 @@ class FirstChargeDialog : BaseViewBindingActivity<DialogFirstChargeBinding>(),
HashMap() HashMap()
eventValue[AFInAppEventParameterName.CONTENT_TYPE] = "Gold" eventValue[AFInAppEventParameterName.CONTENT_TYPE] = "Gold"
eventValue[AFInAppEventParameterName.QUANTITY] = 1 eventValue[AFInAppEventParameterName.QUANTITY] = 1
eventValue[AFInAppEventParameterName.CONTENT_ID] = purchase.orderId!! eventValue[AFInAppEventParameterName.CONTENT_ID] = purchase.getOrderId()!!
eventValue[AFInAppEventParameterName.REVENUE] = skuDetails.getOneTimePurchaseOfferDetails()?.let {
skuDetails.oneTimePurchaseOfferDetails?.priceAmountMicros!! / 1000000f eventValue[AFInAppEventParameterName.REVENUE] =
eventValue["Price"] = skuDetails.oneTimePurchaseOfferDetails?.formattedPrice!! it.getPriceAmountMicros() / 1000000f
eventValue[AFInAppEventParameterName.CURRENCY] = eventValue["Price"] = it.getFormattedPrice()
skuDetails.oneTimePurchaseOfferDetails?.priceCurrencyCode!! eventValue[AFInAppEventParameterName.CURRENCY] =
it.getPriceCurrencyCode()
}
AppsFlyerLib.getInstance().logEvent( AppsFlyerLib.getInstance().logEvent(
applicationContext, applicationContext,
AFInAppEventType.PURCHASE, AFInAppEventType.PURCHASE,
@@ -321,10 +326,10 @@ class FirstChargeDialog : BaseViewBindingActivity<DialogFirstChargeBinding>(),
/*购买商品*/ /*购买商品*/
@SuppressLint("CheckResult") @SuppressLint("CheckResult")
fun buyProduct(skuDetails: ProductDetails?) { fun buyProduct(skuDetails: IProductDetails?) {
if (skuDetails != null) { if (skuDetails != null) {
Log.d(TAG, "BuyProduct:" + skuDetails.productId) Log.d(TAG, "BuyProduct:" + skuDetails.getProductId())
PayModel.get().placeOrder(skuDetails.productId) PayModel.get().placeOrder(skuDetails.getProductId())
.compose(bindToLifecycle()) .compose(bindToLifecycle())
.subscribe( .subscribe(
{ recordId: PayRecordId -> { recordId: PayRecordId ->
@@ -345,7 +350,7 @@ class FirstChargeDialog : BaseViewBindingActivity<DialogFirstChargeBinding>(),
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
if (billingManager?.isServiceConnected == true) { if (billingManager?.isServiceConnected() == true) {
billingManager?.onQueryPurchases() billingManager?.onQueryPurchases()
} }
} }

View File

@@ -6,8 +6,8 @@ import android.util.TypedValue
import android.view.LayoutInflater import android.view.LayoutInflater
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.databinding.DataBindingUtil import androidx.databinding.DataBindingUtil
import com.chuhai.utils.ServiceTime import com.example.lib_utils.ServiceTime
import com.chuhai.utils.ktx.singleClick import com.example.lib_utils.ktx.singleClick
import com.yizhuan.habu.R import com.yizhuan.habu.R
import com.yizhuan.habu.avroom.redpackage.open.RedPackageOpenDialog import com.yizhuan.habu.avroom.redpackage.open.RedPackageOpenDialog
import com.yizhuan.habu.common.widget.dialog.DialogManager import com.yizhuan.habu.common.widget.dialog.DialogManager

View File

@@ -11,12 +11,12 @@ import android.view.View
import android.view.WindowManager import android.view.WindowManager
import android.view.animation.LinearInterpolator import android.view.animation.LinearInterpolator
import androidx.core.view.isVisible import androidx.core.view.isVisible
import com.chuhai.utils.ServiceTime import com.example.lib_utils.ServiceTime
import com.chuhai.utils.ktx.getColorById import com.example.lib_utils.ktx.getColorById
import com.chuhai.utils.ktx.singleClick import com.example.lib_utils.ktx.singleClick
import com.chuhai.utils.ktx.toStringRes import com.example.lib_utils.ktx.toStringRes
import com.chuhai.utils.log.ILog import com.example.lib_utils.log.ILog
import com.chuhai.utils.spannable.spannableBuilder import com.example.lib_utils.spannable.spannableBuilder
import com.trello.rxlifecycle3.android.FragmentEvent import com.trello.rxlifecycle3.android.FragmentEvent
import com.yizhuan.habu.R import com.yizhuan.habu.R
import com.yizhuan.habu.avroom.redpackage.RedPackageHandler import com.yizhuan.habu.avroom.redpackage.RedPackageHandler

View File

@@ -2,11 +2,11 @@ package com.yizhuan.habu.avroom.redpackage.send
import android.graphics.Color import android.graphics.Color
import androidx.core.view.isVisible import androidx.core.view.isVisible
import com.chuhai.utils.ktx.addDisableFilter import com.example.lib_utils.ktx.addDisableFilter
import com.chuhai.utils.ktx.getColorById import com.example.lib_utils.ktx.getColorById
import com.chuhai.utils.ktx.singleClick import com.example.lib_utils.ktx.singleClick
import com.chuhai.utils.ktx.toStringRes import com.example.lib_utils.ktx.toStringRes
import com.chuhai.utils.log.ILog import com.example.lib_utils.log.ILog
import com.yizhuan.habu.R import com.yizhuan.habu.R
import com.yizhuan.habu.base.BaseBindingFragment import com.yizhuan.habu.base.BaseBindingFragment
import com.yizhuan.habu.databinding.RedPackagePrivateFragmentBinding import com.yizhuan.habu.databinding.RedPackagePrivateFragmentBinding

View File

@@ -1,9 +1,9 @@
package com.yizhuan.habu.avroom.redpackage.send package com.yizhuan.habu.avroom.redpackage.send
import com.chuhai.utils.ktx.addDisableFilter import com.example.lib_utils.ktx.addDisableFilter
import com.chuhai.utils.ktx.setOnInputChangedListener import com.example.lib_utils.ktx.setOnInputChangedListener
import com.chuhai.utils.ktx.singleClick import com.example.lib_utils.ktx.singleClick
import com.chuhai.utils.ktx.toStringRes import com.example.lib_utils.ktx.toStringRes
import com.yizhuan.habu.R import com.yizhuan.habu.R
import com.yizhuan.habu.base.BaseBindingFragment import com.yizhuan.habu.base.BaseBindingFragment
import com.yizhuan.habu.databinding.RedPackagePublicFragmentBinding import com.yizhuan.habu.databinding.RedPackagePublicFragmentBinding

View File

@@ -6,8 +6,8 @@ import android.os.Bundle
import android.view.Gravity import android.view.Gravity
import android.view.WindowManager import android.view.WindowManager
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import com.chuhai.utils.ktx.singleClick import com.example.lib_utils.ktx.singleClick
import com.chuhai.utils.ktx.toStringRes import com.example.lib_utils.ktx.toStringRes
import com.yizhuan.habu.R import com.yizhuan.habu.R
import com.yizhuan.habu.avroom.redpackage.RedPackageEvent import com.yizhuan.habu.avroom.redpackage.RedPackageEvent
import com.yizhuan.habu.base.BaseDialog import com.yizhuan.habu.base.BaseDialog

View File

@@ -2,7 +2,7 @@ package com.yizhuan.habu.avroom.redpackage.send
import com.chad.library.adapter.base.BaseQuickAdapter import com.chad.library.adapter.base.BaseQuickAdapter
import com.chad.library.adapter.base.BaseViewHolder import com.chad.library.adapter.base.BaseViewHolder
import com.chuhai.utils.ktx.getColorById import com.example.lib_utils.ktx.getColorById
import com.yizhuan.habu.R import com.yizhuan.habu.R
import io.realm.internal.Keep import io.realm.internal.Keep

View File

@@ -8,7 +8,6 @@ import android.widget.FrameLayout;
import androidx.appcompat.widget.AppCompatTextView; import androidx.appcompat.widget.AppCompatTextView;
import com.chuhai.utils.UiUtils;
import com.yizhuan.habu.R; import com.yizhuan.habu.R;
import com.yizhuan.habu.common.util.Utils; import com.yizhuan.habu.common.util.Utils;
import com.yizhuan.habu.ui.widget.magicindicator.buildins.UIUtil; import com.yizhuan.habu.ui.widget.magicindicator.buildins.UIUtil;

View File

@@ -13,7 +13,7 @@ import android.view.WindowManager;
import android.widget.FrameLayout; import android.widget.FrameLayout;
import android.widget.TextView; import android.widget.TextView;
import com.chuhai.core.component.SuperBottomSheetDialog; import com.example.lib_core.component.SuperBottomSheetDialog;
import com.google.android.material.bottomsheet.BottomSheetBehavior; import com.google.android.material.bottomsheet.BottomSheetBehavior;
import com.yizhuan.habu.R; import com.yizhuan.habu.R;
import com.yizhuan.habu.common.util.Utils; import com.yizhuan.habu.common.util.Utils;

View File

@@ -15,8 +15,10 @@ import android.widget.TextView;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat; import androidx.core.content.ContextCompat;
import com.example.module_base.support.google.IGoogleService;
import com.example.module_base.support.login.ILoginService;
import com.netease.nim.uikit.StatusBarUtil; import com.netease.nim.uikit.StatusBarUtil;
import com.netease.nim.uikit.common.util.log.LogUtil;
import com.yizhuan.habu.upgrade.AppUpgradeHelper; import com.yizhuan.habu.upgrade.AppUpgradeHelper;
import com.trello.rxlifecycle3.android.ActivityEvent; import com.trello.rxlifecycle3.android.ActivityEvent;
import com.yizhuan.habu.MainActivity; import com.yizhuan.habu.MainActivity;
@@ -37,16 +39,11 @@ import com.yizhuan.xchat_android_core.auth.event.LoginReportEvent;
import com.yizhuan.xchat_android_library.common.SpConstants; import com.yizhuan.xchat_android_library.common.SpConstants;
import com.yizhuan.xchat_android_library.common.util.SPUtils; import com.yizhuan.xchat_android_library.common.util.SPUtils;
import com.yizhuan.xchat_android_library.utils.AppMetaDataUtil; import com.yizhuan.xchat_android_library.utils.AppMetaDataUtil;
import com.yizhuan.xchat_android_library.utils.DeviceUtils;
import com.yizhuan.xchat_android_library.utils.ResUtil;
import com.yizhuan.xchat_android_library.utils.SingleToastUtil;
import com.yizhuan.xchat_android_library.utils.constant.PackageNameConstants;
import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode; import org.greenrobot.eventbus.ThreadMode;
import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import io.reactivex.SingleObserver; import io.reactivex.SingleObserver;
@@ -79,7 +76,6 @@ public class LoginActivity extends BaseActivity implements View.OnClickListener
HashMap<String, Object> map = new HashMap<>(2); HashMap<String, Object> map = new HashMap<>(2);
map.put(IReportConstants.MODULE, IReportConstants.PEKO_LOGIN); map.put(IReportConstants.MODULE, IReportConstants.PEKO_LOGIN);
ReportManager.get().reportEvent(IReportConstants.LOGIN_SHOW, map); ReportManager.get().reportEvent(IReportConstants.LOGIN_SHOW, map);
// callbackManager = CallbackManager.Factory.create(); // callbackManager = CallbackManager.Factory.create();
// LoginManager.getInstance().registerCallback(callbackManager, new FacebookCallback<LoginResult>() { // LoginManager.getInstance().registerCallback(callbackManager, new FacebookCallback<LoginResult>() {
// @Override // @Override
@@ -288,7 +284,7 @@ public class LoginActivity extends BaseActivity implements View.OnClickListener
case R.id.cs_google: case R.id.cs_google:
reportLoginType(IReportConstants.THREE); reportLoginType(IReportConstants.THREE);
getDialogManager().showProgressDialog(this); getDialogManager().showProgressDialog(this);
AuthModel.get().googleLogin() AuthModel.get().googleLogin(this)
.compose(bindUntilEvent(ActivityEvent.DESTROY)) .compose(bindUntilEvent(ActivityEvent.DESTROY))
.subscribe(new SingleObserver<String>() { .subscribe(new SingleObserver<String>() {
@Override @Override
@@ -328,6 +324,7 @@ public class LoginActivity extends BaseActivity implements View.OnClickListener
@Override @Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) { protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data); super.onActivityResult(requestCode, resultCode, data);
AuthModel.get().getGoogleLoginService().onActivityResult(requestCode, resultCode, data);
// callbackManager.onActivityResult(requestCode, resultCode, data); // callbackManager.onActivityResult(requestCode, resultCode, data);
} }

View File

@@ -1,222 +0,0 @@
package com.yizhuan.habu.ui.pay;
import android.app.Activity;
import android.util.Log;
import com.alibaba.fastjson.JSONObject;
import com.android.billingclient.api.BillingClient;
import com.android.billingclient.api.BillingClient.BillingResponseCode;
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.ProductDetailsResponseListener;
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 org.jetbrains.annotations.NotNull;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class BillingManager implements PurchasesUpdatedListener {
private static final String TAG = "BillingManager";
/*购买key*/
private static final String BASE_64_ENCODED_PUBLIC_KEY = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApNboVqeCAvW1s2mNCaNipu0bd15HC6FP86E1+dTEdMTD9XLWkYiXCzEbt+ciTda/XdAOYYe4YNnyfW7T/a9E7O0ZyjPj08q2LQaMqgTBecpzQhE7ZhYYmh3DdWrGKCEMLImX4yNuEEX9yC/dVP49nHNqfLWxmnzhDrJ5JDSlpvguOI4lMRe0/1gx7kfEeB8DOg8HfvdibiVZI4vhjk9Oz6sWJQZd1/bOuUe4huAj9Ys/4zcgniE8Da45lGdefjn12y7ELhcUZpFLLKvXmj0qnfqBX94CB+wfbEOYvALKaFb+bBZe/a8YEn/9zA4UsA0j+eRweXBb6e1AqaZJ4wp/JQIDAQAB";
/*客户端*/
private BillingClient billingClient;
/*活动*/
private final Activity mActivity;
/*监听*/
private final BillingUpdatesListener mBillingUpdatesListener;
/*是否连接成功*/
private boolean mIsServiceConnected;
/*商品列表*/
private final List<Purchase> purchaseList = new ArrayList<>();
/*监听接口*/
public interface BillingUpdatesListener {
void onBillingClientSetupFinished();
void onPurchasesUpdated(List<Purchase> purchases);
void onConsumeFinished(String token, @BillingResponseCode int result);
void onFailedHandle(@BillingResponseCode int result);
}
public boolean isServiceConnected() {
return mIsServiceConnected;
}
public BillingManager(Activity activity, final BillingUpdatesListener updatesListener) {
mActivity = activity;
mBillingUpdatesListener = updatesListener;
billingClient = BillingClient.newBuilder(mActivity).enablePendingPurchases().setListener(this).build();
startServiceConnection(() -> {
mBillingUpdatesListener.onBillingClientSetupFinished();
onQueryPurchases();
});
}
/*开始连接Play*/
public void startServiceConnection(final Runnable executeOnSuccess) {
billingClient.startConnection(new BillingClientStateListener() {
@Override
public void onBillingSetupFinished(@NotNull BillingResult billingResult) {
Log.d(TAG, "Setup finished. Response code: " + billingResult.getDebugMessage() + " code = " + billingResult.getResponseCode());
if (billingResult.getResponseCode() == BillingResponseCode.OK) {
mIsServiceConnected = true;
if (executeOnSuccess != null) {
executeOnSuccess.run();
}
} else {
mIsServiceConnected = true;
}
}
@Override
public void onBillingServiceDisconnected() {
mIsServiceConnected = false;
}
});
}
/*请求商品库存*/
public void onQueryPurchases() {
Runnable queryToExecute = () ->
billingClient.queryPurchasesAsync(
QueryPurchasesParams.newBuilder()
.setProductType(BillingClient.ProductType.INAPP)
.build(), this::onPurchasesUpdated);
executeServiceRequest(queryToExecute);
}
/*更新商品*/
@Override
public void onPurchasesUpdated(BillingResult billingResult, List<Purchase> purchases) {
Log.i(TAG, "billingResult.getResponseCode()==" + billingResult.getResponseCode());
purchaseList.clear();
if (billingResult.getResponseCode() == BillingResponseCode.OK) {
if (purchases != null) {
for (Purchase purchase : purchases) {
handlePurchase(purchase);
}
}
mBillingUpdatesListener.onPurchasesUpdated(purchaseList);
} else {
if (billingResult.getResponseCode() == BillingResponseCode.USER_CANCELED) {
} else {
}
mBillingUpdatesListener.onFailedHandle(billingResult.getResponseCode());
}
}
/*商品处理*/
private void handlePurchase(Purchase purchase) {
//验证签名数据
if (!verifyValidSignature(purchase.getOriginalJson(), purchase.getSignature())) {
return;
}
purchaseList.add(purchase);
}
/*验证签名*/
private boolean verifyValidSignature(String signedData, String signature) {
try {
return Security.verifyPurchase(BASE_64_ENCODED_PUBLIC_KEY, signedData, signature);
} catch (IOException e) {
Log.e(TAG, "Got an exception trying to validate a purchase: " + e);
return false;
}
}
/*执行服务请求*/
private void executeServiceRequest(Runnable runnable) {
if (mIsServiceConnected) {
runnable.run();
} else {
startServiceConnection(runnable);
}
}
/*查询内购商品详情*/
public void querySkuDetailsAsync(final List<String> productIdList,
final ProductDetailsResponseListener listener) {
Runnable queryRequest = () -> {
ArrayList<QueryProductDetailsParams.Product> products = new ArrayList<>();
for (String productId : productIdList) {
products.add(QueryProductDetailsParams.Product.newBuilder()
.setProductId(productId)
.setProductType(BillingClient.ProductType.INAPP)
.build());
}
QueryProductDetailsParams queryProductDetailsParams =
QueryProductDetailsParams.newBuilder()
.setProductList(products)
.build();
billingClient.queryProductDetailsAsync(
queryProductDetailsParams,
listener
);
};
executeServiceRequest(queryRequest);
}
/*启动购买,订购流程*/
public void initiatePurchaseFlow(final ProductDetails productDetails, String recordId) {
Runnable purchaseFlowRequest = () -> {
BillingFlowParams.ProductDetailsParams p = BillingFlowParams.ProductDetailsParams.newBuilder()
.setProductDetails(productDetails)
.build();
JSONObject jsonObject = new JSONObject();
ProductDetails.OneTimePurchaseOfferDetails oneTimePurchaseOfferDetails = productDetails.getOneTimePurchaseOfferDetails();
if (oneTimePurchaseOfferDetails != null) {
jsonObject.put("p", oneTimePurchaseOfferDetails.getFormattedPrice());
jsonObject.put("a", oneTimePurchaseOfferDetails.getPriceAmountMicros() / 10000);
jsonObject.put("c", oneTimePurchaseOfferDetails.getPriceCurrencyCode());
}
BillingFlowParams purchaseParams = BillingFlowParams.newBuilder()
.setObfuscatedAccountId(recordId)
.setObfuscatedProfileId(jsonObject.toJSONString())
.setProductDetailsParamsList(List.of(p))
.build();
BillingResult billingResult = billingClient.launchBillingFlow(mActivity, purchaseParams);
Log.i(TAG, " initiatePurchaseFlow billingResult=" + billingResult.getResponseCode() + " " + billingResult.getDebugMessage());
};
executeServiceRequest(purchaseFlowRequest);
}
public void consumeAsync(final String purchaseToken) {
final ConsumeParams consumeParams = ConsumeParams.newBuilder().setPurchaseToken(purchaseToken).build();
executeServiceRequest(() -> billingClient.consumeAsync(consumeParams, (billingResult, s) ->
mBillingUpdatesListener.onConsumeFinished(purchaseToken, billingResult.getResponseCode())));
}
/**
* 销毁结算客户端并断开连接
*/
public void destroy() {
Log.d(TAG, "Destroying the manager.");
if (billingClient != null && billingClient.isReady()) {
billingClient.endConnection();
billingClient = null;
}
}
}

View File

@@ -19,16 +19,18 @@ import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat; import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
import com.android.billingclient.api.BillingClient;
import com.android.billingclient.api.ProductDetails;
import com.android.billingclient.api.Purchase;
import com.appsflyer.AFInAppEventParameterName; import com.appsflyer.AFInAppEventParameterName;
import com.appsflyer.AFInAppEventType; import com.appsflyer.AFInAppEventType;
import com.appsflyer.AppsFlyerLib; import com.appsflyer.AppsFlyerLib;
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 com.netease.nim.uikit.StatusBarUtil; import com.netease.nim.uikit.StatusBarUtil;
import com.yizhuan.habu.R; import com.yizhuan.habu.R;
import com.yizhuan.habu.application.IReportConstants; import com.yizhuan.habu.application.IReportConstants;
@@ -70,7 +72,7 @@ import java.util.Map;
*/ */
@CreatePresenter(ChargePresenter.class) @CreatePresenter(ChargePresenter.class)
public class ChargeActivity extends BaseMvpActivity<IChargeView, ChargePresenter> public class ChargeActivity extends BaseMvpActivity<IChargeView, ChargePresenter>
implements IChargeView, BillingManager.BillingUpdatesListener { implements IChargeView, IBillingService.Listener {
private static final String TAG = "ChargeActivity"; private static final String TAG = "ChargeActivity";
private TextView mTv_gold; private TextView mTv_gold;
@@ -83,7 +85,7 @@ public class ChargeActivity extends BaseMvpActivity<IChargeView, ChargePresenter
private final int BINDCODE_GOLD = 200; private final int BINDCODE_GOLD = 200;
private BillingManager billingManager; private IBillingService billingManager;
private int mChargePosition = -1; private int mChargePosition = -1;
@@ -166,7 +168,7 @@ public class ChargeActivity extends BaseMvpActivity<IChargeView, ChargePresenter
/*初始化*/ /*初始化*/
public void initBilling() { public void initBilling() {
billingManager = new BillingManager(this, this); billingManager = IGoogleService.Companion.newBillingService(this, this);
} }
/*客户端设置成功回调*/ /*客户端设置成功回调*/
@@ -186,17 +188,19 @@ public class ChargeActivity extends BaseMvpActivity<IChargeView, ChargePresenter
productKeys.add(chargeBean.getChargeProdId()); productKeys.add(chargeBean.getChargeProdId());
} }
mChargeAdapter.setNewData(chargeBeanList); mChargeAdapter.setNewData(chargeBeanList);
if (billingManager == null) {
return;
}
billingManager.querySkuDetailsAsync(productKeys, (billingResult, productDetails) -> { billingManager.querySkuDetailsAsync(productKeys, (billingResult, productDetails) -> {
if (billingResult.getResponseCode() != BillingClient.BillingResponseCode.OK) { if (!billingResult.isResponseOk()) {
Log.w(TAG, "Unsuccessful query for type: " + BillingClient.ProductType.INAPP Log.w(TAG, "Unsuccessful query for Error code: " + billingResult.getResponseCode());
+ ". Error code: " + billingResult.getResponseCode());
getDialogManager().dismissDialog(); getDialogManager().dismissDialog();
toast(getString(R.string.Recharge_failure)); toast(getString(R.string.Recharge_failure));
} else if (productDetails.size() > 0) { } else if (productDetails.size() > 0) {
getDialogManager().dismissDialog(); getDialogManager().dismissDialog();
List<ChargeBean> showChargeList = new ArrayList<>(); List<ChargeBean> showChargeList = new ArrayList<>();
for (ChargeBean chargeBean : chargeBeanList) { for (ChargeBean chargeBean : chargeBeanList) {
for (ProductDetails product : productDetails) { for (IProductDetails product : productDetails) {
if (product.getProductId().equals(chargeBean.getChargeProdId())) { if (product.getProductId().equals(chargeBean.getChargeProdId())) {
chargeBean.setProductDetails(product); chargeBean.setProductDetails(product);
showChargeList.add(chargeBean); showChargeList.add(chargeBean);
@@ -212,12 +216,13 @@ public class ChargeActivity extends BaseMvpActivity<IChargeView, ChargePresenter
}); });
} }
/*商品更新回调*/ /*商品更新回调*/
@SuppressLint("CheckResult") @SuppressLint("CheckResult")
@Override @Override
public void onPurchasesUpdated(List<Purchase> purchases) { public void onPurchasesUpdated(@Nullable List<? extends IPurchase> purchases) {
for (Purchase purchase : purchases) { for (IPurchase purchase : purchases) {
if (purchase.getPurchaseState() == Purchase.PurchaseState.PURCHASED && if (purchase.isPurchasedState() &&
purchase.getAccountIdentifiers() != null) { purchase.getAccountIdentifiers() != null) {
PayModel.get().verifyOrder( PayModel.get().verifyOrder(
purchase.getAccountIdentifiers().getObfuscatedAccountId(), purchase.getAccountIdentifiers().getObfuscatedAccountId(),
@@ -228,7 +233,7 @@ public class ChargeActivity extends BaseMvpActivity<IChargeView, ChargePresenter
.subscribe(token -> { .subscribe(token -> {
billingManager.consumeAsync(token); billingManager.consumeAsync(token);
ProductDetails productDetails = null; IProductDetails productDetails = null;
for (ChargeBean datum : mChargeAdapter.getData()) { for (ChargeBean datum : mChargeAdapter.getData()) {
if (datum.getChargeProdId().equals(purchase.getProducts().get(0))) { if (datum.getChargeProdId().equals(purchase.getProducts().get(0))) {
productDetails = datum.getProductDetails(); productDetails = datum.getProductDetails();
@@ -240,9 +245,11 @@ public class ChargeActivity extends BaseMvpActivity<IChargeView, ChargePresenter
eventValue.put(AFInAppEventParameterName.CONTENT_TYPE, "Gold"); eventValue.put(AFInAppEventParameterName.CONTENT_TYPE, "Gold");
eventValue.put(AFInAppEventParameterName.QUANTITY, 1); eventValue.put(AFInAppEventParameterName.QUANTITY, 1);
eventValue.put(AFInAppEventParameterName.CONTENT_ID, purchase.getOrderId()); eventValue.put(AFInAppEventParameterName.CONTENT_ID, purchase.getOrderId());
eventValue.put(AFInAppEventParameterName.REVENUE, productDetails.getOneTimePurchaseOfferDetails().getPriceAmountMicros() / 1000000f); if (productDetails.getOneTimePurchaseOfferDetails() != null) {
eventValue.put("Price", productDetails.getOneTimePurchaseOfferDetails().getFormattedPrice()); eventValue.put(AFInAppEventParameterName.REVENUE, productDetails.getOneTimePurchaseOfferDetails().getPriceAmountMicros() / 1000000f);
eventValue.put(AFInAppEventParameterName.CURRENCY, productDetails.getOneTimePurchaseOfferDetails().getPriceCurrencyCode()); eventValue.put("Price", productDetails.getOneTimePurchaseOfferDetails().getFormattedPrice());
eventValue.put(AFInAppEventParameterName.CURRENCY, productDetails.getOneTimePurchaseOfferDetails().getPriceCurrencyCode());
}
AppsFlyerLib.getInstance().logEvent(getApplicationContext(), AFInAppEventType.PURCHASE, eventValue); AppsFlyerLib.getInstance().logEvent(getApplicationContext(), AFInAppEventType.PURCHASE, eventValue);
} }
}, },
@@ -262,12 +269,15 @@ public class ChargeActivity extends BaseMvpActivity<IChargeView, ChargePresenter
} }
/*失败处理*/ /*失败处理*/
public void onFailedHandle(@BillingClient.BillingResponseCode int result) { public void onFailedHandle(int result) {
} }
/*购买商品*/ /*购买商品*/
@SuppressLint("CheckResult") @SuppressLint("CheckResult")
public void buyProduct(ProductDetails productDetails) { public void buyProduct(IProductDetails productDetails) {
if (billingManager == null) {
return;
}
if (productDetails != null) { if (productDetails != null) {
Log.d(TAG, "BuyProduct:" + productDetails.getProductId()); Log.d(TAG, "BuyProduct:" + productDetails.getProductId());
PayModel.get().placeOrder(productDetails.getProductId()) PayModel.get().placeOrder(productDetails.getProductId())

View File

@@ -6,7 +6,7 @@ import android.os.Build
import android.os.Environment import android.os.Environment
import android.text.SpannableString import android.text.SpannableString
import android.view.View import android.view.View
import com.chuhai.utils.log.ILog import com.example.lib_utils.log.ILog
import com.netease.nim.uikit.StatusBarUtil import com.netease.nim.uikit.StatusBarUtil
import com.yizhuan.habu.upgrade.AppUpgradeHelper import com.yizhuan.habu.upgrade.AppUpgradeHelper
import com.yizhuan.habu.BuildConfig import com.yizhuan.habu.BuildConfig

View File

@@ -7,7 +7,7 @@ import android.os.Bundle
import android.view.View import android.view.View
import android.view.WindowManager import android.view.WindowManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.chuhai.utils.UiUtils import com.example.lib_utils.UiUtils
import com.yizhuan.habu.R import com.yizhuan.habu.R
import com.yizhuan.habu.ui.webview.CommonWebViewActivity import com.yizhuan.habu.ui.webview.CommonWebViewActivity
import com.yizhuan.xchat_android_core.home.bean.BannerInfo import com.yizhuan.xchat_android_core.home.bean.BannerInfo

View File

@@ -7,7 +7,7 @@ import android.view.LayoutInflater
import android.view.Window import android.view.Window
import android.view.WindowManager import android.view.WindowManager
import androidx.databinding.DataBindingUtil import androidx.databinding.DataBindingUtil
import com.chuhai.utils.ktx.singleClick import com.example.lib_utils.ktx.singleClick
import com.yizhuan.habu.R import com.yizhuan.habu.R
import com.yizhuan.habu.avroom.activity.AVRoomActivity import com.yizhuan.habu.avroom.activity.AVRoomActivity
import com.yizhuan.habu.databinding.AllServiceGiftGoRoomTipsDialogBinding import com.yizhuan.habu.databinding.AllServiceGiftGoRoomTipsDialogBinding

View File

@@ -12,10 +12,10 @@ import android.view.WindowManager
import android.widget.TextView import android.widget.TextView
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.databinding.DataBindingUtil import androidx.databinding.DataBindingUtil
import com.chuhai.utils.ktx.getColorById import com.example.lib_utils.ktx.getColorById
import com.chuhai.utils.ktx.singleClick import com.example.lib_utils.ktx.singleClick
import com.chuhai.utils.ktx.toStringRes import com.example.lib_utils.ktx.toStringRes
import com.chuhai.utils.spannable.SpannableTextBuilder import com.example.lib_utils.spannable.SpannableTextBuilder
import com.yizhuan.habu.R import com.yizhuan.habu.R
import com.yizhuan.habu.avroom.activity.AVRoomActivity import com.yizhuan.habu.avroom.activity.AVRoomActivity
import com.yizhuan.habu.databinding.DialogGiftAllServiceLevelBinding import com.yizhuan.habu.databinding.DialogGiftAllServiceLevelBinding

View File

@@ -16,7 +16,7 @@ import android.widget.FrameLayout;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import com.chuhai.utils.ServiceTime; import com.example.lib_utils.ServiceTime;
import com.opensource.svgaplayer.SVGADrawable; import com.opensource.svgaplayer.SVGADrawable;
import com.opensource.svgaplayer.SVGADynamicEntity; import com.opensource.svgaplayer.SVGADynamicEntity;
import com.opensource.svgaplayer.SVGAImageView; import com.opensource.svgaplayer.SVGAImageView;

View File

@@ -12,13 +12,14 @@ import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.view.isInvisible import androidx.core.view.isInvisible
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.GridLayoutManager
import com.android.billingclient.api.BillingClient
import com.android.billingclient.api.BillingResult
import com.android.billingclient.api.ProductDetails
import com.android.billingclient.api.Purchase
import com.appsflyer.AFInAppEventParameterName import com.appsflyer.AFInAppEventParameterName
import com.appsflyer.AFInAppEventType import com.appsflyer.AFInAppEventType
import com.appsflyer.AppsFlyerLib import com.appsflyer.AppsFlyerLib
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 com.netease.nim.uikit.StatusBarUtil import com.netease.nim.uikit.StatusBarUtil
import com.netease.nim.uikit.common.util.sys.TimeUtil import com.netease.nim.uikit.common.util.sys.TimeUtil
import com.opensource.svgaplayer.SVGADrawable import com.opensource.svgaplayer.SVGADrawable
@@ -30,8 +31,6 @@ import com.yizhuan.habu.base.BaseViewBindingActivity
import com.yizhuan.habu.base.TitleBar import com.yizhuan.habu.base.TitleBar
import com.yizhuan.habu.common.EmptyViewHelper import com.yizhuan.habu.common.EmptyViewHelper
import com.yizhuan.habu.databinding.ActivityVipMainBinding import com.yizhuan.habu.databinding.ActivityVipMainBinding
import com.yizhuan.habu.ui.pay.BillingManager
import com.yizhuan.habu.ui.pay.BillingManager.BillingUpdatesListener
import com.yizhuan.habu.ui.pay.ChargeActivity import com.yizhuan.habu.ui.pay.ChargeActivity
import com.yizhuan.habu.ui.setting.ModifyPwdActivity import com.yizhuan.habu.ui.setting.ModifyPwdActivity
import com.yizhuan.habu.ui.utils.RVDelegate import com.yizhuan.habu.ui.utils.RVDelegate
@@ -63,7 +62,7 @@ import java.net.MalformedURLException
import java.net.URL import java.net.URL
class VipMainActivity : BaseViewBindingActivity<ActivityVipMainBinding>(), class VipMainActivity : BaseViewBindingActivity<ActivityVipMainBinding>(),
VipMagicIndicatorAdapter.OnItemSelectListener, BillingUpdatesListener { VipMagicIndicatorAdapter.OnItemSelectListener, IBillingService.Listener {
companion object { companion object {
@@ -80,7 +79,7 @@ class VipMainActivity : BaseViewBindingActivity<ActivityVipMainBinding>(),
private val authAdapter = VipAuthAdapter() private val authAdapter = VipAuthAdapter()
private lateinit var rvDelegate: RVDelegate<VipAuthInfo> private lateinit var rvDelegate: RVDelegate<VipAuthInfo>
private val vipViewModel: VipViewModel by viewModels() private val vipViewModel: VipViewModel by viewModels()
private var billingManager: BillingManager? = null private var billingManager: IBillingService? = null
private var googleChargeBean: ChargeBean? = null//google private var googleChargeBean: ChargeBean? = null//google
private var chargeInfo: ChargeBean? = null//official private var chargeInfo: ChargeBean? = null//official
@@ -233,12 +232,15 @@ class VipMainActivity : BaseViewBindingActivity<ActivityVipMainBinding>(),
binding.tvOpenVip.setOnClickListener { binding.tvOpenVip.setOnClickListener {
if (AppMetaDataUtil.getChannelID().equals(Constants.GOOGLE)) { if (AppMetaDataUtil.getChannelID().equals(Constants.GOOGLE)) {
if ((googleChargeBean?.productDetails?.oneTimePurchaseOfferDetails?.priceAmountMicros ?: "0") == "0") { if ((googleChargeBean?.productDetails?.getOneTimePurchaseOfferDetails()
?.getPriceAmountMicros() ?: "0") == "0"
) {
toast(getString(R.string.Recharge_failure)) toast(getString(R.string.Recharge_failure))
return@setOnClickListener return@setOnClickListener
} }
SelectPayTypeDialog.newInstance( SelectPayTypeDialog.newInstance(
googleChargeBean?.productDetails?.oneTimePurchaseOfferDetails?.formattedPrice ?: "0", googleChargeBean?.productDetails?.getOneTimePurchaseOfferDetails()
?.getFormattedPrice() ?: "0",
true, true,
googleChargeBean?.getMoney() ?: 0.0 googleChargeBean?.getMoney() ?: 0.0
) )
@@ -311,7 +313,7 @@ class VipMainActivity : BaseViewBindingActivity<ActivityVipMainBinding>(),
} }
private fun initBilling() { private fun initBilling() {
billingManager = BillingManager(this, this) billingManager = IGoogleService.newBillingService(this,this)
} }
override fun initWhiteTitleBar(title: String?) { override fun initWhiteTitleBar(title: String?) {
@@ -396,31 +398,36 @@ class VipMainActivity : BaseViewBindingActivity<ActivityVipMainBinding>(),
chargeInfo?.let { chargeBean -> chargeInfo?.let { chargeBean ->
val productKeys: MutableList<String> = ArrayList() val productKeys: MutableList<String> = ArrayList()
productKeys.add(chargeBean.getChargeProdId()) productKeys.add(chargeBean.getChargeProdId())
billingManager?.querySkuDetailsAsync(productKeys) { billingResult: BillingResult, productDetails: List<ProductDetails> -> billingManager?.querySkuDetailsAsync(productKeys,
if (billingResult.responseCode != BillingClient.BillingResponseCode.OK) { object : IBillingService.ProductDetailsResponseListener {
Log.w( override fun onProductDetailsResponse(
TAG, billingResult: IBillingResult,
"Unsuccessful query for type: " + BillingClient.SkuType.INAPP productDetails: List<IProductDetails>
+ ". Error code: " + billingResult.responseCode ) {
) if (!billingResult.isResponseOk()) {
} else if (productDetails.isNotEmpty()) { Log.w(
val showChargeList: MutableList<ChargeBean> = ArrayList() TAG,
for (skuDetails in productDetails) { "Unsuccessful query for Error code: " + billingResult.getResponseCode()
if (skuDetails.productId == chargeBean.getChargeProdId()) { )
chargeBean.productDetails = skuDetails } else if (productDetails.isNotEmpty()) {
showChargeList.add(chargeBean) val showChargeList: MutableList<ChargeBean> = ArrayList()
break for (skuDetails in productDetails) {
if (skuDetails.getProductId() == chargeBean.getChargeProdId()) {
chargeBean.productDetails = skuDetails
showChargeList.add(chargeBean)
break
}
}
if (showChargeList.size > 0) {
googleChargeBean = showChargeList[0]
binding.tvOpenVip.text = "${
googleChargeBean?.getMoney()
}${getString(R.string.me_immediately_become_a_Peko_nobleman)}"
}
} }
} }
if (showChargeList.size > 0) {
googleChargeBean = showChargeList[0]
binding.tvOpenVip.text = "${
googleChargeBean?.getMoney()
}${getString(R.string.me_immediately_become_a_Peko_nobleman)}"
}
}
}
})
} }
}, { }, {
it.printStackTrace() it.printStackTrace()
@@ -430,24 +437,26 @@ class VipMainActivity : BaseViewBindingActivity<ActivityVipMainBinding>(),
/*商品更新回调*/ /*商品更新回调*/
@SuppressLint("CheckResult") @SuppressLint("CheckResult")
override fun onPurchasesUpdated(purchases: List<Purchase>) { override fun onPurchasesUpdated(purchases: List<IPurchase>) {
for (purchase in purchases) { for (purchase in purchases) {
if (purchase.purchaseState == Purchase.PurchaseState.PURCHASED && if (purchase.isPurchasedState() &&
purchase.accountIdentifiers != null purchase.getAccountIdentifiers() != null
) { ) {
PayModel.get().verifyOrder( PayModel.get().verifyOrder(
purchase.accountIdentifiers!!.obfuscatedAccountId, purchase.getAccountIdentifiers()!!.getObfuscatedAccountId(),
purchase.products[0], purchase.getProducts().firstOrNull(),
purchase.packageName, purchase.getPackageName(),
purchase.purchaseToken purchase.getPurchaseToken()
) )
.compose(bindToLifecycle()) .compose(bindToLifecycle())
.subscribe( .subscribe(
{ token: String? -> { token: String ->
//L.i("token=" + token); //L.i("token=" + token);
billingManager?.consumeAsync(token) billingManager?.consumeAsync(token)
var skuDetails: ProductDetails? = null var skuDetails: IProductDetails? = null
if (googleChargeBean?.getChargeProdId() == purchase.products[0]) { if (googleChargeBean?.getChargeProdId() == purchase.getProducts()
.firstOrNull()
) {
skuDetails = googleChargeBean?.productDetails skuDetails = googleChargeBean?.productDetails
} }
if (skuDetails != null) { if (skuDetails != null) {
@@ -455,12 +464,19 @@ class VipMainActivity : BaseViewBindingActivity<ActivityVipMainBinding>(),
HashMap() HashMap()
eventValue[AFInAppEventParameterName.CONTENT_TYPE] = "Gold" eventValue[AFInAppEventParameterName.CONTENT_TYPE] = "Gold"
eventValue[AFInAppEventParameterName.QUANTITY] = 1 eventValue[AFInAppEventParameterName.QUANTITY] = 1
eventValue[AFInAppEventParameterName.CONTENT_ID] = purchase.orderId!! eventValue[AFInAppEventParameterName.CONTENT_ID] =
eventValue[AFInAppEventParameterName.REVENUE] = purchase.getOrderId()!!
skuDetails.oneTimePurchaseOfferDetails?.priceAmountMicros!! / 1000000f if (skuDetails.getOneTimePurchaseOfferDetails() != null) {
eventValue["Price"] = skuDetails.oneTimePurchaseOfferDetails?.formattedPrice!! eventValue[AFInAppEventParameterName.REVENUE] =
eventValue[AFInAppEventParameterName.CURRENCY] = skuDetails.getOneTimePurchaseOfferDetails()
skuDetails.oneTimePurchaseOfferDetails?.priceCurrencyCode!! ?.getPriceAmountMicros()!! / 1000000f
eventValue["Price"] =
skuDetails.getOneTimePurchaseOfferDetails()
?.getFormattedPrice()!!
eventValue[AFInAppEventParameterName.CURRENCY] =
skuDetails.getOneTimePurchaseOfferDetails()
?.getPriceCurrencyCode()!!
}
AppsFlyerLib.getInstance().logEvent( AppsFlyerLib.getInstance().logEvent(
applicationContext, applicationContext,
AFInAppEventType.PURCHASE, AFInAppEventType.PURCHASE,
@@ -488,10 +504,10 @@ class VipMainActivity : BaseViewBindingActivity<ActivityVipMainBinding>(),
/*购买商品*/ /*购买商品*/
@SuppressLint("CheckResult") @SuppressLint("CheckResult")
fun buyProduct(productDetails: ProductDetails?) { fun buyProduct(productDetails: IProductDetails?) {
if (productDetails != null) { if (productDetails != null) {
Log.d(TAG, "BuyProduct:" + productDetails.productId) Log.d(TAG, "BuyProduct:" + productDetails.getProductId())
PayModel.get().placeOrder(productDetails.productId) PayModel.get().placeOrder(productDetails.getProductId())
.compose(bindToLifecycle()) .compose(bindToLifecycle())
.subscribe( .subscribe(
{ recordId: PayRecordId -> { recordId: PayRecordId ->
@@ -512,7 +528,7 @@ class VipMainActivity : BaseViewBindingActivity<ActivityVipMainBinding>(),
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
if (billingManager?.isServiceConnected == true) { if (billingManager?.isServiceConnected() == true) {
billingManager?.onQueryPurchases() billingManager?.onQueryPurchases()
} }
} }

View File

@@ -19,6 +19,8 @@ buildscript {
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:7.4.2' classpath 'com.android.tools.build:gradle:7.4.2'
// aRouter
classpath "com.alibaba:arouter-register:1.0.2"
//realm 数据库插件 //realm 数据库插件
classpath "io.realm:realm-gradle-plugin:10.16.1" classpath "io.realm:realm-gradle-plugin:10.16.1"
// android 资源混淆插件 // android 资源混淆插件

View File

@@ -94,10 +94,6 @@ dependencies {
// implementation 'com.google.firebase:firebase-core:19.0.0' // implementation 'com.google.firebase:firebase-core:19.0.0'
// implementation 'com.google.android.gms:play-services-ads-identifier:18.0.1' // implementation 'com.google.android.gms:play-services-ads-identifier:18.0.1'
//googleplay内购
api 'com.google.android.gms:play-services-wallet:19.2.1'
api 'com.android.billingclient:billing:6.0.1'
api 'org.jetbrains.kotlin:kotlin-reflect:1.7.10' api 'org.jetbrains.kotlin:kotlin-reflect:1.7.10'
api project(':nim_uikit') api project(':nim_uikit')
@@ -107,6 +103,8 @@ dependencies {
implementation 'com.liulishuo.okdownload:okhttp:1.0.7' implementation 'com.liulishuo.okdownload:okhttp:1.0.7'
implementation 'com.tencent.liteav:LiteAVSDK_TRTC:11.4.0.13189' implementation 'com.tencent.liteav:LiteAVSDK_TRTC:11.4.0.13189'
api project(':modules:module_base')
} }
repositories { repositories {
mavenCentral() mavenCentral()

View File

@@ -1,8 +1,15 @@
package com.yizhuan.xchat_android_core.auth; package com.yizhuan.xchat_android_core.auth;
import android.app.Activity;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import androidx.annotation.NonNull;
import com.example.module_base.support.google.IGoogleService;
import com.example.module_base.support.login.ILoginService;
import com.example.module_base.support.login.LoginSDKException;
import com.example.module_base.support.login.PlatformInfo;
import com.netease.nim.uikit.api.NimUIKit; import com.netease.nim.uikit.api.NimUIKit;
import com.netease.nim.uikit.common.util.log.LogUtil; import com.netease.nim.uikit.common.util.log.LogUtil;
import com.netease.nim.uikit.common.util.string.StringUtil; import com.netease.nim.uikit.common.util.string.StringUtil;
@@ -134,6 +141,7 @@ public class AuthModel extends BaseModel implements IAuthModel {
private Platform facebook; private Platform facebook;
private Platform line; private Platform line;
private Platform google; private Platform google;
private ILoginService googleLoginService;
/****************************************************** IM *************************************************************/ /****************************************************** IM *************************************************************/
private StatusCode statusCode; private StatusCode statusCode;
@@ -166,6 +174,14 @@ public class AuthModel extends BaseModel implements IAuthModel {
return instance; return instance;
} }
@Override
public ILoginService getGoogleLoginService() {
if (googleLoginService == null) {
googleLoginService = IGoogleService.Companion.newLoginService();
}
return googleLoginService;
}
@Override @Override
public ThirdUserInfo getThirdUserInfo() { public ThirdUserInfo getThirdUserInfo() {
return thirdUserInfo; return thirdUserInfo;
@@ -437,58 +453,40 @@ public class AuthModel extends BaseModel implements IAuthModel {
} }
@Override @Override
public Single<String> googleLogin() { public Single<String> googleLogin(Activity activity) {
return Single.create(new SingleOnSubscribe<Platform>() { return Single.create((SingleOnSubscribe<PlatformInfo>) e -> {
@Override ILoginService loginService = getGoogleLoginService();
public void subscribe(SingleEmitter<Platform> e) throws Exception { if (loginService == null) {
google = ShareSDK.getPlatform(GooglePlus.NAME); e.onError(new Throwable(ResUtil.getString(R.string.bean_response_serviceresult_015)));
//是否安装客户端 return;
if (!DeviceUtils.isAppInstalled(getContext(), PackageNameConstants.GOOGLE_NAME)) { }
e.onError(new Throwable(ResUtil.getString(R.string.xchat_android_core_auth_authmodel_09))); //是否安装客户端
return; if (!DeviceUtils.isAppInstalled(getContext(), PackageNameConstants.GOOGLE_NAME)) {
} e.onError(new Throwable(ResUtil.getString(R.string.xchat_android_core_auth_authmodel_09)));
//判断指定平台是否已经完成授权 return;
if (google.isAuthValid()) { }
google.removeAccount(true); loginService.login(activity, new ILoginService.Listener() {
} @Override
google.setPlatformActionListener(new PlatformActionListener() { public void onSuccess(@NonNull PlatformInfo platformInfo) {
@Override thirdUserInfo = new ThirdUserInfo();
public void onComplete(Platform platform, int i, HashMap<String, Object> hashMap) { thirdUserInfo.setType(ThirdUserInfo.TYPE_GOOGLE);
if (i == Platform.ACTION_USER_INFOR) { thirdUserInfo.setPlatform("Google");
String openid = platform.getDb().getUserId(); thirdUserInfo.setUserName(platformInfo.getName());
String unionid = platform.getDb().get("unionid"); thirdUserInfo.setUserIcon(platformInfo.getAvatar());
Logger.i("openid:" + openid + " unionid:" + unionid + platform.getDb().getUserIcon()); e.onSuccess(platformInfo);
}
thirdUserInfo = new ThirdUserInfo(); @Override
thirdUserInfo.setType(ThirdUserInfo.TYPE_GOOGLE); public void onFailure(@NonNull LoginSDKException exception) {
thirdUserInfo.setPlatform("Google"); exception.printStackTrace();
thirdUserInfo.setUserName(platform.getDb().getUserName()); LogUtils.d("googleLogin" + exception);
thirdUserInfo.setUserGender(platform.getDb().getUserGender()); e.onError(new Throwable(ResUtil.getString(R.string.xchat_android_core_auth_authmodel_010) + exception.getCode()));
thirdUserInfo.setUserIcon(platform.getDb().getUserIcon()); }
e.onSuccess(platform); });
} })
}
@Override
public void onError(Platform platform, int i, Throwable throwable) {
throwable.printStackTrace();
LogUtils.d("googleLogin" + i);
e.onError(new Throwable(ResUtil.getString(R.string.xchat_android_core_auth_authmodel_010) + i));
}
@Override
public void onCancel(Platform platform, int i) {
e.onError(new Throwable(ResUtil.getString(R.string.xchat_android_core_auth_authmodel_011)));
}
});
google.SSOSetting(false);
google.showUser(null);
}
})
.flatMap(platform -> { .flatMap(platform -> {
String openid = platform.getDb().getUserId(); String openid = platform.getId();
String unionid = platform.getDb().getUserId(); String unionid = platform.getId();
String avatar = thirdUserInfo.getUserIcon(); String avatar = thirdUserInfo.getUserIcon();
if (avatar != null && avatar.equals("null")) { if (avatar != null && avatar.equals("null")) {
avatar = null; avatar = null;
@@ -509,6 +507,79 @@ public class AuthModel extends BaseModel implements IAuthModel {
.doOnSuccess(s -> EventBus.getDefault().post(new LoginEvent())); .doOnSuccess(s -> EventBus.getDefault().post(new LoginEvent()));
} }
// @Override
// public Single<String> googleLogin() {
// return Single.create(new SingleOnSubscribe<Platform>() {
// @Override
// public void subscribe(SingleEmitter<Platform> e) throws Exception {
// google = ShareSDK.getPlatform(GooglePlus.NAME);
// //是否安装客户端
// if (!DeviceUtils.isAppInstalled(getContext(), PackageNameConstants.GOOGLE_NAME)) {
// e.onError(new Throwable(ResUtil.getString(R.string.xchat_android_core_auth_authmodel_09)));
// return;
// }
// //判断指定平台是否已经完成授权
// if (google.isAuthValid()) {
// google.removeAccount(true);
// }
// google.setPlatformActionListener(new PlatformActionListener() {
// @Override
// public void onComplete(Platform platform, int i, HashMap<String, Object> hashMap) {
// if (i == Platform.ACTION_USER_INFOR) {
// String openid = platform.getDb().getUserId();
// String unionid = platform.getDb().get("unionid");
// Logger.i("openid:" + openid + " unionid:" + unionid + platform.getDb().getUserIcon());
//
// thirdUserInfo = new ThirdUserInfo();
// thirdUserInfo.setType(ThirdUserInfo.TYPE_GOOGLE);
// thirdUserInfo.setPlatform("Google");
// thirdUserInfo.setUserName(platform.getDb().getUserName());
// thirdUserInfo.setUserGender(platform.getDb().getUserGender());
// thirdUserInfo.setUserIcon(platform.getDb().getUserIcon());
// e.onSuccess(platform);
// }
// }
//
// @Override
// public void onError(Platform platform, int i, Throwable throwable) {
// throwable.printStackTrace();
// LogUtils.d("googleLogin" + i);
// e.onError(new Throwable(ResUtil.getString(R.string.xchat_android_core_auth_authmodel_010) + i));
// }
//
// @Override
// public void onCancel(Platform platform, int i) {
// e.onError(new Throwable(ResUtil.getString(R.string.xchat_android_core_auth_authmodel_011)));
// }
// });
// google.SSOSetting(false);
// google.showUser(null);
//
// }
// })
// .flatMap(platform -> {
// String openid = platform.getDb().getUserId();
// String unionid = platform.getDb().getUserId();
// String avatar = thirdUserInfo.getUserIcon();
// if (avatar != null && avatar.equals("null")) {
// avatar = null;
// }
// thirdUserInfo.setUserIcon(avatar);
// String gender = thirdUserInfo.getUserGender();
// if (gender != null && !gender.trim().isEmpty()) {
// gender = gender.replace("m", "1").replace("f", "2");
// }
// thirdUserInfo.setUserGender(gender);
// EventBus.getDefault().post(new LoginReportEvent(3));
// return thirdLogin(openid, unionid, TYPE_GOOGLE_LOGIN, "", "");
// })
// .flatMap(s -> imLogin(currentAccountInfo))
// .subscribeOn(AndroidSchedulers.mainThread())
// .observeOn(AndroidSchedulers.mainThread())
// .compose(RxHelper.handleException())
// .doOnSuccess(s -> EventBus.getDefault().post(new LoginEvent()));
// }
/** /**
* 第三方信息登录 * 第三方信息登录
* *

View File

@@ -1,5 +1,8 @@
package com.yizhuan.xchat_android_core.auth; package com.yizhuan.xchat_android_core.auth;
import android.app.Activity;
import com.example.module_base.support.login.ILoginService;
import com.yizhuan.xchat_android_core.auth.entity.ThirdUserInfo; import com.yizhuan.xchat_android_core.auth.entity.ThirdUserInfo;
import com.yizhuan.xchat_android_core.base.IModel; import com.yizhuan.xchat_android_core.base.IModel;
@@ -9,6 +12,8 @@ import io.reactivex.Single;
public interface IAuthModel extends IModel { public interface IAuthModel extends IModel {
ILoginService getGoogleLoginService();
ThirdUserInfo getThirdUserInfo(); ThirdUserInfo getThirdUserInfo();
void setThirdUserInfo(ThirdUserInfo thirdUserInfo); void setThirdUserInfo(ThirdUserInfo thirdUserInfo);
@@ -63,7 +68,9 @@ public interface IAuthModel extends IModel {
Single<String> lineLogin(); Single<String> lineLogin();
Single<String> googleLogin(); // Single<String> googleLogin();
Single<String> googleLogin(Activity activity);
/** /**
* 重置用户信息 * 重置用户信息

View File

@@ -15,8 +15,8 @@ import androidx.lifecycle.MutableLiveData;
import com.bumptech.glide.request.FutureTarget; import com.bumptech.glide.request.FutureTarget;
import com.bumptech.glide.request.target.Target; import com.bumptech.glide.request.target.Target;
import com.chuhai.utils.LanguageUtils; import com.example.lib_utils.LanguageUtils;
import com.chuhai.utils.TelephonyUtils; import com.example.lib_utils.TelephonyUtils;
import com.netease.nim.uikit.support.glide.GlideApp; import com.netease.nim.uikit.support.glide.GlideApp;
import com.yizhuan.xchat_android_core.R; import com.yizhuan.xchat_android_core.R;
import com.yizhuan.xchat_android_core.DemoCache; import com.yizhuan.xchat_android_core.DemoCache;

View File

@@ -5,7 +5,7 @@ import android.text.TextUtils;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import com.chuhai.utils.TelephonyUtils; import com.example.lib_utils.TelephonyUtils;
import com.yizhuan.xchat_android_core.auth.AuthModel; import com.yizhuan.xchat_android_core.auth.AuthModel;
import com.yizhuan.xchat_android_core.utils.APIEncryptUtil; import com.yizhuan.xchat_android_core.utils.APIEncryptUtil;
import com.yizhuan.xchat_android_core.utils.OaidUtil; import com.yizhuan.xchat_android_core.utils.OaidUtil;

View File

@@ -1,7 +1,7 @@
package com.yizhuan.xchat_android_core.interceptor package com.yizhuan.xchat_android_core.interceptor
import com.chuhai.utils.AppUtils import com.example.lib_utils.AppUtils
import com.chuhai.utils.ServiceTime import com.example.lib_utils.ServiceTime
import com.yizhuan.xchat_android_core.utils.LogUtils import com.yizhuan.xchat_android_core.utils.LogUtils
import com.yizhuan.xchat_android_library.utils.NetworkUtils import com.yizhuan.xchat_android_library.utils.NetworkUtils
import okhttp3.Headers import okhttp3.Headers

View File

@@ -1,6 +1,6 @@
package com.yizhuan.xchat_android_core.pay.bean; package com.yizhuan.xchat_android_core.pay.bean;
import com.android.billingclient.api.ProductDetails; import com.example.module_base.support.billing.IProductDetails;
import java.io.Serializable; import java.io.Serializable;
@@ -25,7 +25,7 @@ public class ChargeBean implements Serializable{
public int giftGoldNum; public int giftGoldNum;
public int channel; public int channel;
public String prodDesc; public String prodDesc;
private ProductDetails mProductDetails; private IProductDetails mProductDetails;
public boolean isSelected; public boolean isSelected;
@@ -82,11 +82,11 @@ public class ChargeBean implements Serializable{
this.prodDesc = prodDesc; this.prodDesc = prodDesc;
} }
public ProductDetails getProductDetails() { public IProductDetails getProductDetails() {
return mProductDetails; return mProductDetails;
} }
public void setProductDetails(ProductDetails productDetails) { public void setProductDetails(IProductDetails productDetails) {
this.mProductDetails = productDetails; this.mProductDetails = productDetails;
} }

View File

@@ -1,6 +1,7 @@
package com.yizhuan.xchat_android_core.pay.bean; package com.yizhuan.xchat_android_core.pay.bean;
import com.android.billingclient.api.ProductDetails;
import com.example.module_base.support.billing.IProductDetails;
import java.util.ArrayList; import java.util.ArrayList;
@@ -17,5 +18,5 @@ public class FirstChargeGoods {
private ArrayList<FirstChargeReward> firstChargeRewardList; private ArrayList<FirstChargeReward> firstChargeRewardList;
private String giveMoney; private String giveMoney;
private boolean finishCharge; private boolean finishCharge;
private ProductDetails productDetails; private IProductDetails productDetails;
} }

View File

@@ -4,7 +4,7 @@ import androidx.annotation.CallSuper
import androidx.lifecycle.Lifecycle import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver import androidx.lifecycle.LifecycleEventObserver
import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.LifecycleOwner
import com.chuhai.utils.log.ILog import com.example.lib_utils.log.ILog
import com.trello.rxlifecycle3.LifecycleProvider import com.trello.rxlifecycle3.LifecycleProvider
import com.trello.rxlifecycle3.LifecycleTransformer import com.trello.rxlifecycle3.LifecycleTransformer
import com.trello.rxlifecycle3.OutsideLifecycleException import com.trello.rxlifecycle3.OutsideLifecycleException

View File

@@ -2,7 +2,7 @@ package com.yizhuan.xchat_android_core.support.room
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import com.chuhai.utils.log.ILog import com.example.lib_utils.log.ILog
import com.yizhuan.xchat_android_core.support.room.lifecycle.RoomLifecycle import com.yizhuan.xchat_android_core.support.room.lifecycle.RoomLifecycle
import com.yizhuan.xchat_android_core.support.room.lifecycle.RoomLifecycleRegistry import com.yizhuan.xchat_android_core.support.room.lifecycle.RoomLifecycleRegistry

View File

@@ -1,6 +1,6 @@
package com.yizhuan.xchat_android_core.support.room package com.yizhuan.xchat_android_core.support.room
import com.chuhai.utils.log.ILog import com.example.lib_utils.log.ILog
/** /**
* Created by Max on 2023/10/26 17:12 * Created by Max on 2023/10/26 17:12

View File

@@ -1,6 +1,6 @@
package com.yizhuan.xchat_android_core.support.room.lifecycle package com.yizhuan.xchat_android_core.support.room.lifecycle
import com.chuhai.utils.ICleared import com.example.lib_utils.ICleared
/** /**
* Created by Max on 2023/10/26 11:50 * Created by Max on 2023/10/26 11:50

View File

@@ -1,6 +1,6 @@
package com.yizhuan.xchat_android_core.support.room.lifecycle package com.yizhuan.xchat_android_core.support.room.lifecycle
import com.chuhai.utils.log.ILog import com.example.lib_utils.log.ILog
import com.yizhuan.xchat_android_core.support.room.RoomContext import com.yizhuan.xchat_android_core.support.room.RoomContext
import java.util.concurrent.CopyOnWriteArrayList import java.util.concurrent.CopyOnWriteArrayList

View File

@@ -35,8 +35,6 @@ android {
'src/module_luban/java', 'src/module_luban/java',
'src/module_easyphoto/java', 'src/module_easyphoto/java',
'src/module_common/java', 'src/module_common/java',
'src/module_utils/java',
'src/module_core/java',
] ]
@@ -45,8 +43,6 @@ android {
'src/module_easypermission/res', 'src/module_easypermission/res',
'src/module_easyphoto/res', 'src/module_easyphoto/res',
'src/module_common/res', 'src/module_common/res',
'src/module_utils/res',
'src/module_core/res',
] ]
@@ -88,18 +84,10 @@ dependencies {
androidTestImplementation 'androidx.test.ext:junit:1.1.3' androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
api 'androidx.constraintlayout:constraintlayout:2.1.4'
api 'androidx.appcompat:appcompat:1.4.2'
api 'androidx.recyclerview:recyclerview:1.2.1'
api 'androidx.cardview:cardview:1.0.0' api 'androidx.cardview:cardview:1.0.0'
api 'androidx.gridlayout:gridlayout:1.0.0' api 'androidx.gridlayout:gridlayout:1.0.0'
api "androidx.core:core-ktx:1.7.0"
api "androidx.fragment:fragment:$fragment_version" api "androidx.fragment:fragment:$fragment_version"
api "androidx.fragment:fragment-ktx:$fragment_version" api "androidx.fragment:fragment-ktx:$fragment_version"
api 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.1'
api 'androidx.lifecycle:lifecycle-extensions:2.2.0'
api 'com.google.android.material:material:1.6.1'
api "com.squareup.retrofit2:retrofit:${retrofitVersion}" api "com.squareup.retrofit2:retrofit:${retrofitVersion}"
api "com.squareup.okhttp3:okhttp:${okhttp3}" api "com.squareup.okhttp3:okhttp:${okhttp3}"
@@ -151,6 +139,9 @@ dependencies {
// 网络请求chrome数据调试 // 网络请求chrome数据调试
api 'com.facebook.stetho:stetho:1.5.1' api 'com.facebook.stetho:stetho:1.5.1'
api 'com.facebook.stetho:stetho-okhttp3:1.5.1' api 'com.facebook.stetho:stetho-okhttp3:1.5.1'
api project(':libs:lib_utils')
api project(':libs:lib_core')
} }
repositories { repositories {
mavenCentral() mavenCentral()

View File

@@ -3,6 +3,8 @@ package com.yizhuan.xchat_android_library.common.application;
import android.app.Application; import android.app.Application;
import android.content.Context; import android.content.Context;
import com.example.lib_utils.AppUtils;
/** /**
* Application的代理类 * Application的代理类
*/ */
@@ -26,7 +28,7 @@ public abstract class BaseApp extends Application{
public static void init(Application application) { public static void init(Application application) {
gContext = application; gContext = application;
com.chuhai.utils.AppUtils.init(application); AppUtils.init(application);
} }
/** /**

View File

@@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
</resources>

View File

@@ -1,3 +0,0 @@
<resources>
</resources>

1
libs/lib_core/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
/build

View File

@@ -0,0 +1,19 @@
apply from : "../lib_standard.gradle"
android {
namespace 'com.example.lib_core'
}
dependencies {
// 工具集
api project(path: ":libs:lib_utils")
api 'androidx.constraintlayout:constraintlayout:2.1.4'
api 'androidx.recyclerview:recyclerview:1.2.1'
api 'com.google.android.material:material:1.6.1'
api 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.1'
api 'androidx.lifecycle:lifecycle-extensions:2.2.0'
api "com.alibaba:fastjson:1.2.41"
}

View File

21
libs/lib_core/proguard-rules.pro vendored Normal file
View File

@@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

View File

@@ -0,0 +1,24 @@
package com.example.lib_core
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.Assert.*
/**
* Instrumented test, which will execute on an Android device.
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest {
@Test
fun useAppContext() {
// Context of the app under test.
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
assertEquals("com.example.lib_core.test", appContext.packageName)
}
}

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
</manifest>

View File

@@ -1,10 +1,10 @@
package com.chuhai.core.component package com.example.lib_core.component
import LifecycleCleared import LifecycleCleared
import android.content.Context import android.content.Context
import android.content.DialogInterface import android.content.DialogInterface
import androidx.lifecycle.Lifecycle import androidx.lifecycle.Lifecycle
import com.chuhai.utils.ktx.asLifecycle import com.example.lib_utils.ktx.asLifecycle
import com.google.android.material.bottomsheet.BottomSheetDialog import com.google.android.material.bottomsheet.BottomSheetDialog

View File

@@ -0,0 +1,17 @@
package com.example.lib_core
import org.junit.Test
import org.junit.Assert.*
/**
* Example local unit test, which will execute on the development machine (host).
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
class ExampleUnitTest {
@Test
fun addition_isCorrect() {
assertEquals(4, 2 + 2)
}
}

41
libs/lib_standard.gradle Normal file
View File

@@ -0,0 +1,41 @@
apply plugin: "com.android.library"
apply plugin: "org.jetbrains.kotlin.android"
apply plugin: "kotlin-android"
apply plugin: "kotlin-kapt"
android {
compileSdkVersion COMPILE_SDK_VERSION.toInteger()
defaultConfig {
minSdkVersion MIN_SDK_VERSION.toInteger()
targetSdkVersion TARGET_SDK_VERSION.toInteger()
versionCode 1
versionName "1.0.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles 'proguard-rules.pro'
}
buildTypes {
release {
minifyEnabled true
zipAlignEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
debug {
debuggable true
minifyEnabled false
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_11
targetCompatibility JavaVersion.VERSION_11
}
kotlinOptions {
jvmTarget = '11'
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
}

1
libs/lib_utils/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
/build

View File

@@ -0,0 +1,10 @@
apply from : "../lib_standard.gradle"
android {
namespace 'com.example.lib_utils'
}
dependencies {
api "androidx.core:core-ktx:1.7.0"
api 'androidx.appcompat:appcompat:1.4.2'
}

View File

21
libs/lib_utils/proguard-rules.pro vendored Normal file
View File

@@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

View File

@@ -0,0 +1,24 @@
package com.example.lib_utils
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.Assert.*
/**
* Instrumented test, which will execute on an Android device.
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest {
@Test
fun useAppContext() {
// Context of the app under test.
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
assertEquals("com.example.lib_utils.test", appContext.packageName)
}
}

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
</manifest>

View File

@@ -1,4 +1,4 @@
package com.chuhai.utils; package com.example.lib_utils;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.app.ActivityManager; import android.app.ActivityManager;

View File

@@ -1,4 +1,4 @@
package com.chuhai.utils package com.example.lib_utils
/** /**

View File

@@ -1,4 +1,4 @@
package com.chuhai.utils package com.example.lib_utils
import android.os.Build import android.os.Build
import android.os.LocaleList import android.os.LocaleList

View File

@@ -1,4 +1,4 @@
package com.chuhai.utils package com.example.lib_utils
import android.os.SystemClock import android.os.SystemClock

View File

@@ -1,4 +1,4 @@
package com.chuhai.utils package com.example.lib_utils
import android.graphics.Outline import android.graphics.Outline
import android.view.View import android.view.View

View File

@@ -1,8 +1,8 @@
package com.chuhai.utils package com.example.lib_utils
import android.content.Context import android.content.Context
import android.telephony.TelephonyManager import android.telephony.TelephonyManager
import com.chuhai.utils.log.ILog import com.example.lib_utils.log.ILog
/** /**
* Created by Max on 2023/11/14 10:17 * Created by Max on 2023/11/14 10:17

View File

@@ -1,4 +1,4 @@
package com.chuhai.utils package com.example.lib_utils
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.content.Context import android.content.Context

View File

@@ -1,4 +1,4 @@
package com.chuhai.utils.ktx package com.example.lib_utils.ktx
import android.app.Activity import android.app.Activity
import android.content.Context import android.content.Context

View File

@@ -1,9 +1,8 @@
package com.chuhai.utils.ktx package com.example.lib_utils.ktx
import android.text.Editable import android.text.Editable
import android.text.InputFilter import android.text.InputFilter
import android.text.InputFilter.LengthFilter import android.text.InputFilter.LengthFilter
import android.text.Spanned
import android.text.TextWatcher import android.text.TextWatcher
import android.text.method.HideReturnsTransformationMethod import android.text.method.HideReturnsTransformationMethod
import android.text.method.PasswordTransformationMethod import android.text.method.PasswordTransformationMethod

View File

@@ -1,4 +1,4 @@
package com.chuhai.utils.ktx package com.example.lib_utils.ktx
import android.app.Activity import android.app.Activity
import android.content.Context import android.content.Context
@@ -9,7 +9,7 @@ import androidx.annotation.*
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.content.res.ResourcesCompat import androidx.core.content.res.ResourcesCompat
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import com.chuhai.utils.AppUtils import com.example.lib_utils.AppUtils
/** /**
* Created by Max on 2023/10/24 15:11 * Created by Max on 2023/10/24 15:11

View File

@@ -1,6 +1,6 @@
package com.chuhai.utils.ktx package com.example.lib_utils.ktx
import com.chuhai.utils.UiUtils import com.example.lib_utils.UiUtils
import kotlin.math.roundToInt import kotlin.math.roundToInt
/** /**

View File

@@ -1,4 +1,4 @@
package com.chuhai.utils.ktx package com.example.lib_utils.ktx
import android.graphics.* import android.graphics.*
import android.os.Build import android.os.Build
@@ -9,8 +9,8 @@ import android.view.ViewGroup
import android.widget.Checkable import android.widget.Checkable
import android.widget.TextView import android.widget.TextView
import androidx.core.view.ScrollingView import androidx.core.view.ScrollingView
import com.chuhai.utils.ShapeViewOutlineProvider import com.example.lib_utils.ShapeViewOutlineProvider
import com.chuhai.utils.UiUtils import com.example.lib_utils.UiUtils
/** /**

View File

@@ -1,4 +1,4 @@
package com.chuhai.utils.log package com.example.lib_utils.log
import android.util.Log import android.util.Log

View File

@@ -1,4 +1,4 @@
package com.chuhai.utils.log package com.example.lib_utils.log
/** /**
* Created by Max on 2023/10/26 10:29 * Created by Max on 2023/10/26 10:29

View File

@@ -1,4 +1,4 @@
package com.chuhai.utils.log package com.example.lib_utils.log
/** /**

View File

@@ -1,4 +1,4 @@
package com.chuhai.utils.log package com.example.lib_utils.log
import android.util.Log import android.util.Log
@@ -22,7 +22,7 @@ object LogUtil {
* 设置文件打印 * 设置文件打印
*/ */
fun setFilePrinter(filePrinter: LogPrinter) { fun setFilePrinter(filePrinter: LogPrinter) {
this.filePrinter = filePrinter LogUtil.filePrinter = filePrinter
} }
fun e(tag: String, message: String, filePrinter: Boolean = false) { fun e(tag: String, message: String, filePrinter: Boolean = false) {

View File

@@ -1,4 +1,4 @@
package com.chuhai.utils.spannable; package com.example.lib_utils.spannable;
import android.content.Context; import android.content.Context;
import android.graphics.Canvas; import android.graphics.Canvas;

View File

@@ -1,4 +1,4 @@
package com.chuhai.utils.spannable package com.example.lib_utils.spannable
import android.graphics.Canvas import android.graphics.Canvas
import android.graphics.Paint import android.graphics.Paint

View File

@@ -1,4 +1,4 @@
package com.chuhai.utils.spannable package com.example.lib_utils.spannable
import android.text.Spannable import android.text.Spannable
import android.text.SpannableStringBuilder import android.text.SpannableStringBuilder
@@ -10,7 +10,7 @@ import android.view.View
import android.widget.TextView import android.widget.TextView
import androidx.annotation.ColorInt import androidx.annotation.ColorInt
import androidx.annotation.DrawableRes import androidx.annotation.DrawableRes
import com.chuhai.utils.ktx.dp import com.example.lib_utils.ktx.dp
/** /**
* Created by Max on 2023/10/26 20:14 * Created by Max on 2023/10/26 20:14
@@ -209,7 +209,7 @@ class SpannableTextBuilder(private val textView: TextView) {
spannableBuilder.append(text) spannableBuilder.append(text)
val end = spannableBuilder.length val end = spannableBuilder.length
spannableBuilder.setSpan( spannableBuilder.setSpan(
IconTextSpan( com.example.lib_utils.spannable.IconTextSpan(
textView.context, textView.context,
backgroundColor, backgroundColor,
text, text,

View File

@@ -1,4 +1,4 @@
package com.chuhai.utils.spannable package com.example.lib_utils.spannable
import android.content.Context import android.content.Context
import android.graphics.Canvas import android.graphics.Canvas

View File

@@ -0,0 +1,17 @@
package com.example.lib_utils
import org.junit.Test
import org.junit.Assert.*
/**
* Example local unit test, which will execute on the development machine (host).
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
class ExampleUnitTest {
@Test
fun addition_isCorrect() {
assertEquals(4, 2 + 2)
}
}

View File

@@ -0,0 +1,54 @@
/*
* 文件说明module的基础配置
*/
apply plugin: "com.android.library"
apply plugin: "org.jetbrains.kotlin.android"
apply plugin: "kotlin-android"
apply plugin: "kotlin-kapt"
apply plugin: "com.alibaba.arouter"
android {
compileSdkVersion COMPILE_SDK_VERSION.toInteger()
defaultConfig {
minSdkVersion MIN_SDK_VERSION.toInteger()
targetSdkVersion TARGET_SDK_VERSION.toInteger()
versionCode 1
versionName "1.0.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles 'proguard-rules.pro'
}
buildTypes {
release {
minifyEnabled true
zipAlignEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
debug {
debuggable true
minifyEnabled false
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_11
targetCompatibility JavaVersion.VERSION_11
}
kotlinOptions {
jvmTarget = '11'
}
}
dependencies {
implementation 'androidx.core:core-ktx:1.7.0'
implementation 'androidx.appcompat:appcompat:1.4.2'
implementation 'com.google.android.material:material:1.6.1'
// aRouter
api 'com.alibaba:arouter-api:1.4.0'
api 'com.alibaba:arouter-annotation:1.0.6'
kapt 'com.alibaba:arouter-compiler:1.5.2'
}

1
modules/module_base/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
/build

View File

@@ -0,0 +1,17 @@
apply from: "../module_base.gradle"
android {
namespace 'com.example.module_base'
}
kapt {
arguments {
arg("AROUTER_MODULE_NAME", project.getName())
}
}
dependencies {
// 内部组件库
api project(path: ":libs:lib_core")
api project(path: ":libs:lib_utils")
}

View File

21
modules/module_base/proguard-rules.pro vendored Normal file
View File

@@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

View File

@@ -0,0 +1,24 @@
package com.example.module_base
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.Assert.*
/**
* Instrumented test, which will execute on an Android device.
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest {
@Test
fun useAppContext() {
// Context of the app under test.
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
assertEquals("com.example.module_base.test", appContext.packageName)
}
}

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
</manifest>

View File

@@ -0,0 +1,9 @@
package com.example.module_base.config
/**
* Created by Max on 2023/11/22 16:01
* Desc:
**/
object RouterPath {
const val GOOGLE_SERVICE = "/google/service"
}

View File

@@ -0,0 +1,12 @@
package com.example.module_base.support.billing
/**
* Created by Max on 2023/11/22 20:55
* Desc:
**/
interface IAccountIdentifiers {
fun getObfuscatedAccountId(): String?
fun getObfuscatedProfileId(): String?
}

View File

@@ -0,0 +1,12 @@
package com.example.module_base.support.billing
/**
* Created by Max on 2023/11/22 20:20
* Desc:
**/
interface IBillingResult {
fun getResponseCode(): Int
fun isResponseOk(): Boolean
}

View File

@@ -0,0 +1,34 @@
package com.example.module_base.support.billing
/**
* Created by Max on 2023/11/22 17:44
* Desc:支付
**/
interface IBillingService {
fun isServiceConnected(): Boolean
fun onQueryPurchases()
fun querySkuDetailsAsync(
productIdList: List<String>,
listener: IBillingService.ProductDetailsResponseListener
)
fun consumeAsync(purchaseToken: String)
fun initiatePurchaseFlow(productDetails: IProductDetails, recordId: String)
fun destroy()
interface Listener {
fun onBillingClientSetupFinished()
fun onPurchasesUpdated(purchases: List<IPurchase>)
fun onConsumeFinished(token: String?, result: Int)
fun onFailedHandle(result: Int)
}
interface ProductDetailsResponseListener {
fun onProductDetailsResponse(billingResult: IBillingResult, productDetails: List<IProductDetails>)
}
}

View File

@@ -0,0 +1,13 @@
package com.example.module_base.support.billing
/**
* Created by Max on 2023/11/22 21:06
* Desc:
**/
interface IOneTimePurchaseOfferDetails {
fun getPriceAmountMicros(): Long
fun getFormattedPrice(): String
fun getPriceCurrencyCode(): String
}

View File

@@ -0,0 +1,14 @@
package com.example.module_base.support.billing
/**
* Created by Max on 2023/11/22 20:17
* Desc:
**/
interface IProductDetails {
fun getData(): Any
fun getProductId(): String
fun getOneTimePurchaseOfferDetails(): IOneTimePurchaseOfferDetails?
}

View File

@@ -0,0 +1,23 @@
package com.example.module_base.support.billing
/**
* Created by Max on 2023/11/22 19:22
* Desc:
**/
interface IPurchase {
fun getData(): Any
fun getPurchaseState(): Int
fun isPurchasedState(): Boolean
fun getAccountIdentifiers(): IAccountIdentifiers?
fun getProducts(): List<String>
fun getPackageName(): String
fun getPurchaseToken(): String
fun getOrderId(): String?
}

View File

@@ -0,0 +1,37 @@
package com.example.module_base.support.google
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.login.ILoginService
/**
* Created by Max on 2023/11/22 15:30
* Desc:google服务
**/
interface IGoogleService : IProvider {
companion object {
val instance: IGoogleService? by lazy {
ARouter.getInstance().navigation(IGoogleService::class.java)
}
fun newLoginService(): ILoginService? {
return instance?.newLoginService()
}
fun newBillingService(
activity: Activity,
listener: IBillingService.Listener
): IBillingService? {
return instance?.newBillingService(activity, listener)
}
}
fun newLoginService(): ILoginService
fun newBillingService(
activity: Activity,
listener: IBillingService.Listener
): IBillingService
}

View File

@@ -0,0 +1,22 @@
package com.example.module_base.support.login
import android.app.Activity
import android.content.Intent
/**
* Created by Max on 2023/11/22 15:52
* Desc:登录服务
**/
interface ILoginService {
fun login(activity: Activity, listener: Listener)
fun logout()
fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?)
interface Listener {
fun onSuccess(platformInfo: PlatformInfo)
fun onFailure(exception: LoginSDKException)
}
}

View File

@@ -0,0 +1,21 @@
package com.example.module_base.support.login
/**
* Created by Max on 2023/11/22 17:06
* Desc:登录SDK-异常
**/
class LoginSDKException : Exception {
private var code: Int = -1
fun getCode(): Int {
return code
}
constructor(code: Int) : super() {
this.code = code
}
constructor(code: Int, cause: Throwable?) : super(cause) {
this.code = code
}
}

View File

@@ -0,0 +1,8 @@
package com.example.module_base.support.login
/**
* Created by Max on 2023/11/22 15:45
* Desc:第三方平台信息
**/
data class PlatformInfo(val id: String, var name: String?, var gender: Int?, var avatar: String?) {
}

View File

@@ -0,0 +1,17 @@
package com.example.module_base
import org.junit.Test
import org.junit.Assert.*
/**
* Example local unit test, which will execute on the development machine (host).
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
class ExampleUnitTest {
@Test
fun addition_isCorrect() {
assertEquals(4, 2 + 2)
}
}

1
modules/module_google/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
/build

View File

@@ -0,0 +1,24 @@
apply from: "../module_standard.gradle"
android {
namespace 'com.example.module_google'
defaultConfig {
buildConfigField "String", "GOOGLE_APP_KEY", "\"xxx\""
buildConfigField "String", "GOOGLE_SERVER_CLIENT_ID", "\"..com\""
}
}
kapt {
arguments {
arg("AROUTER_MODULE_NAME", project.getName())
}
}
dependencies {
// google登录
implementation 'com.google.android.gms:play-services-auth:20.7.0'
// googleplay内购
implementation 'com.google.android.gms:play-services-wallet:19.2.1'
implementation 'com.android.billingclient:billing:6.0.1'
}

View File

View File

@@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

View File

@@ -0,0 +1,24 @@
package com.example.module_google
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.Assert.*
/**
* Instrumented test, which will execute on an Android device.
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest {
@Test
fun useAppContext() {
// Context of the app under test.
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
assertEquals("com.example.module_google.test", appContext.packageName)
}
}

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
</manifest>

Some files were not shown because too many files have changed in this diff Show More