diff --git a/app/build.gradle.kts b/app/build.gradle.kts index c89b1b2..555a0ce 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -46,7 +46,7 @@ android { "GT_INSTALL_CHANNEL" to (project.findProperty("GT_INSTALL_CHANNEL") as? String ?: "GT_INSTALL_CHANNEL") )) ndk { - abiFilters.addAll(listOf("arm64-v8a", "x86_64")) + abiFilters.addAll(listOf("arm64-v8a", "x86_64", "x86", "armeabi-v7a")) } testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" @@ -74,7 +74,7 @@ android { manifestPlaceholders.putAll(mapOf( "GETUI_APPID" to (project.findProperty("GETUI_APPID") as? String ?: ""), "GT_INSTALL_CHANNEL" to "general", - "apk.applicationId" to "com.img.rabbit" + "apk.applicationId" to "com.img.rabbit", )) } @@ -178,6 +178,7 @@ dependencies { //noinspection GradleDynamicVersion api("com.alipay.sdk:alipaysdk-android:+@aar") implementation(libs.wechat.sdk) //微信 +// implementation("com.tencent.mm.opensdk:wechat-sdk-android-without-mta:6.7.9") //Retrofit 依赖 implementation(libs.retrofit) implementation(libs.retrofit.kotlin.serialization) @@ -211,6 +212,6 @@ dependencies { implementation(libs.facebook.animated.gif) //必须集成,图片加载需要 implementation(libs.bumptech.glide) //必须集成,图片加载需要 implementation(libs.androidx.webkit) //4.45版本之后 必须集成,用来支持暗黑模式 - implementation("androidx.legacy:legacy-support-v4:1.0.0") + implementation(libs.androidx.legacy.support.v4) } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index a39ba01..81e45c1 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -26,6 +26,10 @@ + + + + + android:launchMode="singleTop" + android:theme="@android:style/Theme.Translucent.NoTitleBar"/> @@ -146,6 +149,15 @@ android:resource="@xml/dcloud_file_provider" /> + + + \ No newline at end of file diff --git a/app/src/main/java/com/img/rabbit/BaseApplication.kt b/app/src/main/java/com/img/rabbit/BaseApplication.kt index 17a3cac..c861c44 100644 --- a/app/src/main/java/com/img/rabbit/BaseApplication.kt +++ b/app/src/main/java/com/img/rabbit/BaseApplication.kt @@ -72,7 +72,7 @@ class BaseApplication : Application() { UMConfigure.setLogEnabled(true) PlatformConfig.setFileProvider("${BuildConfig.APPLICATION_ID}.fileprovider") - PlatformConfig.setWeixin(Constants.WechatAppId, Constants.WechatAppSecret) + PlatformConfig.setWeixin(Constants.WxAppId, Constants.WxSecret) MobclickAgent.setPageCollectionMode(MobclickAgent.PageMode.AUTO) UMConfigure.setProcessEvent(true) diff --git a/app/src/main/java/com/img/rabbit/MainActivity.kt b/app/src/main/java/com/img/rabbit/MainActivity.kt index 7d4881c..31441cf 100644 --- a/app/src/main/java/com/img/rabbit/MainActivity.kt +++ b/app/src/main/java/com/img/rabbit/MainActivity.kt @@ -52,6 +52,7 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen +import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.lifecycleScope import androidx.lifecycle.viewmodel.compose.viewModel import com.google.accompanist.permissions.ExperimentalPermissionsApi @@ -68,9 +69,11 @@ import com.img.rabbit.pages.dialog.UpdateDialog import com.img.rabbit.provider.storage.GlobalStateManager import com.img.rabbit.provider.storage.PreferenceUtil import com.img.rabbit.provider.storage.PreferenceUtil.saveBDVID +import com.img.rabbit.utils.AppEventBus import com.img.rabbit.utils.AppUpdate import com.img.rabbit.utils.ChannelUtils import com.img.rabbit.utils.FileUtils +import com.img.rabbit.utils.LoginBindEvent import com.img.rabbit.utils.UniAppUtils import com.img.rabbit.utils.UniMpUpdate import com.img.rabbit.utils.UpdateUtils @@ -87,6 +90,7 @@ import kotlinx.coroutines.launch import kotlin.system.exitProcess class MainActivity : ComponentActivity(), LoadingCallback { + private lateinit var generalViewModel: GeneralViewModel @OptIn(DelicateCoroutinesApi::class, ExperimentalPermissionsApi::class) @SuppressLint("UnrememberedMutableState", "CoroutineCreationDuringComposition") override fun onCreate(savedInstanceState: Bundle?) { @@ -101,13 +105,11 @@ class MainActivity : ComponentActivity(), LoadingCallback { val coroutineScope = rememberCoroutineScope() val splashViewModel: SplashViewModel = viewModel() - val generalViewModel: GeneralViewModel = viewModel() + generalViewModel = ViewModelProvider(this, ViewModelProvider.AndroidViewModelFactory.getInstance(application))[GeneralViewModel::class.java] var loginViewModel: LoginViewModel = viewModel() val context = LocalContext.current var showSplash by remember { mutableStateOf(false) } - var globalLogin by mutableStateOf(GlobalStateManager(context).globalLoginNotifyFlow().collectAsState(initial = false)) - var globalLogout by mutableStateOf(GlobalStateManager(context).globalLogoutNotifyFlow().collectAsState(initial = false)) var globalBind by mutableStateOf(GlobalStateManager(context).globalBindNotifyFlow().collectAsState(initial = false)) var globalUnBind by mutableStateOf(GlobalStateManager(context).globalUnBindNotifyFlow().collectAsState(initial = false)) var globalUpdate by mutableStateOf(GlobalStateManager(context).globalUpdateNotifyFlow().collectAsState(initial = false)) @@ -131,34 +133,19 @@ class MainActivity : ComponentActivity(), LoadingCallback { } } + LaunchedEffect(loginViewModel.userConfigResult.value) { + if (loginViewModel.userConfigResult.value != null){ + // 用户配置信息获取成功 + loginViewModel.requestUserInfo() + loginViewModel.userConfigResult.value = null + } + } + // 设置启动页显示条件 splashScreen.setKeepOnScreenCondition { splashViewModel.isLoading.value // 当为 true 时,启动页不消失 } - //更新用户配置与用户信息 - if(globalLogin.value == true || globalBind.value == true || globalUnBind.value == true || globalLogout.value == true){ - loginViewModel.requestUserConfig() - loginViewModel.requestUserInfo() - } - - // 登录成功后,2秒后自动更新状态 - if(globalLogin.value == true){ - GlobalScope.launch { - //延迟2秒,方便处理多有事件都收到通知 - delay(2*1000) - GlobalStateManager(context).storeGlobalLoginNotify(false) - } - } - - // 退出成功后,2秒后自动更新状态 - if(globalLogout.value == true){ - GlobalScope.launch { - //延迟2秒,方便处理多有事件都收到通知 - delay(2*1000) - GlobalStateManager(context).storeGlobalLogoutNotify(false) - } - } // 绑定成功后,2秒后自动更新状态 if(globalBind.value == true){ @@ -178,6 +165,24 @@ class MainActivity : ComponentActivity(), LoadingCallback { } } + // 处理全局事件,类似与EventBus订阅 + LaunchedEffect(Unit) { + AppEventBus.events.collect { event -> + when (event) { + is LoginBindEvent.Login -> { + Log.i("AppEventBus","--------------登录成功,开始获取配置和个人数据") + if(!event.isLogin){ + loginViewModel.reset() + } + loginViewModel.requestUserConfig() + } + is LoginBindEvent.Bind -> { + loginViewModel.requestUserConfig() + } + } + } + } + AppTheme { SplashScreenContent{ //未同意提示政策弹窗 @@ -201,17 +206,16 @@ class MainActivity : ComponentActivity(), LoadingCallback { showSplash = true } - if(showSplash || globalLogout.value == true){ + if(showSplash){ //|| globalLogout.value == true){ // 全局注销,重新登录 - if(globalLogout.value == true){ - loginViewModel = viewModel() - loginViewModel.requestUserConfig() - //loginViewModel.initWXApi(this) - } +// if(globalLogout.value == true){ +// loginViewModel = viewModel() +// loginViewModel.requestUserConfig() +// } val token = PreferenceUtil.getAccessToken() // 未登录,显示登录页 - if (token.isNullOrEmpty() && !loginViewModel.isLogin.value) { + if (token.isNullOrEmpty() && loginViewModel.userConfigResult.value == null) { // 同意隐私协议政策,检验是否有一键登录权限 loginViewModel.oneKeyLoginForGeTuiSdk(context as Activity) { isAllowShowOneKeyScreen -> if (isAllowShowOneKeyScreen) { diff --git a/app/src/main/java/com/img/rabbit/config/Constants.kt b/app/src/main/java/com/img/rabbit/config/Constants.kt index 241d906..089ba1d 100644 --- a/app/src/main/java/com/img/rabbit/config/Constants.kt +++ b/app/src/main/java/com/img/rabbit/config/Constants.kt @@ -8,8 +8,8 @@ object Constants { const val privacyUrl = "https://jitutu.batiao8.com/static/policy-jietutu/privacy-ios.html"//隐私政策 //const val getuiAppId = "40qbPjPkYs7TnVAYCX0Ig6"//个推appid (gradle.properties) - const val WechatAppId = "wx7d1a7d1507482cef"// 微信APPID - const val WechatAppSecret = ""//微信secret + const val WxAppId = "wx7d1a7d1507482cef"// 微信APPID + const val WxSecret = "5264c353296db25405fc29e43c40d3a5"//微信secret const val UmengAppkey = "69a641119a7f3764887cd287"// 友盟appKey const val AppId = ""//appid diff --git a/app/src/main/java/com/img/rabbit/pages/LoginPage.kt b/app/src/main/java/com/img/rabbit/pages/LoginPage.kt index 25ff14c..d26cf18 100644 --- a/app/src/main/java/com/img/rabbit/pages/LoginPage.kt +++ b/app/src/main/java/com/img/rabbit/pages/LoginPage.kt @@ -72,14 +72,14 @@ import com.g.gysdk.EloginActivityParam import com.g.gysdk.GYManager import com.g.gysdk.GYResponse import com.g.gysdk.GyCallBack -import com.img.rabbit.bean.local.toAlipayResult import com.img.rabbit.config.Constants.agreementUrl import com.img.rabbit.config.Constants.privacyUrl import com.img.rabbit.pages.toolbar.TitleBar -import com.img.rabbit.provider.storage.GlobalStateManager import com.img.rabbit.provider.storage.PreferenceUtil -import com.img.rabbit.utils.StringUtils +import com.img.rabbit.utils.AppEventBus +import com.img.rabbit.utils.LoginBindEvent import com.img.rabbit.utils.UrlLinkUtils.openAgreement +import com.img.rabbit.utils.WXAuthEvent import kotlinx.coroutines.delay import org.json.JSONObject @@ -101,63 +101,35 @@ fun LoginScreen(navController: NavHostController? = null, generalViewModel: Gene } } + //关于登录的事件监听 + LaunchedEffect(Unit) { + AppEventBus.events.collect { event -> + when (event) { + //微信授权结果(authType=0 ---->拿着Code登录) + is WXAuthEvent.AuthResult -> { + if(loginViewModel.isLoginWxAuthor){ + loginViewModel.requestWxLogin(event.code) + loginViewModel.isLoginWxAuthor = false + } + } + } + } + } + // 登录成功后,保存 token - LaunchedEffect(loginViewModel.loginState.value) { - if (loginViewModel.loginState.value !=null && loginViewModel.loginState.value?.data?.token != null) { - //登录成功 - PreferenceUtil.saveAccessToken(loginViewModel.loginState.value?.data?.token) - - loginViewModel.setLogin(true) - //更新登录状态 - GlobalStateManager(context).storeGlobalLoginNotify(true) - //清理loginState - loginViewModel.loginState.value = null - //提示登录成功 - Toast.makeText(context, "登录成功", Toast.LENGTH_SHORT).show() - // 当允许返回上一页时,登录成功后,返回上一页 + LaunchedEffect(loginViewModel.loginResult.value) { + if (loginViewModel.loginResult.value?.data?.token?.isNotEmpty() == true) { + val loginInfo = loginViewModel.loginResult.value?.data + AppEventBus.post( LoginBindEvent.Login(userId = loginInfo?.user_id?:"", loginType = PreferenceUtil.getLoginType(), isLogin = true, data = loginInfo) ) + Toast.makeText(context, "登录成功", Toast.LENGTH_SHORT).show() //提示登录成功 if(isVisibilityBreak){ - navController?.popBackStack() + navController?.popBackStack() // 当允许返回上一页时,登录成功后,返回上一页 } - }else if(loginViewModel.loginState.value !=null && loginViewModel.loginState.value?.data?.token == null){ - //登录失败 - loginViewModel.setLogin(false) + loginViewModel.loginResult.value = null //清理loginState + }else if(loginViewModel.loginResult.value != null && loginViewModel.loginResult.value?.data?.token == null){ +// loginViewModel.setLogin(false) //登录失败 Log.w("LoginScreen","登录失败,无有效的Token") - Toast.makeText(context, "登录失败,请重新登录", Toast.LENGTH_SHORT).show() - } - } - - var globalWxAuthorization by mutableStateOf(GlobalStateManager(context).globalWxAuthorizationFlow().collectAsState(initial = "")) - LaunchedEffect(globalWxAuthorization.value) { - if(globalWxAuthorization.value?.isNotEmpty() == true){ - loginViewModel.requestWxLogin(globalWxAuthorization.value!!) - //清理globalWxAuthorization - GlobalStateManager(context).storeGlobalWxAuthorization("") - } - } - - LaunchedEffect(loginViewModel.authInfoForAlipay.value) { - if(loginViewModel.authInfoForAlipay.value.isEmpty()) return@LaunchedEffect - loginViewModel.loginWithAliPay(context){rawResult -> - Log.i("loginWithAliPay", "支付宝登录结果:$rawResult") - val alipayResult = rawResult.toAlipayResult() - // 处理支付宝登录结果 - when (alipayResult.resultStatus) { - "9000" -> { - // 登录成功,result 字段中包含 auth_code - val authCode = StringUtils.parseAlipayResult(alipayResult.result ?: "")["auth_code"] ?: "" - loginViewModel.requestAlipayLogin(authCode) - } - - "6001" -> { - "用户取消登录" - } - - else -> { - alipayResult.memo ?: "登录失败" - } - } - //清理authInfoForAlipay - loginViewModel.authInfoForAlipay.value = "" + Toast.makeText(context, "登录失败,请重新登录", Toast.LENGTH_SHORT).show()//提示登录成功 } } @@ -673,7 +645,7 @@ private fun OneKeyLoginScreen(context: Context, viewModel: LoginViewModel, gener "天翼账号提供认证服务" } "CU" -> {//联通 - "联通账号提供认证服务" + "认证服务由联通统一认证提供" } else -> {//移动 "移动账号提供认证服务" @@ -688,7 +660,6 @@ private fun OneKeyLoginScreen(context: Context, viewModel: LoginViewModel, gener } val agreementTextView = view.findViewById(R.id.layout_one_key_login_agreement_tv) - //TODO 服务协议,如:“登录即认可《天翼账号服务与隐私协议》、《用户协议》和《隐私政策》并使用本机号码登录” val targets = mapOf( "serviceAgreement" to privacyName, @@ -705,18 +676,28 @@ private fun OneKeyLoginScreen(context: Context, viewModel: LoginViewModel, gener } val loginButton = view.findViewById(R.id.layout_one_key_login_btn) - loginButton.setOnClickListener { - // 处理登录点击 - oneKeyLogin( - context = context, - numberTv = phoneTextView, - sloganTv = serviceTextView, - loginBtn = loginButton, - checkBox = checkbox, - privacyTv = agreementTextView, - viewModel = viewModel - ) - } + // 处理登录点击 + oneKeyLogin( + context = context, + numberTv = phoneTextView, + sloganTv = serviceTextView, + loginBtn = loginButton, + checkBox = checkbox, + privacyTv = agreementTextView, + viewModel = viewModel + ) +// loginButton.setOnClickListener { +// // 处理登录点击 +// oneKeyLogin( +// context = context, +// numberTv = phoneTextView, +// sloganTv = serviceTextView, +// loginBtn = loginButton, +// checkBox = checkbox, +// privacyTv = agreementTextView, +// viewModel = viewModel +// ) +// } } ) } @@ -776,7 +757,7 @@ private fun WxLoginScreen( // 启动微信验证,请求登录 if (viewModel.isPolicyAgreement.value) { //打开微信登录 - viewModel.loginWithWechat(context, generalViewModel.api) + viewModel.authorWechat(context, generalViewModel.api) } else { Toast.makeText( context, @@ -951,7 +932,7 @@ private fun AliPayLoginScreen( // 启动支付宝验证,请求登录 if (viewModel.isPolicyAgreement.value) { // 打开支付宝登录 - viewModel.requestAliPayAuthParam() + viewModel.requestAliPayAuthParam(context) } else { Toast.makeText( context, @@ -1395,27 +1376,10 @@ private fun oneKeyLogin( privacyTv: TextView, viewModel: LoginViewModel, ) { - val eloginActivityParam = EloginActivityParam() - .setActivity(context as Activity) - .setNumberTextview(numberTv) - .setSloganTextview(sloganTv) - .setLoginButton(loginBtn) - .setPrivacyCheckbox(checkBox) - .setPrivacyTextview(privacyTv) - .setUiErrorListener { msg -> //隐私协议未打勾、界面不合规、setLoginOnClickListener抛出异常等情况下的回调 - Log.e("OneKeyLogin", "UIErrorListener.onError:$msg") - } - .setLoginOnClickListener { - if (!checkBox.isChecked) { - // 抛出异常,避免sdk进行后续登录动作(否则eAccountLogin会回调onFailed错误) - throw IllegalStateException("请先仔细阅读协议并勾选,然后再点击登录") - } - //启动登录时候的转圈圈 - } - GYManager.getInstance().eAccountLogin(eloginActivityParam, 5000, object : GyCallBack { + val gyCallBack = object : GyCallBack { override fun onSuccess(response: GYResponse?) { - // 登录成功,需要与后端交互 - Log.i("OneKeyLogin", "onSuccess:$response") + loginBtn.isEnabled = true + Log.i("OneKeyLogin", "OneKeyLoginViewModel------onSuccess:$response") try { val jsonObject = JSONObject(response?.msg?:"{}") val data = jsonObject.getJSONObject("data") @@ -1427,12 +1391,32 @@ private fun oneKeyLogin( } override fun onFailed(p0: GYResponse?) { - // 登录失败 - Log.e("OneKeyLogin", "onFailed:$p0") + loginBtn.isEnabled = true + Log.e("OneKeyLogin", "OneKeyLoginViewModel------onFailed:$p0") } - }) -} + } + val eloginActivityParam = EloginActivityParam() + .setActivity(context as Activity) + .setNumberTextview(numberTv) + .setSloganTextview(sloganTv) + .setLoginButton(loginBtn) + .setPrivacyCheckbox(checkBox) + .setPrivacyTextview(privacyTv) + .setUiErrorListener { msg -> + loginBtn.isEnabled = true + Log.e("OneKeyLogin", "OneKeyLoginViewModel------UIErrorListener.onError:$msg") + } + .setLoginOnClickListener { + if (!checkBox.isChecked) { + throw IllegalStateException("请先仔细阅读协议并勾选,然后再点击登录") + } + loginBtn.isEnabled = false + } + + // 预先注册登录回调 + GYManager.getInstance().eAccountLogin(eloginActivityParam, 5000, gyCallBack) +} enum class LoginScreenType { LOGIN_NORMAL, diff --git a/app/src/main/java/com/img/rabbit/pages/screen/HomeScreen.kt b/app/src/main/java/com/img/rabbit/pages/screen/HomeScreen.kt index 34bcac7..f68090a 100644 --- a/app/src/main/java/com/img/rabbit/pages/screen/HomeScreen.kt +++ b/app/src/main/java/com/img/rabbit/pages/screen/HomeScreen.kt @@ -58,8 +58,10 @@ import com.img.rabbit.pages.LoadingCallback import com.img.rabbit.provider.storage.GlobalStateManager import com.img.rabbit.provider.storage.PreferenceUtil import com.img.rabbit.route.ScreenRoute +import com.img.rabbit.utils.AppEventBus import com.img.rabbit.utils.UniAppUtils import com.img.rabbit.utils.UniMpUpdate +import com.img.rabbit.utils.UniMpWXPayEvent import com.img.rabbit.viewmodel.GeneralViewModel import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch @@ -103,6 +105,15 @@ fun HomeScreen( } } + LaunchedEffect(Unit) { + AppEventBus.events.collect { event -> + when (event) { + is UniMpWXPayEvent.PayResult -> { + Log.i("HomeScreen", "HomeScreen----->PayResult: ${event.code}") + } + } + } + } var homeIconConfig by remember { mutableStateOf(PreferenceUtil.getUserConfig()?.config?.homeIconEntity) } var uniVersionConfig by remember { mutableStateOf(PreferenceUtil.getUserConfig()?.config?.uniVersionEntity) } diff --git a/app/src/main/java/com/img/rabbit/pages/screen/MineScreen.kt b/app/src/main/java/com/img/rabbit/pages/screen/MineScreen.kt index b156968..daa0b7b 100644 --- a/app/src/main/java/com/img/rabbit/pages/screen/MineScreen.kt +++ b/app/src/main/java/com/img/rabbit/pages/screen/MineScreen.kt @@ -72,7 +72,7 @@ fun MineScreen( val TAG = "Rabbit_Mine" val context = LocalContext.current val scope = rememberCoroutineScope() - var globalLogin by mutableStateOf(GlobalStateManager(context).globalLoginNotifyFlow().collectAsState(initial = false)) +// var globalLogin by mutableStateOf(GlobalStateManager(context).globalLoginNotifyFlow().collectAsState(initial = false)) var globalBind by mutableStateOf(GlobalStateManager(context).globalBindNotifyFlow().collectAsState(initial = false)) var globalUnBind by mutableStateOf(GlobalStateManager(context).globalUnBindNotifyFlow().collectAsState(initial = false)) @@ -105,7 +105,8 @@ fun MineScreen( } //刷新用户信息 - if(globalLogin.value == true || globalBind.value == true || globalUnBind.value == true){ +// if(globalLogin.value == true || globalBind.value == true || globalUnBind.value == true){ + if(globalBind.value == true || globalUnBind.value == true){ scope.launch { delay(300) userInfo = PreferenceUtil.getUserInfo() diff --git a/app/src/main/java/com/img/rabbit/pages/screen/mine/SettingScreen.kt b/app/src/main/java/com/img/rabbit/pages/screen/mine/SettingScreen.kt index 00afda3..e6b8b76 100644 --- a/app/src/main/java/com/img/rabbit/pages/screen/mine/SettingScreen.kt +++ b/app/src/main/java/com/img/rabbit/pages/screen/mine/SettingScreen.kt @@ -1,6 +1,7 @@ package com.img.rabbit.pages.screen.mine import android.annotation.SuppressLint +import android.util.Log import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.border @@ -44,44 +45,23 @@ import androidx.navigation.compose.rememberNavController import com.img.rabbit.R import com.img.rabbit.pages.toolbar.TitleBar import com.img.rabbit.provider.storage.GlobalStateManager +import com.img.rabbit.provider.storage.PreferenceUtil import com.img.rabbit.utils.AppDataStoreUtils +import com.img.rabbit.utils.AppEventBus +import com.img.rabbit.utils.LoginBindEvent import com.img.rabbit.viewmodel.LoginViewModel @SuppressLint("UnrememberedMutableState") @Composable fun SettingScreen(navController: NavHostController, loginViewModel: LoginViewModel) { val context = LocalContext.current - var globalLogin by mutableStateOf(GlobalStateManager(context).globalLoginNotifyFlow().collectAsState(initial = false)) var cacheDataSize by remember { mutableStateOf("正在计算...") } - /* - LaunchedEffect(loginViewModel.logoutState.value) { - if(loginViewModel.logoutState.value?.status == true){ - // 执行用户数据清除 - PreferenceUtil.clearLogin() - loginViewModel.setLogin(false) - // 跳转登录页面 - loginViewModel.restViewModel.intValue = 1 - - loginViewModel.logoutState.value = null - - loginViewModel.loginScreenType.value = LoginScreenType.LOGIN_NORMAL - navController.navigate("login?type=${LoginViewModel.JumpLoginType.FROM_LOGOUT.type}") { - // 清除所有页面,包括登录页 - popUpTo(navController.graph.startDestinationId) { inclusive = true } - } - } - } - */ LaunchedEffect(Unit) { AppDataStoreUtils.getAppStorageStats(context){ _, _, _, totalDataCacheSize -> cacheDataSize = totalDataCacheSize } } - if(globalLogin.value == true){ - navController.popBackStack() - } - Scaffold{ @@ -289,71 +269,73 @@ fun SettingScreen(navController: NavHostController, loginViewModel: LoginViewMod } } - //切换/退出账号 - Column( - modifier = Modifier.fillMaxWidth().align(Alignment.BottomCenter) - ) { - //账号切换 - Box( - modifier = Modifier - .fillMaxWidth() - .wrapContentHeight() - .padding(start = 33.dp, end = 33.dp, bottom = 18.dp) - .background( - Color(0x00000000), - shape = RoundedCornerShape(359.dp), - ) - .border(width = 1.dp, color = Color(0xFF000000), shape = RoundedCornerShape(359.dp)) - .clickable( - indication = null, - interactionSource = remember { MutableInteractionSource() } - ) { - //TODO 账号切换 - navController.navigate("managerAccount") - } + if(PreferenceUtil.getUserConfig()?.temp == false){ + //切换/退出账号 + Column( + modifier = Modifier.fillMaxWidth().align(Alignment.BottomCenter) ) { - Text( - "账号切换", - color = Color(0xFF1A1A1A), - fontSize = 16.sp, - fontWeight = FontWeight.Bold, + //账号切换 + Box( modifier = Modifier - .wrapContentWidth() + .fillMaxWidth() .wrapContentHeight() - .padding(vertical = 12.dp) - .align(Alignment.Center) - ) - } + .padding(start = 33.dp, end = 33.dp, bottom = 18.dp) + .background( + Color(0x00000000), + shape = RoundedCornerShape(359.dp), + ) + .border(width = 1.dp, color = Color(0xFF000000), shape = RoundedCornerShape(359.dp)) + .clickable( + indication = null, + interactionSource = remember { MutableInteractionSource() } + ) { + // 账号切换 + navController.navigate("managerAccount") + } + ) { + Text( + "账号切换", + color = Color(0xFF1A1A1A), + fontSize = 16.sp, + fontWeight = FontWeight.Bold, + modifier = Modifier + .wrapContentWidth() + .wrapContentHeight() + .padding(vertical = 12.dp) + .align(Alignment.Center) + ) + } - //退出登录 - Box( - modifier = Modifier - .fillMaxWidth() - .wrapContentHeight() - .padding(start = 33.dp, end = 33.dp, bottom = 30.dp) - .background( - Color(0xFF252525), - shape = RoundedCornerShape(359.dp), - ) - .clickable( - indication = null, - interactionSource = remember { MutableInteractionSource() } - ) { - // 退出登录 - loginViewModel.requestLogout(context) - } - ) { - Text( - "退出登录", - color = Color(0xFFC2FF43), - fontSize = 16.sp, - fontWeight = FontWeight.Bold, + //退出登录 + Box( modifier = Modifier - .wrapContentWidth() + .fillMaxWidth() .wrapContentHeight() - .padding(vertical = 12.dp) - .align(Alignment.Center) - ) + .padding(start = 33.dp, end = 33.dp, bottom = 30.dp) + .background( + Color(0xFF252525), + shape = RoundedCornerShape(359.dp), + ) + .clickable( + indication = null, + interactionSource = remember { MutableInteractionSource() } + ) { + // 退出登录 + loginViewModel.requestLogout(context) + } + ) { + Text( + "退出登录", + color = Color(0xFFC2FF43), + fontSize = 16.sp, + fontWeight = FontWeight.Bold, + modifier = Modifier + .wrapContentWidth() + .wrapContentHeight() + .padding(vertical = 12.dp) + .align(Alignment.Center) + ) + } } } } diff --git a/app/src/main/java/com/img/rabbit/pages/screen/mine/setting/AccountManagerScreen.kt b/app/src/main/java/com/img/rabbit/pages/screen/mine/setting/AccountManagerScreen.kt index 9daf222..fee074a 100644 --- a/app/src/main/java/com/img/rabbit/pages/screen/mine/setting/AccountManagerScreen.kt +++ b/app/src/main/java/com/img/rabbit/pages/screen/mine/setting/AccountManagerScreen.kt @@ -23,7 +23,6 @@ import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember @@ -50,16 +49,17 @@ import com.img.rabbit.R import com.img.rabbit.bean.response.UserInfoEntity import com.img.rabbit.pages.dialog.TipsDialog import com.img.rabbit.pages.toolbar.TitleBar -import com.img.rabbit.provider.storage.GlobalStateManager import com.img.rabbit.provider.storage.PreferenceUtil +import com.img.rabbit.utils.AppEventBus +import com.img.rabbit.utils.LoginBindEvent import com.img.rabbit.viewmodel.AccountManagerViewModel import com.img.rabbit.viewmodel.LoginViewModel +import kotlinx.coroutines.delay @SuppressLint("UnrememberedMutableState") @Composable fun AccountManagerScreen(navController: NavHostController, viewModel: AccountManagerViewModel = viewModel(), loginViewModel: LoginViewModel) { val context = LocalContext.current - var globalLogin by mutableStateOf(GlobalStateManager(context).globalLoginNotifyFlow().collectAsState(initial = false)) var showDialogStatus by mutableStateOf(false) var selectedUserInfo by mutableStateOf(null) @@ -69,23 +69,19 @@ fun AccountManagerScreen(navController: NavHostController, viewModel: AccountMan viewModel.requestAccount() } - if(globalLogin.value == true){ - viewModel.requestAccount() - } - LaunchedEffect(viewModel.switchState.value) { if (viewModel.switchState.value != null && viewModel.switchState.value?.data?.token != null) { - // 切换账号成功 + val loginInfo = viewModel.switchState.value?.data + PreferenceUtil.saveLoginType(null) + loginInfo?.let { PreferenceUtil.saveLoginInfo(it) } PreferenceUtil.saveAccessToken(viewModel.switchState.value?.data?.token) - - loginViewModel.setLogin(true) - //更新登录状态 - GlobalStateManager(context).storeGlobalLoginNotify(true) - //清理loginState - loginViewModel.loginState.value = null + AppEventBus.post( LoginBindEvent.Login(userId = loginInfo?.user_id?:"", loginType = null, isLogin = true, data = loginInfo) ) Toast.makeText(context, "切换账号成功!", Toast.LENGTH_SHORT).show() - navController.popBackStack() + //延迟执行,确保返回时,接口已经拿到最新的用户信息 + delay(500) + navController.popBackStack(route = "setting", inclusive = true) + viewModel.switchState.value = null } } LaunchedEffect(viewModel.errorState.value) { diff --git a/app/src/main/java/com/img/rabbit/pages/screen/mine/setting/BindScreen.kt b/app/src/main/java/com/img/rabbit/pages/screen/mine/setting/BindScreen.kt index 6ab48d8..77769db 100644 --- a/app/src/main/java/com/img/rabbit/pages/screen/mine/setting/BindScreen.kt +++ b/app/src/main/java/com/img/rabbit/pages/screen/mine/setting/BindScreen.kt @@ -73,7 +73,10 @@ import com.img.rabbit.pages.NetworkDisconnectedPage import com.img.rabbit.pages.toolbar.TitleBar import com.img.rabbit.provider.storage.GlobalStateManager import com.img.rabbit.utils.AgreementTextHelper +import com.img.rabbit.utils.AppEventBus +import com.img.rabbit.utils.LoginBindEvent import com.img.rabbit.utils.UrlLinkUtils.openAgreement +import com.img.rabbit.utils.WXAuthEvent import com.img.rabbit.viewmodel.BindViewModel import com.img.rabbit.viewmodel.GeneralViewModel import kotlinx.coroutines.delay @@ -96,12 +99,18 @@ fun BindScreen(navController: NavHostController, viewModel: BindViewModel = view } } - var globalWxAuthorization by mutableStateOf(GlobalStateManager(context).globalWxAuthorizationFlow().collectAsState(initial = "")) - LaunchedEffect(globalWxAuthorization.value) { - if(globalWxAuthorization.value?.isNotEmpty() == true){ - viewModel.requestWxBind(globalWxAuthorization.value!!) - //清理globalWxAuthorization - GlobalStateManager(context).storeGlobalWxAuthorization("") + //关于绑定授权的事件监听 + LaunchedEffect(Unit) { + AppEventBus.events.collect { event -> + when (event) { + //微信授权结果(authType=1 ---->拿着Code登录) + is WXAuthEvent.AuthResult -> { + if(viewModel.isBindWxAuthor){ + viewModel.requestWxBind(event.code) + viewModel.isBindWxAuthor = false + } + } + } } } diff --git a/app/src/main/java/com/img/rabbit/provider/storage/GlobalStateManager.kt b/app/src/main/java/com/img/rabbit/provider/storage/GlobalStateManager.kt index 9a569a6..3c14e5b 100644 --- a/app/src/main/java/com/img/rabbit/provider/storage/GlobalStateManager.kt +++ b/app/src/main/java/com/img/rabbit/provider/storage/GlobalStateManager.kt @@ -20,9 +20,6 @@ class GlobalStateManager( ) { companion object { private val GLOBAL_LOADING = booleanPreferencesKey("global_loading") - private val GLOBAL_WX_AUTHORIZATION = stringPreferencesKey("global_wx_authorization") - private val GLOBAL_LOGIN_NOTIFY = booleanPreferencesKey("global_login_notify") - private val GLOBAL_LOGOUT_NOTIFY = booleanPreferencesKey("global_logout_notify") private val GLOBAL_BIND_NOTIFY = booleanPreferencesKey("global_bind_notify") private val GLOBAL_UNBIND_NOTIFY = booleanPreferencesKey("global_unbind_notify") private val GLOBAL_UPDATE_NOTIFY = booleanPreferencesKey("global_update_notify") @@ -43,32 +40,6 @@ class GlobalStateManager( } } - - suspend fun storeGlobalWxAuthorization(value: String) { - context.storeData.edit { preferences -> - preferences[GLOBAL_WX_AUTHORIZATION] = value - } - } - fun globalWxAuthorizationFlow(): Flow { - return context.storeData.data.map { - preferences -> - preferences[GLOBAL_WX_AUTHORIZATION] - } - } - - - suspend fun storeGlobalLoginNotify(value: Boolean) { - context.storeData.edit { preferences -> - preferences[GLOBAL_LOGIN_NOTIFY] = value - } - } - fun globalLoginNotifyFlow(): Flow { - return context.storeData.data.map { - preferences -> - preferences[GLOBAL_LOGIN_NOTIFY] - } - } - suspend fun storeGlobalBindNotify(value: Boolean) { context.storeData.edit { preferences -> preferences[GLOBAL_BIND_NOTIFY] = value @@ -94,19 +65,6 @@ class GlobalStateManager( } - suspend fun storeGlobalLogoutNotify(value: Boolean) { - context.storeData.edit { preferences -> - preferences[GLOBAL_LOGOUT_NOTIFY] = value - } - } - fun globalLogoutNotifyFlow(): Flow { - return context.storeData.data.map { - preferences -> - preferences[GLOBAL_LOGOUT_NOTIFY] - } - } - - suspend fun storeGlobalUpdateNotify(value: Boolean) { context.storeData.edit { preferences -> diff --git a/app/src/main/java/com/img/rabbit/provider/storage/PreferenceUtil.kt b/app/src/main/java/com/img/rabbit/provider/storage/PreferenceUtil.kt index 9b94031..bafe0fd 100644 --- a/app/src/main/java/com/img/rabbit/provider/storage/PreferenceUtil.kt +++ b/app/src/main/java/com/img/rabbit/provider/storage/PreferenceUtil.kt @@ -22,6 +22,7 @@ object PreferenceUtil { private const val KEY_X_TOKEN = "x_token" private const val KEY_OAID = "android_oaid" private const val KEY_LOGIN_INFO = "login_info" + private const val KEY_LOGIN_TYPE = "login_type" private const val KEY_DB_VID = "bd_vid" private const val KEY_USER_CONFIG = "user_config" private const val KEY_WX_CODE = "wx_code" @@ -89,6 +90,14 @@ object PreferenceUtil { return gson.fromJson(mmkv.decodeString(KEY_USER_CONFIG, "{}"), UserConfigEntity::class.java) } + fun saveLoginType(type: String?) { + mmkv.encode(KEY_LOGIN_TYPE, type) + } + + fun getLoginType(): String? { + return mmkv.decodeString(KEY_LOGIN_TYPE, null) + } + fun loginInfo(): LoginInfoEntity?{ return getLoginInfos()?.find { it.isLogin } diff --git a/app/src/main/java/com/img/rabbit/utils/AppEventBus.kt b/app/src/main/java/com/img/rabbit/utils/AppEventBus.kt new file mode 100644 index 0000000..814b7ba --- /dev/null +++ b/app/src/main/java/com/img/rabbit/utils/AppEventBus.kt @@ -0,0 +1,62 @@ +package com.img.rabbit.utils + +import com.img.rabbit.pages.LoginScreenType +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.asSharedFlow + +object AppEventBus { + /* + private val _events = MutableSharedFlow( + replay = 1, // 关键:保存最后 1 条,新订阅者能收到旧消息 + onBufferOverflow = BufferOverflow.DROP_OLDEST // 缓冲区满时丢弃旧的 + ) + val events = _events.asSharedFlow() + */ + private val _events = MutableSharedFlow() + val events = _events.asSharedFlow() + + suspend fun post(event: UniMpWXPayEvent) { + _events.emit(event) + } + + suspend fun post(event: LoginBindEvent) { + _events.emit(event) + } + + suspend fun post(event: WXAuthEvent) { + _events.emit(event) + } +} + +/** + * 登录、绑定与退出账号事件 + */ +sealed class LoginBindEvent { + /** + * 处理登录与登出(isLogin:true 登录,false 登出) + * 登录类型:LoginScreenType + * 传递数据:data + */ + data class Login(val userId: String?, val loginType: String?, val isLogin: Boolean, val data: Any?) : LoginBindEvent() + /** + * 处理绑定与解绑(isBind:true 绑定,false 解绑) + * 绑定类型:LoginScreenType,仅包含手机(LoginScreenType.LOGIN_CAPTCHA)和微信(LoginScreenType.LOGIN_WX) + */ + data class Bind(val userId: String, val loginType: LoginScreenType, val isBind: Boolean) : LoginBindEvent() +} + + +/** + * 微信授权 + * 授权类型:authType=0 登录 + */ +sealed class WXAuthEvent { + data class AuthResult(val code: String, val authType: Int) : WXAuthEvent() +} + +/** + * UniMp小程序调用微信支付事件结果通知 + */ +sealed class UniMpWXPayEvent { + data class PayResult(val code: Int) : UniMpWXPayEvent() +} diff --git a/app/src/main/java/com/img/rabbit/utils/UniAppUtils.kt b/app/src/main/java/com/img/rabbit/utils/UniAppUtils.kt index 034fae0..7373bc4 100644 --- a/app/src/main/java/com/img/rabbit/utils/UniAppUtils.kt +++ b/app/src/main/java/com/img/rabbit/utils/UniAppUtils.kt @@ -25,6 +25,9 @@ import kotlin.jvm.java object UniAppUtils { + /** + * 所有运行的UniMp小程序实体 + */ val uniMpPair = mutableMapOf() //当前正在更新的小程序 @@ -33,6 +36,14 @@ object UniAppUtils { var currentDownloadUniMp: UniVersionEntity? = null //仅当跳转指定小程序时,才需要跳转指定位置 var currentUniMpJumpPatch: String? = null + + + /** + *获取当前前台运行的UniMp小程序实体 + */ + fun getCurrentUniMp(): IUniMP?{ + return uniMpPair.filter { it.value?.isRunning == true }.values.firstOrNull() + } /** * 是否存在更新 */ diff --git a/app/src/main/java/com/img/rabbit/viewmodel/BindViewModel.kt b/app/src/main/java/com/img/rabbit/viewmodel/BindViewModel.kt index caecb39..b8115eb 100644 --- a/app/src/main/java/com/img/rabbit/viewmodel/BindViewModel.kt +++ b/app/src/main/java/com/img/rabbit/viewmodel/BindViewModel.kt @@ -26,6 +26,7 @@ import okhttp3.RequestBody.Companion.toRequestBody class BindViewModel : BaseViewModel() { private val TAG = "BindViewModel" private val ONEKEY_TAG = "BindViewModel_OneKey" + var isBindWxAuthor = false val bindScreenType = mutableStateOf(BindScreenType.BIND_NORMAL) // 登录状态 val bindState = mutableStateOf?>(null) @@ -216,6 +217,7 @@ class BindViewModel : BaseViewModel() { Toast.makeText(context, "您没有安装微信客户端,请先下载安装", Toast.LENGTH_SHORT).show() return } + isBindWxAuthor = true val req = SendAuth.Req() req.scope = "snsapi_userinfo" // 只能填 snsapi_userinfo req.state = context.packageName + Math.random() * 1000 + "_phone" diff --git a/app/src/main/java/com/img/rabbit/viewmodel/GeneralViewModel.kt b/app/src/main/java/com/img/rabbit/viewmodel/GeneralViewModel.kt index 47f61ed..214c805 100644 --- a/app/src/main/java/com/img/rabbit/viewmodel/GeneralViewModel.kt +++ b/app/src/main/java/com/img/rabbit/viewmodel/GeneralViewModel.kt @@ -1,8 +1,13 @@ package com.img.rabbit.viewmodel import android.annotation.SuppressLint +import android.app.Activity import android.app.Application +import android.content.BroadcastReceiver import android.content.Context +import android.content.Context.RECEIVER_EXPORTED +import android.content.Intent +import android.content.IntentFilter import android.net.ConnectivityManager import android.net.Network import android.net.NetworkCapabilities @@ -10,29 +15,25 @@ import android.net.NetworkRequest import android.os.Build import androidx.compose.runtime.State import androidx.compose.runtime.mutableStateOf +import androidx.core.content.ContextCompat.registerReceiver import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.viewModelScope -import com.img.rabbit.bean.response.UniVersionEntity -import com.img.rabbit.bean.response.VersionEntity import com.img.rabbit.config.Constants import com.img.rabbit.provider.api.ApiManager -import com.img.rabbit.provider.storage.GlobalStateManager import com.img.rabbit.provider.storage.PreferenceUtil -import com.img.rabbit.utils.MMKVUtils.mmkv +import com.tencent.mm.opensdk.constants.ConstantsAPI +import com.tencent.mm.opensdk.modelpay.PayReq import com.tencent.mm.opensdk.openapi.IWXAPI import com.tencent.mm.opensdk.openapi.WXAPIFactory import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.GlobalScope -import kotlinx.coroutines.flow.SharingStarted -import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch @SuppressLint("ObsoleteSdkInt") class GeneralViewModel(application: Application) : AndroidViewModel(application) { lateinit var api: IWXAPI + lateinit var receiver: android.content.BroadcastReceiver private val _networkStatus = MutableLiveData() val networkStatus: LiveData = _networkStatus fun setNetworkStatus(status: Boolean) { @@ -103,9 +104,36 @@ class GeneralViewModel(application: Application) : AndroidViewModel(application) } private fun initWXApi(context: Context) { - api = WXAPIFactory.createWXAPI(context, Constants.WechatAppId) + api = WXAPIFactory.createWXAPI(context, Constants.WxAppId, true) + api.registerApp(Constants.WxAppId) + + //建议动态监听微信启动广播进行注册到微信 + receiver = object : BroadcastReceiver() { + override fun onReceive(context: Context?, intent: Intent?) { + // 将该app注册到微信 + api.registerApp(Constants.WxAppId) + } + } + + //建议动态监听微信启动广播进行注册到微信 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + context.registerReceiver(receiver, + IntentFilter(ConstantsAPI.ACTION_REFRESH_WXAPP), RECEIVER_EXPORTED) + } } +// private fun wxPay(api: IWXAPI){ +// val request = PayReq() +// request.appId = "wx7d1a7d1507482cef" +// request.partnerId = "1511850511"; +// request.prepayId= "wx06112039579543463f9116a0527ce30001" +// request.packageValue = "Sign=WXPay" +// request.nonceStr= "QjlkDdZY54eKmvfKrtawJD9Cws7pvUh0" +// request.timeStamp= "1772767239" +// request.sign= "DOhyV8QBng20nrZxgV8l8+4DD1foi7XKRfPnhHbzf63qWvL2f3miKTqAVtoS1U9syO38ENXrS18XzWHRMNnoyWgTGLp/SxbZjRjqHvrLJKIa1pH0svdv/uPXK1GlvjqsMXgeoTEXn73aHBNlcctNaZ8GCWbxpg77kdcCJfM+qWOSQOMJOpKh8lTx4dQzhWqdOSzABkQJTg6TThNUN3/00yeN7K9wZ4JOpN+Tmtaliztp0wQ3iAHgAqZmhxwv7ZyRev2izpoukdJ2aBn/+xPK/Hs5kI2KM67x6quvrWiQV31GixU2i84ddI3uxn1DwR90f5iEyA10NOylPA+D9rOEUQ==" +// api.sendReq(request) +// } + override fun onCleared() { super.onCleared() connectivityManager.unregisterNetworkCallback(networkCallback) diff --git a/app/src/main/java/com/img/rabbit/viewmodel/LoginViewModel.kt b/app/src/main/java/com/img/rabbit/viewmodel/LoginViewModel.kt index a972b78..42e6903 100644 --- a/app/src/main/java/com/img/rabbit/viewmodel/LoginViewModel.kt +++ b/app/src/main/java/com/img/rabbit/viewmodel/LoginViewModel.kt @@ -8,7 +8,6 @@ import android.widget.Toast import androidx.compose.runtime.MutableState import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.State -import androidx.compose.runtime.mutableIntStateOf import com.alipay.sdk.app.AuthTask import com.img.rabbit.pages.LoginScreenType import com.g.gysdk.GYManager @@ -19,24 +18,24 @@ import com.github.gzuliyujiang.oaid.DeviceIdentifier import com.google.gson.JsonObject import com.img.rabbit.bean.local.ErrorBean import com.img.rabbit.bean.local.OnekeyPreLogin +import com.img.rabbit.bean.local.toAlipayResult import com.img.rabbit.bean.response.LoginInfoEntity -import com.img.rabbit.bean.response.UniVersionEntity import com.img.rabbit.bean.response.UserConfigEntity import com.img.rabbit.provider.api.ApiManager import com.img.rabbit.provider.api.ResultVo import com.img.rabbit.provider.storage.GlobalStateManager import com.img.rabbit.provider.storage.PreferenceUtil import com.img.rabbit.provider.utils.HeadParamUtils.applicationContext +import com.img.rabbit.utils.AppEventBus +import com.img.rabbit.utils.LoginBindEvent import com.img.rabbit.utils.MMKVUtils -import com.img.rabbit.utils.UniAppUtils +import com.img.rabbit.utils.StringUtils import com.tencent.mm.opensdk.modelmsg.SendAuth import com.tencent.mm.opensdk.openapi.IWXAPI -import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch -import kotlinx.coroutines.suspendCancellableCoroutine import kotlinx.coroutines.withContext import kotlinx.serialization.json.Json import okhttp3.RequestBody.Companion.toRequestBody @@ -46,22 +45,24 @@ class LoginViewModel : BaseViewModel() { private val ONEKEY_TAG = "OneKeyLoginViewModel" //private lateinit var api: IWXAPI - + var isLoginWxAuthor = false val authInfoForAlipay: MutableState = mutableStateOf("") val loginScreenType = mutableStateOf(LoginScreenType.LOGIN_NORMAL) // 登录用户名 val userName = mutableStateOf("") - // 登录验证码 - val captcha = mutableStateOf("") - // 登录验证码发送时间戳 - val captchaTimestamp = mutableStateOf("") - fun setCaptcha(loginCaptcha: String) { - captcha.value = loginCaptcha - } fun setUserName(loginName: String) { userName.value = loginName } + // 登录验证码 + val captcha = mutableStateOf("") + fun setCaptcha(loginCaptcha: String) { + captcha.value = loginCaptcha + } + // 登录验证码发送时间戳 + val captchaTimestamp = mutableStateOf("") + + private val isGYUIDValid = mutableStateOf(false) @@ -79,20 +80,39 @@ class LoginViewModel : BaseViewModel() { _policyAgreement.value = isAgreement } - private val _isLogin = mutableStateOf(false) - val isLogin: State = _isLogin - - fun setLogin(isLogin: Boolean) { - _isLogin.value = isLogin - } +// private val _isLogin = mutableStateOf(false) +// val isLogin: State = _isLogin +// +// fun setLogin(isLogin: Boolean) { +// _isLogin.value = isLogin +// } - // 登录状态 - val loginState = mutableStateOf?>(null) + // 登录获取结果 + val loginResult = mutableStateOf?>(null) + + // 用户配置获取结果 + val userConfigResult = mutableStateOf?>(null) + // 错误状态 val errorState = mutableStateOf(null) + fun reset(){ + isLoginWxAuthor = false + authInfoForAlipay.value = "" + loginScreenType.value = LoginScreenType.LOGIN_NORMAL + userName.value = "" + captcha.value = "" + captchaTimestamp.value = "" + isGYUIDValid.value = false + oneKeyPreLogin = null + setIsPolicyAgreement(true) + loginResult.value = null + userConfigResult.value = null + errorState.value = null + } + fun requestUserConfig(){ mLaunch { val oaid = MMKVUtils.getString("oaid") ?: "" @@ -101,6 +121,7 @@ class LoginViewModel : BaseViewModel() { PreferenceUtil.saveXToken(response.data.token) PreferenceUtil.setTimeDiff(response.data.nowtime.toLong() - System.currentTimeMillis() / 1000) PreferenceUtil.saveUserConfig(response.data) + userConfigResult.value = response applicationContext?.let { GlobalStateManager(it) }?.storeGlobalUserConfigNotify(true) }else{ @@ -143,9 +164,7 @@ class LoginViewModel : BaseViewModel() { // 根据解析结果决定是否继续(根据errorCode判断) if (oneKeyPreLogin?.errorCode == 0) { - oneKeyLoginValid( - onShowOneKeyScreen = onShowOneKeyScreen - ) + oneKeyLoginValid(onShowOneKeyScreen = onShowOneKeyScreen) } else { onShowOneKeyScreen(false) Log.e(ONEKEY_TAG, "预登录校验失败: ${oneKeyPreLogin?.errorDesc}") @@ -210,7 +229,8 @@ class LoginViewModel : BaseViewModel() { jsonObject.addProperty("bind", "") jsonObject.add("data", jsonOneKey) - requestLogin(jsonObject) + Log.i(ONEKEY_TAG, "--->开始登录") + requestLogin(jsonObject, LoginScreenType.LOGIN_ONE_KEY) } @@ -252,72 +272,58 @@ class LoginViewModel : BaseViewModel() { jsonObject.addProperty("login_type", "phone") jsonObject.add("phone", jsonPhone) - requestLogin(jsonObject) + requestLogin(jsonObject, LoginScreenType.LOGIN_CAPTCHA) } - fun loginWithWechat(context: Context, wxApi:IWXAPI) { + fun authorWechat(context: Context, wxApi:IWXAPI) { if (isPolicyAgreement.value) { - doWxAuth(context, wxApi) + if (!wxApi.isWXAppInstalled) { + Toast.makeText(context, "您没有安装微信客户端,请先下载安装", Toast.LENGTH_SHORT).show() + return + } + isLoginWxAuthor = true + val req = SendAuth.Req() + req.scope = "snsapi_userinfo" // 只能填 snsapi_userinfo + req.state = context.packageName + Math.random() * 1000 + "_phone" + wxApi.sendReq(req) }else{ Toast.makeText(context, "请先同意用户协议和隐私政策", Toast.LENGTH_SHORT).show() } } - //获取微信授权 - private fun doWxAuth(context: Context, wxApi:IWXAPI) { - if (!wxApi.isWXAppInstalled) { - Toast.makeText(context, "您没有安装微信客户端,请先下载安装", Toast.LENGTH_SHORT).show() - return - } - val req = SendAuth.Req() - req.scope = "snsapi_userinfo" // 只能填 snsapi_userinfo - req.state = context.packageName + Math.random() * 1000 + "_phone" - wxApi.sendReq(req) + fun requestWxLogin(code: String){ + val jsonObject = getWxLoginParam(code) ?: return + requestLogin(jsonObject, LoginScreenType.LOGIN_WX) } /** * 拿着微信授权码完成登录(在WXEntryActivity中调用) - * @param wechatCode 微信授权码 + * @param code 微信授权码 */ - fun requestWxLogin(wechatCode: String) { - if(wechatCode.isEmpty()){ - return + fun getWxLoginParam(code: String): JsonObject? { + if(code.isEmpty()){ + return null } isLoading.value = true // 开始加载 - PreferenceUtil.saveWxCode(wechatCode) + PreferenceUtil.saveWxCode(code) // 调用 API 获取数据 val jsonWx = JsonObject() - jsonWx.addProperty("code", wechatCode) + jsonWx.addProperty("code", code) jsonWx.addProperty("code_type", "") val jsonObject = JsonObject() jsonObject.addProperty("login_type", "weixin") jsonObject.add("weixin", jsonWx) - requestLogin(jsonObject) + return jsonObject } - /** - * 支付宝登录 - * authInfo: 该参数需由后端生成并加签,包含 app_id、pid、target_id 等信息 - */ - fun loginWithAliPay(context: Context,onAuthResult: (Map) -> Unit) { - if(authInfoForAlipay.value.isEmpty()){ - Toast.makeText(context, "请先获取支付宝登录授权码", Toast.LENGTH_SHORT).show() - return - } - // 发送请求获取支付宝登录授权码 - mLaunch { - onAuthResult(doAlipayLogin(context as Activity, authInfoForAlipay.value)) - } - } - /** * 请求支付宝登录参数 */ - fun requestAliPayAuthParam() { + fun requestAliPayAuthParam(context: Context) { isLoading.value = true // 开始加载 mLaunch { @@ -325,11 +331,42 @@ class LoginViewModel : BaseViewModel() { val data = response.data val param = data.param + authorAlipay(context = context,authParam = param) authInfoForAlipay.value = param isLoading.value = false // 加载完成 } } + private fun authorAlipay(context: Context, authParam: String){ + if(authParam.isEmpty()){ + Toast.makeText(context, "请先获取支付宝登录授权码", Toast.LENGTH_SHORT).show() + return + } + // 发送请求获取支付宝登录授权码 + mLaunch { + val authorResult = doAlipayLogin(context as Activity, authParam) + Log.i("loginWithAliPay", "支付宝登录结果:$authorResult") + val alipayResult = authorResult.toAlipayResult() + // 处理支付宝登录结果 + when (alipayResult.resultStatus) { + "9000" -> { + // 登录成功,result 字段中包含 auth_code + val authCode = StringUtils.parseAlipayResult(alipayResult.result ?: "")["auth_code"] ?: "" + val jsonObject = getAlipayLoginParam(authCode) ?: return@mLaunch + requestLogin(jsonObject, LoginScreenType.LOGIN_ALIPAY) + } + + "6001" -> { + "用户取消登录" + } + + else -> { + alipayResult.memo ?: "登录失败" + } + } + } + } + /** * 封装支付宝登录逻辑 * @param activity 当前 Activity 上下文 @@ -350,12 +387,12 @@ class LoginViewModel : BaseViewModel() { } /** - * 拿着微信授权码完成登录(在WXEntryActivity中调用) - * @param authCode 微信授权码 + * 拿着支付宝授权码完成登录 + * @param authCode 支付宝授权码 */ - fun requestAlipayLogin(authCode: String) { + private fun getAlipayLoginParam(authCode: String): JsonObject? { if(authCode.isEmpty()){ - return + return null } isLoading.value = true // 开始加载 @@ -368,19 +405,18 @@ class LoginViewModel : BaseViewModel() { jsonObject.addProperty("bind", "") jsonObject.add("data", jsonWx) - requestLogin(jsonObject) + return jsonObject } //请求登录 - private fun requestLogin(jsonObject: JsonObject){ + private fun requestLogin(jsonObject: JsonObject, loginType: LoginScreenType){ mLaunch { val response = ApiManager.serviceVo.login(jsonObject.toString().toRequestBody()) if (response.status) { - loginState.value = response - val loginInfoEntity = response.data - loginInfoEntity.isLogin = true - //记录登录数据 - PreferenceUtil.saveLoginInfo(loginInfoEntity) + PreferenceUtil.saveLoginType(loginType.name) + PreferenceUtil.saveLoginInfo(response.data.apply { isLogin = true })//记录登录数据 + PreferenceUtil.saveAccessToken(response.data.token) + loginResult.value = response }else{ errorState.value = ErrorBean(response.code.toString(), response.message.ifEmpty { "登录失败" }) } @@ -409,12 +445,12 @@ class LoginViewModel : BaseViewModel() { if (response.status) { //logoutState.value = response PreferenceUtil.clearLogin() - setLogin(false) +// setLogin(false) // 跳转登录页面 - //restViewModel.intValue = 1 - GlobalScope.launch { - GlobalStateManager(context).storeGlobalLogoutNotify(true) - } +// GlobalScope.launch { +// GlobalStateManager(context).storeGlobalLogoutNotify(true) +// } + AppEventBus.post( LoginBindEvent.Login(userId = null, loginType = PreferenceUtil.getLoginType(), isLogin = false, data = null) ) } else { errorState.value = ErrorBean(response.code.toString(), response.message.ifEmpty { "退出登录失败" }) } diff --git a/app/src/main/java/com/img/rabbit/wxapi/WXEntryActivity.kt b/app/src/main/java/com/img/rabbit/wxapi/WXEntryActivity.kt index 0ff41f1..9c09ff5 100644 --- a/app/src/main/java/com/img/rabbit/wxapi/WXEntryActivity.kt +++ b/app/src/main/java/com/img/rabbit/wxapi/WXEntryActivity.kt @@ -2,7 +2,8 @@ package com.img.rabbit.wxapi -import com.img.rabbit.provider.storage.GlobalStateManager +import com.img.rabbit.utils.AppEventBus +import com.img.rabbit.utils.WXAuthEvent import com.tencent.mm.opensdk.constants.ConstantsAPI import com.tencent.mm.opensdk.modelbase.BaseResp import com.tencent.mm.opensdk.modelmsg.SendAuth @@ -22,8 +23,13 @@ class WXEntryActivity : WXCallbackActivity() { //val wxState = WxBean(code = authResp.code,state = authResp.state) GlobalScope.launch { - GlobalStateManager(this@WXEntryActivity).storeGlobalWxAuthorization(authResp.code) - + //GlobalStateManager(this@WXEntryActivity).storeGlobalWxAuthorization(authResp.code) + AppEventBus.post( + WXAuthEvent.AuthResult( + code = authResp.code, + authType = 0 + ) + ) finish() } } diff --git a/app/src/main/java/com/img/rabbit/wxapi/WXPayEntryActivity.kt b/app/src/main/java/com/img/rabbit/wxapi/WXPayEntryActivity.kt index 91208f2..74b9dc4 100644 --- a/app/src/main/java/com/img/rabbit/wxapi/WXPayEntryActivity.kt +++ b/app/src/main/java/com/img/rabbit/wxapi/WXPayEntryActivity.kt @@ -1,11 +1,46 @@ +package com.img.rabbit.wxapi +import android.content.Intent +import android.os.Bundle +import androidx.lifecycle.ViewModelProvider +import com.img.rabbit.utils.UniAppUtils +import com.img.rabbit.viewmodel.GeneralViewModel +import com.tencent.mm.opensdk.constants.ConstantsAPI +import com.tencent.mm.opensdk.modelbase.BaseReq +import com.tencent.mm.opensdk.modelbase.BaseResp +import io.dcloud.feature.payment.weixin.AbsWXPayCallbackActivity +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers -package com.img.rabbit.wxapi; +class WXPayEntryActivity : AbsWXPayCallbackActivity() { + //val scope = CoroutineScope(Dispatchers.Main) + private lateinit var generalViewModel: GeneralViewModel + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + generalViewModel = ViewModelProvider.AndroidViewModelFactory.getInstance(application) + .create(GeneralViewModel::class.java) + generalViewModel.api.handleIntent(intent, this) + } -import io.dcloud.feature.payment.weixin.AbsWXPayCallbackActivity; + override fun onNewIntent(intent: Intent?) { + super.onNewIntent(intent) + setIntent(intent) + generalViewModel.api.handleIntent(getIntent(), this) + } + override fun onReq(baseReq: BaseReq?) { } + + override fun onResp(baseResp: BaseResp) { + super.onResp(baseResp) + if (baseResp.type == ConstantsAPI.COMMAND_PAY_BY_WX) { + // 处理支付结果 + //scope.launch { AppEventBus.post(UniMpWXPayEvent.PayResult(baseResp.errCode)) } + //结果通知到UniMp小程序 + UniAppUtils.getCurrentUniMp()?.sendUniMPEvent("wx_pay_result", baseResp.errCode) + + finish() + } + } -public class WXPayEntryActivity extends AbsWXPayCallbackActivity{ - } diff --git a/settings.gradle.kts b/settings.gradle.kts index f2788e5..f43643f 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -15,11 +15,15 @@ pluginManagement { gradlePluginPortal() } } +@Suppress("UnstableApiUsage") dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositories { google() mavenCentral() + flatDir { + dirs("app/libs") + } maven { url = uri("https://jitpack.io") } maven { url = uri("https://company/com/maven2") } maven { url = uri("https://repo1.maven.org/maven2/") } @@ -32,8 +36,6 @@ dependencyResolutionManagement { maven { url = uri("https://developer.hihonor.com/repo/") } maven { url = uri("https://artifact.bytedance.com/repository/Volcengine/") } //巨量融合 maven { url = uri("https://repo.eclipse.org/content/repositories/paho-snapshots/") } //mqtt - mavenCentral() - google() } }