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()
}
}