parent
3828c73d44
commit
054597ea96
|
|
@ -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)
|
||||
|
||||
}
|
||||
|
|
@ -26,6 +26,10 @@
|
|||
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
|
||||
<!--开关wifi状态,解决国内机型移动网络权限问题需要-->
|
||||
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
|
||||
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
|
||||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
|
||||
<!--Unimp要求-->
|
||||
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
|
||||
|
||||
<!-- 安装应用权限 -->
|
||||
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"
|
||||
|
|
@ -93,10 +97,9 @@
|
|||
|
||||
|
||||
<activity
|
||||
android:name=".wxapi.WXPayEntryActivity"
|
||||
android:excludeFromRecents="true"
|
||||
android:name="com.img.rabbit.wxapi.WXPayEntryActivity"
|
||||
android:exported="true"
|
||||
android:launchMode="singleTask"
|
||||
android:launchMode="singleTop"
|
||||
android:theme="@android:style/Theme.Translucent.NoTitleBar"/>
|
||||
|
||||
|
||||
|
|
@ -146,6 +149,15 @@
|
|||
android:resource="@xml/dcloud_file_provider" />
|
||||
</provider>
|
||||
|
||||
<meta-data
|
||||
android:name="UMENG_CHANNEL"
|
||||
android:value="${UMENG_CHANNEL}" />
|
||||
<meta-data
|
||||
android:name="WX_APPID"
|
||||
android:value="wx7d1a7d1507482cef" />
|
||||
<meta-data
|
||||
android:name="WX_SECRET"
|
||||
android:value="5264c353296db25405fc29e43c40d3a5" />
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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<TextView>(R.id.layout_one_key_login_agreement_tv)
|
||||
//TODO 服务协议,如:“登录即认可《天翼账号服务与隐私协议》、《用户协议》和《隐私政策》并使用本机号码登录”
|
||||
|
||||
val targets = mapOf(
|
||||
"serviceAgreement" to privacyName,
|
||||
|
|
@ -705,7 +676,6 @@ private fun OneKeyLoginScreen(context: Context, viewModel: LoginViewModel, gener
|
|||
}
|
||||
|
||||
val loginButton = view.findViewById<TextView>(R.id.layout_one_key_login_btn)
|
||||
loginButton.setOnClickListener {
|
||||
// 处理登录点击
|
||||
oneKeyLogin(
|
||||
context = context,
|
||||
|
|
@ -716,7 +686,18 @@ private fun OneKeyLoginScreen(context: Context, viewModel: LoginViewModel, gener
|
|||
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,
|
||||
|
|
|
|||
|
|
@ -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) }
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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,6 +269,7 @@ fun SettingScreen(navController: NavHostController, loginViewModel: LoginViewMod
|
|||
}
|
||||
}
|
||||
|
||||
if(PreferenceUtil.getUserConfig()?.temp == false){
|
||||
//切换/退出账号
|
||||
Column(
|
||||
modifier = Modifier.fillMaxWidth().align(Alignment.BottomCenter)
|
||||
|
|
@ -308,7 +289,7 @@ fun SettingScreen(navController: NavHostController, loginViewModel: LoginViewMod
|
|||
indication = null,
|
||||
interactionSource = remember { MutableInteractionSource() }
|
||||
) {
|
||||
//TODO 账号切换
|
||||
// 账号切换
|
||||
navController.navigate("managerAccount")
|
||||
}
|
||||
) {
|
||||
|
|
@ -360,6 +341,7 @@ fun SettingScreen(navController: NavHostController, loginViewModel: LoginViewMod
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(showBackground = true)
|
||||
@Composable
|
||||
|
|
|
|||
|
|
@ -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<UserInfoEntity?>(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) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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<String?> {
|
||||
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<Boolean?> {
|
||||
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<Boolean?> {
|
||||
return context.storeData.data.map {
|
||||
preferences ->
|
||||
preferences[GLOBAL_LOGOUT_NOTIFY]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
suspend fun storeGlobalUpdateNotify(value: Boolean) {
|
||||
context.storeData.edit { preferences ->
|
||||
|
|
|
|||
|
|
@ -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 }
|
||||
|
|
|
|||
|
|
@ -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<LoginBindEvent>(
|
||||
replay = 1, // 关键:保存最后 1 条,新订阅者能收到旧消息
|
||||
onBufferOverflow = BufferOverflow.DROP_OLDEST // 缓冲区满时丢弃旧的
|
||||
)
|
||||
val events = _events.asSharedFlow()
|
||||
*/
|
||||
private val _events = MutableSharedFlow<Any>()
|
||||
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()
|
||||
}
|
||||
|
|
@ -25,6 +25,9 @@ import kotlin.jvm.java
|
|||
|
||||
|
||||
object UniAppUtils {
|
||||
/**
|
||||
* 所有运行的UniMp小程序实体
|
||||
*/
|
||||
val uniMpPair = mutableMapOf<String?, IUniMP?>()
|
||||
|
||||
//当前正在更新的小程序
|
||||
|
|
@ -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()
|
||||
}
|
||||
/**
|
||||
* 是否存在更新
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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<ResultVo<LoginInfoEntity>?>(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"
|
||||
|
|
|
|||
|
|
@ -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<Boolean>()
|
||||
val networkStatus: LiveData<Boolean> = _networkStatus
|
||||
fun setNetworkStatus(status: Boolean) {
|
||||
|
|
@ -103,8 +104,35 @@ 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()
|
||||
|
|
|
|||
|
|
@ -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<String> = 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<Boolean> = _isLogin
|
||||
|
||||
fun setLogin(isLogin: Boolean) {
|
||||
_isLogin.value = isLogin
|
||||
}
|
||||
// private val _isLogin = mutableStateOf(false)
|
||||
// val isLogin: State<Boolean> = _isLogin
|
||||
//
|
||||
// fun setLogin(isLogin: Boolean) {
|
||||
// _isLogin.value = isLogin
|
||||
// }
|
||||
|
||||
|
||||
|
||||
// 登录状态
|
||||
val loginState = mutableStateOf<ResultVo<LoginInfoEntity>?>(null)
|
||||
// 登录获取结果
|
||||
val loginResult = mutableStateOf<ResultVo<LoginInfoEntity>?>(null)
|
||||
|
||||
// 用户配置获取结果
|
||||
val userConfigResult = mutableStateOf<ResultVo<UserConfigEntity>?>(null)
|
||||
|
||||
// 错误状态
|
||||
val errorState = mutableStateOf<ErrorBean?>(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<String, String>) -> 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 { "退出登录失败" })
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,45 @@
|
|||
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?) { }
|
||||
|
||||
public class WXPayEntryActivity extends AbsWXPayCallbackActivity{
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue