From 5f0a7b3a22353af8fb4d82d794f55d4f2abb8643 Mon Sep 17 00:00:00 2001 From: shenzuqiang Date: Wed, 11 Mar 2026 09:28:42 +0800 Subject: [PATCH] =?UTF-8?q?Dev=EF=BC=9A=201=E3=80=81=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E4=BA=8B=E4=BB=B6=E4=B8=8A=E6=8A=A5=202=E3=80=81Uni=E5=B0=8F?= =?UTF-8?q?=E7=A8=8B=E5=BA=8F=E8=B5=84=E6=BA=90=E5=8E=8B=E7=BC=A9=E8=A7=A3?= =?UTF-8?q?=E5=8E=8B=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle.kts | 7 +- app/proguard-rules.pro | 383 ++++++++++++++++++ .../java/com/img/rabbit/BaseApplication.kt | 2 +- .../main/java/com/img/rabbit/MainActivity.kt | 36 +- .../img/rabbit/bean/request/ReportRequest.kt | 22 + .../img/rabbit/bean/response/ConfigEntity.kt | 4 +- .../java/com/img/rabbit/pages/LoginPage.kt | 21 +- .../com/img/rabbit/pages/screen/HomeScreen.kt | 10 +- .../rabbit/pages/screen/mine/SettingScreen.kt | 28 +- .../mine/setting/DeleteAccountScreen.kt | 6 +- .../java/com/img/rabbit/utils/UniAppUtils.kt | 75 ++-- .../java/com/img/rabbit/utils/UpdateUtils.kt | 24 ++ .../img/rabbit/viewmodel/LoginViewModel.kt | 2 +- .../img/rabbit/viewmodel/ReportViewModel.kt | 20 + .../rabbit/viewmodel/interface/ServiceVo.kt | 4 + gradle/libs.versions.toml | 5 +- 16 files changed, 588 insertions(+), 61 deletions(-) create mode 100644 app/src/main/java/com/img/rabbit/bean/request/ReportRequest.kt create mode 100644 app/src/main/java/com/img/rabbit/viewmodel/ReportViewModel.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index f4f6e2b..be58c69 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -110,12 +110,14 @@ android { buildTypes { getByName("debug") { isMinifyEnabled = false + isShrinkResources = false signingConfig = signingConfigs.getByName("config") + proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro") } getByName("release") { // 建议开启混淆以减少启动耗时和体积 - isMinifyEnabled = false - isShrinkResources = false + isMinifyEnabled = true + isShrinkResources = true signingConfig = signingConfigs.getByName("config") proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro") } @@ -326,6 +328,7 @@ dependencies { implementation(libs.android.cn.oaid) //获取手机设备id implementation(libs.fastaes) //解密 implementation(libs.accompanist.permissions) +// implementation(libs.zip4j) //Uni小程序相关依赖 implementation (files("libs/sqlite-release.aar")) //sqlite数据库 diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index b6e52b4..d003fdb 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -20,6 +20,386 @@ # hide the original source file name. #-renamesourcefileattribute SourceFile +-dontwarn +-optimizationpasses 5 +-dontusemixedcaseclassnames +-dontskipnonpubliclibraryclasses +-dontskipnonpubliclibraryclassmembers +-dontpreverify +-verbose + +#-optimizations !code/simplification/arithmetic,!field/*,!class/merging/* +-dontoptimize + +-keep public class * extends android.app.Activity +-keep public class * extends android.app.Application +-keep public class * extends android.app.Service +-keep public class * extends android.content.BroadcastReceiver +-keep public class * extends android.content.ContentProvider +-keep public class * extends android.app.backup.BackupAgentHelper +-keep public class * extends android.preference.Preference +-keep public class * extends io.dcloud.common.DHInterface.IPlugin +-keep public class * extends io.dcloud.common.DHInterface.IFeature +-keep public class * extends io.dcloud.common.DHInterface.IBoot +-keep public class * extends io.dcloud.common.DHInterface.IReflectAble + +-keep class io.dcloud.** {*;} +-dontwarn io.dcloud.** + + +-keep class vi.com.gdi.** {*;} +-keep class android.support.v4.** {*;} + +-keepclasseswithmembers class io.dcloud.appstream.StreamAppManager { + public protected ; +} + +-keep public class * extends io.dcloud.common.DHInterface.IReflectAble{ + public protected ; + public protected *; +} +-keep class **.R +-keep class **.R$* { + public static ; +} +-keep public class * extends io.dcloud.common.DHInterface.IJsInterface{ + public protected ; + public protected *; +} + +-keepclasseswithmembers class io.dcloud.EntryProxy { + ; +} + +-keep class * implements android.os.IInterface { + ; +} + +-keepclasseswithmembers class *{ + public static java.lang.String getJsContent(); +} + +-keepclasseswithmembers class *{ + public static io.dcloud.share.AbsWebviewClient getWebviewClient(io.dcloud.share.ShareAuthorizeView); +} + +-keepattributes Exceptions,InnerClasses,Signature,Deprecated, SourceFile,LineNumberTable,*Annotation*,EnclosingMethod + +-keepclasseswithmembers class * { + public (android.content.Context, android.util.AttributeSet); +} + +-keepclasseswithmembers class * { + public (android.content.Context, android.util.AttributeSet, int); +} + +-keep public class * extends android.app.Application{ + public static ; + public *; +} + +-keepclassmembers class * extends android.app.Activity { + public void *(android.view.View); + public static ; +} + +-keepclassmembers enum * { + public static **[] values(); + public static ** valueOf(java.lang.String); +} + +-keep class * implements android.os.Parcelable { + public static final android.os.Parcelable$Creator *; +} + +-keep class dc.** {*;} +-keep class okio.**{*;} +-keep class org.apache.** {*;} +-keep class org.json.** {*;} +-keep class net.ossrs.** {*;} +-keep class android.** {*;} +-keep class com.facebook.**{*;} +-keep class com.bumptech.glide.**{*;} +-keep class com.alibaba.fastjson.**{*;} +-keep class com.sina.**{*;} +-keep class com.weibo.ssosdk.**{*;} +-keep class com.asus.**{*;} +-keep class com.bun.**{*;} +-keep class com.heytap.**{*;} +-keep class com.huawei.**{*;} +-keep class com.netease.**{*;} +-keep class com.meizu.**{*;} +-keep class com.samsung.**{*;} +-keep class com.zui.**{*;} +-keep class com.amap.**{*;} +-keep class com.autonavi.**{*;} +-keep class pl.droidsonroids.gif.**{*;} +-keep class com.tencent.**{*;} +-keep class com.baidu.**{*;} +-keep class com.iflytek.**{*;} +-keep class com.umeng.**{*;} +-keep class tv.**{*;} +-keep class master.**{*;} +-keep class uk.co.**{*;} +-keep class com.dmcbig.**{*;} +-keep class org.mozilla.**{*;} +-keep class androidtranscoder.**{*;} +-keep class XI.**{*;} + + +-dontwarn android.** +-dontwarn com.tencent.** + +-keep class * implements com.taobao.weex.IWXObject{*;} +-keep public class * extends com.taobao.weex.common.WXModule{*;} + + +-keepattributes Signature + +-dontwarn org.codehaus.mojo.** +-dontwarn org.apache.commons.** +-dontwarn com.amap.** +-dontwarn com.sina.weibo.sdk.** +-dontwarn com.alipay.** +-dontwarn com.lucan.ajtools.** +-dontwarn pl.droidsonroids.gif.** + +-keep class com.taobao.weex.** { *; } +-keep class com.taobao.gcanvas.**{*;} +-dontwarn com.taobao.weex.** +-dontwarn com.taobao.gcanvas.** + +#个推 +-dontwarn com.igexin.** +-keep class com.igexin.** { *; } +-keep class org.json.** { *; } +-dontwarn com.getui.** +-keep class com.getui.** { *; } + +-keep class android.support.v4.app.NotificationCompat { *; } +-keep class android.support.v4.app.NotificationCompat$Builder { *; } +#魅族 +-keep class com.meizu.** { *; } +-dontwarn com.meizu.** +#小米 +-keep class com.xiaomi.** { *; } +-dontwarn com.xiaomi.push.** +-keep class org.apache.thrift.** { *; } +#华为 +-dontwarn com.huawei.hms.** +-keep class com.huawei.hms.** { *; } + +-keep class com.huawei.android.** { *; } +-dontwarn com.huawei.android.** + +-keep class com.hianalytics.android.** { *; } +-dontwarn com.hianalytics.android.** + +-keep class com.huawei.updatesdk.** { *; } +-dontwarn com.huawei.updatesdk.** +#OPPO +-keep class com.coloros.mcssdk.** { *; } +-dontwarn com.coloros.mcssdk.** + +#360聚合广告核心包 +-keep class com.ak.** {*;} +-dontwarn com.ak.** +-keep class android.support.v4.** { +public *; +} + +#广点通SDK +-keep class com.qq.e.** { +public protected *; +} +-keep class android.support.v7.**{ +public *; +} + +#穿山甲SDK +-keep class com.bytedance.sdk.openadsdk.** { *; } +-dontwarn com.bytedance.sdk.openadsdk.** +-keep class com.androidquery.callback.** {*;} +-keep public interface com.bytedance.sdk.openadsdk.downloadnew.** {*;} +-keep class com.ss.sys.ces.* {*;} + +#快手 +-keep class org.chromium.** {*;} +-keep class org.chromium.** {*;} +-keep class aegon.chrome.** {*;} +-keep class com.kwai.**{*;} +-keep class com.kwad.**{*;} +-keepclasseswithmembernames class * { + native ; +} +-dontwarn com.kwai.** +-dontwarn com.kwad.** +-dontwarn com.ksad.** +-dontwarn aegon.chrome.** + +#一键登录 +-dontwarn com.g.gysdk.** +-keep class com.g.gysdk.**{*;} +-dontwarn com.g.elogin.** +-keep class com.g.elogin.**{*;} +-dontwarn com.cmic.sso.sdk.** +-keep class com.cmic.sso.sdk.** {*;} +-dontwarn com.geetest.onelogin.** +-keep class com.geetest.onelogin.** {*;} +-dontwarn com.geetest.onepassv2.** +-keep class com.geetest.onepassv2.** {*;} +-dontwarn com.unicom.xiaowo.login.** +-keep class com.unicom.xiaowo.login.** {*;} +-dontwarn cn.com.chinatelecom.account.api.** +-keep class cn.com.chinatelecom.account.api.** {*;} + + + +#腾讯X5--------------start----------------------- +-dontwarn dalvik.** +-dontwarn com.tencent.smtt.** +#-overloadaggressively +# ------------------ Keep LineNumbers and properties ---------------- # +-keepattributes Exceptions,InnerClasses,Signature,Deprecated,SourceFile,LineNumberTable,*Annotation*,EnclosingMethod +# -------------------------------------------------------------------------- +# Addidional for x5.sdk classes for apps +-keep class com.tencent.smtt.export.external.**{*;} +-keep class com.tencent.tbs.video.interfaces.IUserStateChangedListener {*;} +-keep class com.tencent.smtt.sdk.CacheManager {public *;} +-keep class com.tencent.smtt.sdk.CookieManager {public *;} +-keep class com.tencent.smtt.sdk.WebHistoryItem {public *;} +-keep class com.tencent.smtt.sdk.WebViewDatabase {public *;} +-keep class com.tencent.smtt.sdk.WebBackForwardList {public *;} +-keep public class com.tencent.smtt.sdk.WebView {public ;public ;} +-keep public class com.tencent.smtt.sdk.WebView$HitTestResult {public static final ;public java.lang.String getExtra();public int getType();} +-keep public class com.tencent.smtt.sdk.WebView$WebViewTransport {public ;} +-keep public class com.tencent.smtt.sdk.WebView$PictureListener {public ;public ;} +-keepattributes InnerClasses +-keep public enum com.tencent.smtt.sdk.WebSettings$** {*;} +-keep public enum com.tencent.smtt.sdk.QbSdk$** {*;} +-keep public class com.tencent.smtt.sdk.WebSettings {public *;} + +-keepattributes Signature +-keep public class com.tencent.smtt.sdk.ValueCallback {public ;public ;} +-keep public class com.tencent.smtt.sdk.WebViewClient {public ;public ;} +-keep public class com.tencent.smtt.sdk.DownloadListener {public ;public ;} +-keep public class com.tencent.smtt.sdk.WebChromeClient {public ;public ;} +-keep public class com.tencent.smtt.sdk.WebChromeClient$FileChooserParams {public ;public ;} +-keep class com.tencent.smtt.sdk.SystemWebChromeClient{public *;} +# 1. extension interfaces should be apparent +-keep public class com.tencent.smtt.export.external.extension.interfaces.* {public protected *;} + +# 2. interfaces should be apparent +-keep public class com.tencent.smtt.export.external.interfaces.* {public protected *;} +-keep public class com.tencent.smtt.sdk.WebViewCallbackClient {public protected *;} +-keep public class com.tencent.smtt.sdk.WebStorage$QuotaUpdater {public ;public ;} +-keep public class com.tencent.smtt.sdk.WebIconDatabase {public ;public ;} +-keep public class com.tencent.smtt.sdk.WebStorage {public ;public ;} +-keep public class com.tencent.smtt.sdk.DownloadListener {public ;public ;} +-keep public class com.tencent.smtt.sdk.QbSdk {public ;public ;} +-keep public class com.tencent.smtt.sdk.QbSdk$PreInitCallback {public ;public ;} +-keep public class com.tencent.smtt.sdk.CookieSyncManager {public ;public ;} +-keep public class com.tencent.smtt.sdk.Tbs* {public ;public ;} +-keep public class com.tencent.smtt.utils.LogFileUtils {public ;public ;} +-keep public class com.tencent.smtt.utils.TbsLog {public ;public ;} +-keep public class com.tencent.smtt.utils.TbsLogClient {public ;public ;} +-keep public class com.tencent.smtt.sdk.CookieSyncManager {public ;public ;} +# Added for game demos +-keep public class com.tencent.smtt.sdk.TBSGamePlayer {public ;public ;} +-keep public class com.tencent.smtt.sdk.TBSGamePlayerClient* {public ;public ;} +-keep public class com.tencent.smtt.sdk.TBSGamePlayerClientExtension {public ;public ;} +-keep public class com.tencent.smtt.sdk.TBSGamePlayerService* {public ;public ;} +-keep public class com.tencent.smtt.utils.Apn {public ;public ;} +-keep class com.tencent.smtt.** {*;} +# end +-keep public class com.tencent.smtt.export.external.extension.proxy.ProxyWebViewClientExtension {public ;public ;} +-keep class MTT.ThirdAppInfoNew {*;} +-keep class com.tencent.mtt.MttTraceEvent {*;} +# Game related +-keep public class com.tencent.smtt.gamesdk.* {public protected *;} +-keep public class com.tencent.smtt.sdk.TBSGameBooter {public ;public ;} +-keep public class com.tencent.smtt.sdk.TBSGameBaseActivity {public protected *;} +-keep public class com.tencent.smtt.sdk.TBSGameBaseActivityProxy {public protected *;} +-keep public class com.tencent.smtt.gamesdk.internal.TBSGameServiceClient {public *;} +#腾讯X5--------------end----------------------- + +# 代码混淆压缩比,在 0~7 之间,默认为 5,一般不做修改 +-optimizationpasses 5 +# 混合时不使用大小写混合,混合后的类名为小写 +-dontusemixedcaseclassnames +# 指定不去忽略非公共库的类 +-dontskipnonpubliclibraryclasses +# 这句话能够使我们在查看崩溃报告时能对应到明文的代码 +-keepattributes SourceFile,LineNumberTable +# 保持泛型 +-keepattributes Signature +# 保持注解 +-keepattributes *Annotation* + +# 【关键】正式环境移除日志打印 (需配合 build.gradle 中 isMinifyEnabled true 使用) +-assumenosideeffects class android.util.Log { + public static int v(...); + public static int d(...); + public static int i(...); + public static int w(...); + public static int e(...); +} + +# --- Retrofit & OkHttp --- +-keepattributes Signature, InnerClasses +-keep class retrofit2.** { *; } +-keep class okhttp3.** { *; } +-dontwarn retrofit2.** +-dontwarn okhttp3.** +-keep class com.squareup.okhttp3.** { *; } +-dontwarn com.squareup.okhttp3.** +-dontwarn okio.** + +# --- Gson (必须保持用于解析的 Bean 类不被混淆) --- +-keep class com.google.gson.** { *; } +# 假设你的数据模型包名是 com.img.rabbit.model,请务必根据实际修改: +-keep class com.img.rabbit.model.** { *; } + +# --- Glide & Coil --- +-keep public class * implements com.bumptech.glide.module.GlideModule +-keep class com.bumptech.glide.** { *; } +-keep class io.coilkt.** { *; } + +# --- MMKV --- +-keep class com.tencent.mmkv.** { *; } + +# --- 友盟 (Umeng) --- +-keep class com.umeng.** { *; } +-keep class com.uc.** { *; } +-dontwarn com.umeng.** +-dontwarn com.uc.** + +# --- 个推 (Getui) --- +-keep class com.getui.** { *; } +-dontwarn com.getui.** + +# --- 微信 SDK --- +-keep class com.tencent.mm.opensdk.** { *; } +-keep class com.tencent.wxop.** { *; } +-keep class com.tencent.mm.sdk.** { *; } + +# --- MLKit (人脸检测/分割) --- +-keep class com.google.mlkit.** { *; } +-keep class com.google.android.gms.** { *; } + +# --- Uni小程序 & Fresco & FastJson --- +-keep class com.alibaba.fastjson.** { *; } +-keep class com.facebook.fresco.** { *; } +-keep class com.facebook.imagepipeline.** { *; } +-keep class com.facebook.animated.gif.** { *; } +-keep class pl.droidsonroids.gif.** { *; } +# Uni小程序特定类保持 +-keep class io.dcloud.** { *; } + +# --- Android_CN_OAID --- +-keep class com.github.gzu_liyujiang.oaid.** { *; } + + # 友盟号码认证 -keep class com.umeng.**{*;} @@ -32,3 +412,6 @@ public static ** valueOf(java.lang.String); } # 友盟号码认证 结束 + +-keep class com.img.rabbit.** { *; } +-keep class com.img.rabbit.data.bean.** { *; } diff --git a/app/src/main/java/com/img/rabbit/BaseApplication.kt b/app/src/main/java/com/img/rabbit/BaseApplication.kt index a5656a5..d3bcfd1 100644 --- a/app/src/main/java/com/img/rabbit/BaseApplication.kt +++ b/app/src/main/java/com/img/rabbit/BaseApplication.kt @@ -50,7 +50,7 @@ class BaseApplication : Application() { } override fun attachBaseContext(base: android.content.Context?) { -// MultiDex.install(base) + //MultiDex.install(base) super.attachBaseContext(base) } diff --git a/app/src/main/java/com/img/rabbit/MainActivity.kt b/app/src/main/java/com/img/rabbit/MainActivity.kt index 509a547..a655404 100644 --- a/app/src/main/java/com/img/rabbit/MainActivity.kt +++ b/app/src/main/java/com/img/rabbit/MainActivity.kt @@ -81,6 +81,7 @@ import com.img.rabbit.utils.UpdateUtils import com.img.rabbit.utils.UrlLinkUtils.openAgreement import com.img.rabbit.viewmodel.GeneralViewModel import com.img.rabbit.viewmodel.LoginViewModel +import com.img.rabbit.viewmodel.ReportViewModel import com.img.rabbit.viewmodel.SplashViewModel import com.umeng.analytics.MobclickAgent import com.umeng.commonsdk.UMConfigure @@ -108,6 +109,7 @@ class MainActivity : ComponentActivity(), LoadingCallback { val context = LocalContext.current val loginViewModel: LoginViewModel = viewModel() val splashViewModel: SplashViewModel = viewModel() + val reportViewModel:ReportViewModel = viewModel() generalViewModel = ViewModelProvider(this, ViewModelProvider.AndroidViewModelFactory.getInstance(application))[GeneralViewModel::class.java] var updateAppNotify by mutableStateOf(GlobalStateManager(context).globalUpdateNotifyFlow().collectAsState(initial = false)) @@ -230,29 +232,36 @@ class MainActivity : ComponentActivity(), LoadingCallback { UniMpUpdate.DOWNLOAD_START -> { //资源开始下载 progressWGTToPageState.floatValue = 0f - Log.i("HomeScreen","DOWNLOAD_START") + Log.i("HomeScreen", "DOWNLOAD_START") } + UniMpUpdate.DOWNLOAD_FINISH -> { //资源下载完成 progressWGTToPageState.floatValue = 1f - Log.i("HomeScreen","DOWNLOAD_FINISH") + Log.i("HomeScreen", "DOWNLOAD_FINISH") coroutineScope.launch { - GlobalStateManager(context).storeGlobalUniDownloadNotify(false) + GlobalStateManager(context).storeGlobalUniDownloadNotify( + false + ) } } + UniMpUpdate.DOWNLOAD_FAIL -> { //资源下载失败 progressWGTToPageState.floatValue = -1f - Log.i("HomeScreen","DOWNLOAD_FAIL") + Log.i("HomeScreen", "DOWNLOAD_FAIL") coroutineScope.launch { - GlobalStateManager(context).storeGlobalUniDownloadNotify(false) + GlobalStateManager(context).storeGlobalUniDownloadNotify( + false + ) } } + else -> { //资源下载进度 - if(progress != null){ + if (progress != null) { progressWGTToPageState.floatValue = progress - Log.i("HomeScreen","DOWNLOAD_PROGRESS:$progress") + Log.i("HomeScreen", "DOWNLOAD_PROGRESS:$progress") } } @@ -261,10 +270,17 @@ class MainActivity : ComponentActivity(), LoadingCallback { onRelease = { //资源下载完成后,启动小程序到指定位置 val uniMpEntity = UniAppUtils.currentDownloadUniMp - if(uniMpEntity!=null){ - UniAppUtils.startUniMpPage(context = context, uniMpId = uniMpEntity.unimp_id, uniMpType = uniMpEntity.unimp_type, pagePath = UniAppUtils.currentUniMpJumpPatch?:"") + if (uniMpEntity != null) { + UniAppUtils.startUniMpPage( + context = context, + uniMpId = uniMpEntity.unimp_id, + uniMpType = uniMpEntity.unimp_type, + pagePath = UniAppUtils.currentUniMpJumpPatch ?: "", + reportViewModel = reportViewModel + ) } - } + }, + reportViewModel = reportViewModel ) TipsUniMpToPageDialog( title = "下载资源", diff --git a/app/src/main/java/com/img/rabbit/bean/request/ReportRequest.kt b/app/src/main/java/com/img/rabbit/bean/request/ReportRequest.kt new file mode 100644 index 0000000..565a2a8 --- /dev/null +++ b/app/src/main/java/com/img/rabbit/bean/request/ReportRequest.kt @@ -0,0 +1,22 @@ +package com.img.rabbit.bean.request + +import kotlinx.serialization.Serializable + +@Serializable +data class ReportRequest( + private val source: String = "android", + private val type: String,//事件类型:click error + private val key: String, + private val value: String, + private val extra: String? = null +) + + +object ReportType { + const val CLICK = "click" + const val ERROR = "error" +} + +object ReportKey { + const val EVENT_CLIENT_UNI_RELEASE_WGT: String = "client.uni.release.wgt" //释放资源 +} diff --git a/app/src/main/java/com/img/rabbit/bean/response/ConfigEntity.kt b/app/src/main/java/com/img/rabbit/bean/response/ConfigEntity.kt index 0f39159..d679db6 100644 --- a/app/src/main/java/com/img/rabbit/bean/response/ConfigEntity.kt +++ b/app/src/main/java/com/img/rabbit/bean/response/ConfigEntity.kt @@ -7,12 +7,12 @@ import kotlinx.serialization.Serializable class ConfigEntity { @SerializedName("client.version.upgrade") //版本更新 var versionEntity: VersionEntity? = null - @SerializedName("client.uni.version.upgrade") //小程序模拟器 var uniVersionEntity: List? = emptyList() - @SerializedName("client.icon.uni.home") //uni首页icon var homeIconEntity: List? = emptyList() + @SerializedName("client.wgt.password") //WGT解压密码 + var wgtPassword: String? = null @SerializedName("client.popup.display") //显示开关控制 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 900c58d..abb45eb 100644 --- a/app/src/main/java/com/img/rabbit/pages/LoginPage.kt +++ b/app/src/main/java/com/img/rabbit/pages/LoginPage.kt @@ -9,7 +9,6 @@ import android.util.Log import android.view.LayoutInflater import android.widget.CheckBox import android.widget.TextView -import android.widget.Toast import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.border @@ -38,7 +37,6 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue -import androidx.compose.runtime.livedata.observeAsState import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember @@ -88,6 +86,7 @@ import org.json.JSONObject @SuppressLint("UnrememberedMutableState") @Composable fun LoginScreen(navController: NavHostController? = null, generalViewModel: GeneralViewModel, loginViewModel: LoginViewModel, isVisibilityBreak: Boolean) { + val TAG = "Rabbit_LoginScreen" val context = LocalContext.current //关于登录的事件监听 @@ -116,11 +115,19 @@ fun LoginScreen(navController: NavHostController? = null, generalViewModel: Gene } loginViewModel.loginResult.value = null //清理loginState }else if(loginViewModel.loginResult.value != null && loginViewModel.loginResult.value?.data?.token == null){ - Log.w("LoginScreen","登录失败,无有效的Token") + Log.w(TAG,"登录失败,无有效的Token") CenterToast.show("登录失败,请重新登录") } } + LaunchedEffect(loginViewModel.errorState.value) { + if(loginViewModel.errorState.value != null){ + Log.w(TAG,loginViewModel.errorState.value?.message?:"登录失败") + CenterToast.show("登录失败") + } + loginViewModel.errorState.value = null + } + Scaffold{ Box( modifier = Modifier.fillMaxSize().navigationBarsPadding() @@ -413,7 +420,6 @@ private fun CaptchaLoginScreen(context: Context, viewModel: LoginViewModel) { .clickable(enabled = !isCaptchaCountdown) { // 点击获取验证码 if (validatePhoneEmpty( - context = context, viewModel = viewModel, showToast = true ) @@ -468,7 +474,6 @@ private fun CaptchaLoginScreen(context: Context, viewModel: LoginViewModel) { ) { // 点击登录 if (validateCaptchaLoginEmpty( - context = context, viewModel = viewModel, showToast = true ) @@ -588,7 +593,7 @@ private fun CaptchaLoginScreen(context: Context, viewModel: LoginViewModel) { @SuppressLint("UseKtx", "InflateParams", "SetTextI18n") @Composable private fun OneKeyLoginScreen(context: Context, viewModel: LoginViewModel) { - val TAG = "Rabbit_LoginPage_OneKeyLoginScreen" + val TAG = "Rabbit_LoginScreen_OneKeyLoginScreen" val preLoginResult = GYManager.getInstance().preLoginResult val phoneNumber = viewModel.oneKeyPreLogin?.number ?: "" @@ -1144,7 +1149,7 @@ private fun OtherLoginBar(viewModel: LoginViewModel) { /** * 验证手机号是否为空 */ -private fun validatePhoneEmpty(context: Context, viewModel: LoginViewModel, showToast: Boolean = false): Boolean { +private fun validatePhoneEmpty(viewModel: LoginViewModel, showToast: Boolean = false): Boolean { if (showToast && viewModel.userName.value.isEmpty()) { CenterToast.show("请输入手机号") } @@ -1154,7 +1159,7 @@ private fun validatePhoneEmpty(context: Context, viewModel: LoginViewModel, show /** * 验证验证码登录是否为空 */ -private fun validateCaptchaLoginEmpty(context: Context, viewModel: LoginViewModel, showToast: Boolean = false): Boolean { +private fun validateCaptchaLoginEmpty(viewModel: LoginViewModel, showToast: Boolean = false): Boolean { if (showToast) { if(viewModel.userName.value.isEmpty()){ CenterToast.show("请输入手机号") 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 6d68182..8758740 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 @@ -62,6 +62,7 @@ import com.img.rabbit.route.ScreenRoute import com.img.rabbit.utils.UniAppUtils import com.img.rabbit.utils.UniMpUpdate import com.img.rabbit.viewmodel.GeneralViewModel +import com.img.rabbit.viewmodel.ReportViewModel import io.dcloud.feature.sdk.DCUniMPSDK import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch @@ -79,13 +80,14 @@ fun HomeScreen( val scope: CoroutineScope = rememberCoroutineScope() val progressPair = mutableStateMapOf() + val reportViewModel = viewModel() + // 获取当前路由状态 val navBackStackEntry by navController.currentBackStackEntryAsState() val currentRoute = navBackStackEntry?.destination?.route // 只有当当前路由处于首页 Tab 之一时,才激活 BackHandler var lastClickTime by remember { mutableLongStateOf(0L) } - val updateUserConfigNotify by GlobalStateManager(context).globalUserConfigNotifyFlow().collectAsState(initial = false) BackHandler(enabled = (currentRoute == ScreenRoute.Home.route)) { @@ -259,7 +261,7 @@ fun HomeScreen( } else { loadingCallback?.showLoading() //启动uni小程序(1、直接启动;2、释放并启动) - UniAppUtils.distributeUniMp(context, uniMp) { + UniAppUtils.distributeUniMp(context, uniMp, reportViewModel) { loadingCallback?.hideLoading() } } @@ -389,7 +391,7 @@ fun HomeScreen( } else { loadingCallback?.showLoading() //启动uni小程序(1、直接启动;2、释放并启动) - UniAppUtils.distributeUniMp(context, uniMp) { + UniAppUtils.distributeUniMp(context, uniMp, reportViewModel) { loadingCallback?.hideLoading() } } @@ -484,7 +486,7 @@ fun HomeScreen( GlobalStateManager(context).storeGlobalUniDownloadNotify(true) } }else { - UniAppUtils.startUniMpPage(context = context, uniMpId = uniMpId, uniMpType = item.type, pagePath = item.url) + UniAppUtils.startUniMpPage(context = context, uniMpId = uniMpId, uniMpType = item.type, pagePath = item.url, reportViewModel = reportViewModel) } } ) { 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 0989673..079cc55 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 @@ -44,6 +44,8 @@ import androidx.lifecycle.viewmodel.compose.viewModel import androidx.navigation.NavHostController import androidx.navigation.compose.rememberNavController 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 @@ -57,6 +59,7 @@ import com.img.rabbit.viewmodel.LoginViewModel fun SettingScreen(navController: NavHostController, loginViewModel: LoginViewModel) { val context = LocalContext.current var cacheDataSize by remember { mutableStateOf("正在计算...") } + var showConfirmClearCache by remember { mutableStateOf(false) } LaunchedEffect(Unit) { AppDataStoreUtils.getAppStorageStats(context){ _, _, _, totalDataCacheSize -> @@ -98,9 +101,7 @@ fun SettingScreen(navController: NavHostController, loginViewModel: LoginViewMod indication = null, interactionSource = remember { MutableInteractionSource() } ) { - // 跳转页面 - //navController.navigate("") - AppDataStoreUtils.openAppSettings(context) + showConfirmClearCache = true }, verticalAlignment = Alignment.CenterVertically ) { @@ -364,7 +365,7 @@ fun SettingScreen(navController: NavHostController, loginViewModel: LoginViewMod interactionSource = remember { MutableInteractionSource() } ) { // 退出登录 - loginViewModel.requestLogout(context) + loginViewModel.requestLogout() } ) { Text( @@ -383,6 +384,25 @@ fun SettingScreen(navController: NavHostController, loginViewModel: LoginViewMod } } } + + + if(showConfirmClearCache) { + TipsDialog( + title = "清除缓存", + content1 = "清除缓存后可能会丢失聊天数据", + content2 = "", + cancel = "取消", + confirm = "确定", + data = null, + onStatusChange = { status, isCancel, _ -> + if (!isCancel) { + // 跳转应用设置页面(清除缓存) + AppDataStoreUtils.openAppSettings(context) + } + showConfirmClearCache = status + } + ) + } } } diff --git a/app/src/main/java/com/img/rabbit/pages/screen/mine/setting/DeleteAccountScreen.kt b/app/src/main/java/com/img/rabbit/pages/screen/mine/setting/DeleteAccountScreen.kt index 9274ead..d0cf053 100644 --- a/app/src/main/java/com/img/rabbit/pages/screen/mine/setting/DeleteAccountScreen.kt +++ b/app/src/main/java/com/img/rabbit/pages/screen/mine/setting/DeleteAccountScreen.kt @@ -91,7 +91,7 @@ fun DeleteAccountScreen(navController: NavHostController,viewModel: DeleteAccoun painter = painterResource(id = R.mipmap.ic_warning), contentDescription = null, contentScale = ContentScale.FillWidth, - modifier = Modifier.size(86.dp).align(Alignment.CenterHorizontally) + modifier = Modifier.size(60.dp).align(Alignment.CenterHorizontally) ) Text( @@ -279,7 +279,7 @@ fun DeleteAccountScreen(navController: NavHostController,viewModel: DeleteAccoun .padding(start = 16.dp, end = 16.dp, top = 16.dp) ) { Text( - text = "4.账号注销后账号不可登录,不可恢复", + text = "4.账号注销后原账号不可登录,不可恢复", fontSize = 15.sp, fontWeight = FontWeight.Bold, modifier = Modifier @@ -317,7 +317,7 @@ fun DeleteAccountScreen(navController: NavHostController,viewModel: DeleteAccoun ) } Text( - text = "同意请打勾", + text = "再次登录后会生成新账号,原账号被删除,同意请打勾", fontSize = 13.sp, fontWeight = FontWeight.Normal, modifier = Modifier 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 f7f36ad..2c3c3dc 100644 --- a/app/src/main/java/com/img/rabbit/utils/UniAppUtils.kt +++ b/app/src/main/java/com/img/rabbit/utils/UniAppUtils.kt @@ -2,8 +2,12 @@ package com.img.rabbit.utils import android.content.Context import android.util.Log +import android.webkit.MimeTypeMap import com.github.gzuliyujiang.oaid.DeviceIdentifier import com.img.rabbit.BuildConfig +import com.img.rabbit.bean.request.ReportKey +import com.img.rabbit.bean.request.ReportRequest +import com.img.rabbit.bean.request.ReportType import com.img.rabbit.bean.response.UniVersionEntity import com.img.rabbit.components.CenterToast import com.img.rabbit.config.Constants @@ -13,6 +17,7 @@ import com.img.rabbit.provider.utils.HeadParamUtils.applicationContext import com.img.rabbit.provider.utils.HeadParamUtils.getAppVersionName import com.img.rabbit.uni.UniMPAlipaySplashView import com.img.rabbit.uni.UniMPWxSplashView +import com.img.rabbit.viewmodel.ReportViewModel import com.tencent.mm.opensdk.modelbiz.WXLaunchMiniProgram import com.tencent.mm.opensdk.openapi.IWXAPI import io.dcloud.feature.sdk.DCUniMPSDK @@ -55,7 +60,10 @@ object UniAppUtils { //仅当跳转指定小程序时,才需要跳转指定位置 var currentUniMpJumpPatch: String? = null - + private fun getWgtName(uniMpId: String): String{ + return String.format("%s.wgt", uniMpId) + //return String.format("%s.zip", uniMpId) + } /** *获取当前前台运行的UniMp小程序实体 */ @@ -81,13 +89,13 @@ object UniAppUtils { * 是否需要下载(强制更新或者不存在wgt文件) */ fun isDownloadUniMp(uniVersion: UniVersionEntity): Boolean{ - val wgtName = String.format("%s.wgt", uniVersion.unimp_id) + val wgtName = getWgtName(uniVersion.unimp_id) val wgtFile = File(FileUtils.getInstance().cacheUniAppDir.absolutePath, wgtName) return isUpdateForce(uniVersion) || !(FileUtils.getInstance().fileIsExists(wgtFile) && FileUtils.getFileSize(wgtFile) > 0) } fun wgtIsExists(uniMpId: String): Boolean{ - val wgtName = String.format("%s.wgt", uniMpId) + val wgtName = getWgtName(uniMpId) val wgtFile = File(FileUtils.getInstance().cacheUniAppDir.absolutePath, wgtName) //判断wgt是否下载 return FileUtils.getInstance().fileIsExists(wgtFile) && FileUtils.getFileSize(wgtFile) > 0 @@ -127,14 +135,14 @@ object UniAppUtils { /** * 分发uniMP(下载、更新与启动) */ - fun distributeUniMp(context: Context, uniVersion: UniVersionEntity, onResult:(loading: Boolean) -> Unit){ + fun distributeUniMp(context: Context, uniVersion: UniVersionEntity,reportViewModel: ReportViewModel, onResult:(loading: Boolean) -> Unit){ val isExists = DCUniMPSDK.getInstance().isExistsApp(uniVersion.unimp_id) if(isExists){ //资源已释放,直接启动 startUniMp(context, uniVersion, onResult) }else{ //资源未释放,先释放后启动 - releaseWgt(uniVersion){ isSuccess, versionEntity -> + releaseWgt(uniVersion,reportViewModel){ isSuccess, versionEntity -> if(isSuccess){ startUniMp(context, versionEntity, onResult) }else{ @@ -165,9 +173,9 @@ object UniAppUtils { /** * 启动小程序并直达指定页面 */ - fun startUniMpPage(context: Context, uniMpId: String, uniMpType: String, pagePath: String){ + fun startUniMpPage(context: Context, uniMpId: String, uniMpType: String, pagePath: String, reportViewModel: ReportViewModel){ if(isRelease(uniMpId)){ - releaseWgt(uniMpId){ + releaseWgt(uniMpId,reportViewModel){ // 启动直达页面 startUniMpToPage(context, uniMpId, uniMpType, pagePath) @@ -196,8 +204,8 @@ object UniAppUtils { updateUniMp(uniMpId, DCUniMPSDK.getInstance().openUniMP(context, uniMpId, configuration)) } - private fun releaseWgt(versionEntity: UniVersionEntity, onReleaseWgt: (isSuccess: Boolean, versionEntity: UniVersionEntity) -> Unit) { - releaseWgt(versionEntity.unimp_id){ isSuccess -> + private fun releaseWgt(versionEntity: UniVersionEntity, reportViewModel: ReportViewModel, onReleaseWgt: (isSuccess: Boolean, versionEntity: UniVersionEntity) -> Unit) { + releaseWgt(versionEntity.unimp_id,reportViewModel){ isSuccess -> if(isSuccess){ onReleaseWgt(true, versionEntity) }else{ @@ -207,15 +215,15 @@ object UniAppUtils { } //释放资源 - private fun releaseWgt(uniMpId: String, onReleaseWgt: (isSuccess: Boolean) -> Unit) { + private fun releaseWgt(uniMpId: String, reportViewModel: ReportViewModel, onReleaseWgt: (isSuccess: Boolean) -> Unit) { val appBasePath = DCUniMPSDK.getInstance().getAppBasePath(applicationContext) val deleteSuccess = File(appBasePath, uniMpId).deleteRecursively() if(deleteSuccess){ - val wgtName = String.format("%s.wgt", uniMpId) + val wgtName = getWgtName(uniMpId) val wgtFile = File(FileUtils.getInstance().cacheUniAppDir.absolutePath, wgtName) val uniMPReleaseConfiguration = UniMPReleaseConfiguration().apply { wgtPath = wgtFile.path - password = "6462"////没有密码可以不写 + password = PreferenceUtil.getUserConfig()?.config?.wgtPassword//"6462"////没有密码可以不写 } DCUniMPSDK.getInstance().releaseWgtToRunPath(uniMpId, uniMPReleaseConfiguration) { code, _ -> if (code == 1) { @@ -223,12 +231,22 @@ object UniAppUtils { onReleaseWgt(true) } else { //释放wgt失败 - CenterToast.show("小程序加载失败,请清除缓存后重试!") + CenterToast.show("加载失败,请重试或联系客服!") onReleaseWgt(false) + File(appBasePath, uniMpId).deleteRecursively() + //事件提交 + reportViewModel.requestReport( + ReportRequest( + ReportType.ERROR, + ReportKey.EVENT_CLIENT_UNI_RELEASE_WGT, + uniMpId, + "释放资源失败" + ) + ) } } }else{ - CenterToast.show("资源释放失败,请手动删除小程序运行文件!") + CenterToast.show("加载失败,请重试或联系客服!") } } @@ -236,17 +254,16 @@ object UniAppUtils { /** * 下载wgt文件 */ - fun downloadWGT(context: Context,scope: CoroutineScope, uniVersion: UniVersionEntity, onProgress:(state: UniMpUpdate, filePath: String?, progress: Float?) -> Unit) { - val uniMpID = uniVersion.unimp_id - val wgtName = String.format("%s.wgt", uniMpID) + fun downloadWGT(context: Context,scope: CoroutineScope, uniVersion: UniVersionEntity, reportViewModel: ReportViewModel = ReportViewModel(), onProgress:(state: UniMpUpdate, filePath: String?, progress: Float?) -> Unit) { + val uniMpId = uniVersion.unimp_id + val wgtName = getWgtName(uniMpId) val wgtFile = File(FileUtils.getInstance().cacheUniAppDir.absolutePath, wgtName) onProgress(UniMpUpdate.DOWNLOAD_START, wgtFile.path, 0f) downloadUniMp(scope, uniVersion){uniState, filePath, progress -> onProgress(uniState, filePath, progress) if(uniState == UniMpUpdate.DOWNLOAD_FINISH){ - PreferenceUtil.saveWgtVersion(uniVersion.unimp_id, uniVersion.version) - distributeUniMp(context, uniVersion) { _ ->} + distributeUniMp(context, uniVersion,reportViewModel) { _ ->} } } } @@ -254,15 +271,14 @@ object UniAppUtils { /** * 下载并释放资源(但不会启动) */ - fun downloadReleaseWgt(scope: CoroutineScope, uniVersion: UniVersionEntity, onProgress:(state: UniMpUpdate, progress: Float?) -> Unit,onRelease:(isSuccess: Boolean) -> Unit){ + fun downloadReleaseWgt(scope: CoroutineScope, uniVersion: UniVersionEntity,reportViewModel: ReportViewModel, onProgress:(state: UniMpUpdate, progress: Float?) -> Unit,onRelease:(isSuccess: Boolean) -> Unit){ val uniMpId = uniVersion.unimp_id onProgress(UniMpUpdate.DOWNLOAD_START, 0f) downloadUniMp(scope, uniVersion){uniState, _, progress -> onProgress(UniMpUpdate.DOWNLOAD_LOADING, progress) if(uniState == UniMpUpdate.DOWNLOAD_FINISH){ - PreferenceUtil.saveWgtVersion(uniMpId, uniVersion.version) onProgress(UniMpUpdate.DOWNLOAD_FINISH, 1f) - releaseWgt(uniMpId){ isSuccess -> + releaseWgt(uniMpId,reportViewModel){ isSuccess -> if(isSuccess){ onRelease(true) }else{ @@ -283,12 +299,20 @@ object UniAppUtils { uniVersion: UniVersionEntity, onProgress:(state:UniMpUpdate,filePath: String?, progress: Float) -> Unit ) { - val uniMpID = uniVersion.unimp_id - val wgtName = String.format("%s.wgt", uniMpID) + val extension = MimeTypeMap.getFileExtensionFromUrl(uniVersion.url) + if(extension != "zip" && extension != "wgt"){ + CenterToast.show("资源文件格式不被支持...") + onProgress(UniMpUpdate.DOWNLOAD_FAIL, null, -1f) + return + } + + val uniMpId = uniVersion.unimp_id + val wgtName = getWgtName(uniMpId) val path = FileUtils.getInstance().cacheUniAppDir.absolutePath //先删除旧文件 val oldFile = File(path, wgtName) if(oldFile.exists()){ + oldFile.delete() } onProgress(UniMpUpdate.DOWNLOAD_LOADING, null, 0.01f) @@ -296,7 +320,7 @@ object UniAppUtils { scope.launch { val isAvailable = isFileDownloadable(uniVersion.url) if(!isAvailable){ - Log.i(TAG, "下载失败,无效地址") + Log.i(TAG, "下载失败,无效地址 ------>${uniVersion.url}") onProgress(UniMpUpdate.DOWNLOAD_FAIL, null, -1f) CenterToast.show("下载失败...") }else{ @@ -317,6 +341,7 @@ object UniAppUtils { }, onFinish = {isSuccess, filePath -> if(isSuccess){ + PreferenceUtil.saveWgtVersion(uniMpId, uniVersion.version) Log.i(TAG, "下载完成---->updateUniMp: $filePath") onProgress(UniMpUpdate.DOWNLOAD_FINISH, filePath, 1f) }else{ diff --git a/app/src/main/java/com/img/rabbit/utils/UpdateUtils.kt b/app/src/main/java/com/img/rabbit/utils/UpdateUtils.kt index f61c74b..43a203a 100644 --- a/app/src/main/java/com/img/rabbit/utils/UpdateUtils.kt +++ b/app/src/main/java/com/img/rabbit/utils/UpdateUtils.kt @@ -3,13 +3,16 @@ package com.img.rabbit.utils import android.annotation.SuppressLint import android.content.Context import android.content.Intent +import android.util.Log import androidx.core.content.FileProvider import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch +import net.lingala.zip4j.ZipFile import java.io.File object UpdateUtils { + private const val TAG = "UpdateUtils" @SuppressLint("SetTextI18n") fun download(scope: CoroutineScope, url: String, filePath: String, fileName: String, onProgress:(progress:Int)-> Unit, onFinish:(isSuccess: Boolean, filePath: String?)-> Unit) { scope.launch(Dispatchers.IO) { @@ -51,4 +54,25 @@ object UpdateUtils { e.printStackTrace() } } + + /** + * @param zipFilePath 压缩包路径 (例如: context.filesDir.path + "/test.zip") + * @param destPath 解压目标目录 + * @param password 密码,如果没有密码传 null + */ + fun unpackZip(zipFilePath: String, destPath: String, password: String? = null) { + try { + val zipFile = ZipFile(zipFilePath) + // 如果有密码,设置密码 + if (zipFile.isEncrypted && password != null) { + zipFile.setPassword(password.toCharArray()) + } + // 核心一行代码:解压全部文件 + zipFile.extractAll(destPath) + Log.i(TAG, "unpackZip: 解压成功到: $destPath") + } catch (e: Exception) { + e.printStackTrace() + Log.i(TAG, "unpackZip: 解压失败: ${e.message}") + } + } } \ No newline at end of file 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 012f9d5..92be078 100644 --- a/app/src/main/java/com/img/rabbit/viewmodel/LoginViewModel.kt +++ b/app/src/main/java/com/img/rabbit/viewmodel/LoginViewModel.kt @@ -431,7 +431,7 @@ class LoginViewModel : BaseViewModel() { * 请求退出登录 */ @OptIn(DelicateCoroutinesApi::class) - fun requestLogout(context: Context) { + fun requestLogout() { isLoading.value = true // 开始加载 mLaunch { val response = ApiManager.serviceVo.logout() diff --git a/app/src/main/java/com/img/rabbit/viewmodel/ReportViewModel.kt b/app/src/main/java/com/img/rabbit/viewmodel/ReportViewModel.kt new file mode 100644 index 0000000..973acf5 --- /dev/null +++ b/app/src/main/java/com/img/rabbit/viewmodel/ReportViewModel.kt @@ -0,0 +1,20 @@ +package com.img.rabbit.viewmodel + +import android.util.Log +import com.img.rabbit.bean.request.ReportRequest +import com.img.rabbit.provider.api.ApiManager +import kotlinx.serialization.json.Json +import okhttp3.RequestBody.Companion.toRequestBody + +class ReportViewModel : BaseViewModel() { + private val TAG = "ReportViewModel" + + //请求客服连接 + fun requestReport(requst: ReportRequest){ + mLaunch { + val requstJson = Json.encodeToString(requst) + val response = ApiManager.serviceVo.report(requstJson.toRequestBody()) + Log.i(TAG, "requestReport: ${response.data}") + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/img/rabbit/viewmodel/interface/ServiceVo.kt b/app/src/main/java/com/img/rabbit/viewmodel/interface/ServiceVo.kt index 095cfa9..076c7ce 100644 --- a/app/src/main/java/com/img/rabbit/viewmodel/interface/ServiceVo.kt +++ b/app/src/main/java/com/img/rabbit/viewmodel/interface/ServiceVo.kt @@ -111,4 +111,8 @@ interface ServiceVo { */ @GET("/api/weixin/service") suspend fun wxService(): ResultVo + + //事件上报 + @POST("/api/user/event") + suspend fun report(@Body requestBody: RequestBody): ResultVo } \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 9e303ac..710ba21 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -58,6 +58,7 @@ android_cn_oaid = "4.2.12" fastaes = "1.1.5" foundationVersion = "1.10.3" accompanistPermissions = "0.32.0" +zip4j = "2.11.6" # Uni小程序相关依赖 version recyclerview = "1.0.0" legacySupportV4 = "1.0.0" @@ -137,8 +138,10 @@ android_cn_oaid = { module = "com.github.gzu-liyujiang:Android_CN_OAID", version fastaes = { module = "io.github.billywei01:fastaes", version.ref = "fastaes" } #noinspection SimilarGradleDependency foundation = { group = "androidx.compose.foundation", name = "foundation", version.ref = "foundationVersion" } - +#权限申请 accompanist-permissions = { module = "com.google.accompanist:accompanist-permissions", version.ref = "accompanistPermissions" } +#压缩解压 +zip4j = { group = "net.lingala.zip4j", name = "zip4j", version.ref = "zip4j" } # Uni小程序相关依赖 androidx-recyclerview = { module = "androidx.recyclerview:recyclerview", version.ref = "recyclerview" }