软件内版本检测更新
This commit is contained in:
@@ -114,6 +114,8 @@ dependencies {
|
|||||||
api ("com.tencent.imsdk:imsdk-plus:8.1.6116")
|
api ("com.tencent.imsdk:imsdk-plus:8.1.6116")
|
||||||
implementation("io.github.rroohit:ImageCropView:3.0.1")
|
implementation("io.github.rroohit:ImageCropView:3.0.1")
|
||||||
implementation("androidx.core:core-splashscreen:1.0.1") // 添加 SplashScreen 依赖
|
implementation("androidx.core:core-splashscreen:1.0.1") // 添加 SplashScreen 依赖
|
||||||
|
// 添加 lifecycle-runtime-ktx 依赖
|
||||||
|
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.6.2")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -52,6 +52,13 @@
|
|||||||
<data android:mimeType="image/*" />
|
<data android:mimeType="image/*" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
<receiver
|
||||||
|
android:name=".model.ApkInstallReceiver"
|
||||||
|
android:exported="false">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.DOWNLOAD_COMPLETE" />
|
||||||
|
</intent-filter>
|
||||||
|
</receiver>
|
||||||
|
|
||||||
<service
|
<service
|
||||||
android:name=".MyFirebaseMessagingService"
|
android:name=".MyFirebaseMessagingService"
|
||||||
|
|||||||
@@ -1,19 +1,24 @@
|
|||||||
package com.aiosman.riderpro
|
package com.aiosman.riderpro
|
||||||
|
|
||||||
import android.Manifest
|
import android.Manifest
|
||||||
|
import android.app.AlertDialog
|
||||||
|
import android.app.DownloadManager
|
||||||
import android.app.NotificationChannel
|
import android.app.NotificationChannel
|
||||||
import android.app.NotificationManager
|
import android.app.NotificationManager
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
import android.content.IntentFilter
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.os.Environment
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.activity.ComponentActivity
|
import androidx.activity.ComponentActivity
|
||||||
import androidx.activity.compose.setContent
|
import androidx.activity.compose.setContent
|
||||||
import androidx.activity.enableEdgeToEdge
|
import androidx.activity.enableEdgeToEdge
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
|
import androidx.annotation.RequiresApi
|
||||||
import androidx.compose.animation.AnimatedContentScope
|
import androidx.compose.animation.AnimatedContentScope
|
||||||
import androidx.compose.animation.ExperimentalSharedTransitionApi
|
import androidx.compose.animation.ExperimentalSharedTransitionApi
|
||||||
import androidx.compose.animation.SharedTransitionScope
|
import androidx.compose.animation.SharedTransitionScope
|
||||||
@@ -23,6 +28,7 @@ import androidx.compose.ui.graphics.Color
|
|||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.core.view.WindowCompat
|
import androidx.core.view.WindowCompat
|
||||||
import androidx.lifecycle.ProcessLifecycleOwner
|
import androidx.lifecycle.ProcessLifecycleOwner
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.navigation.NavHostController
|
import androidx.navigation.NavHostController
|
||||||
import cn.jiguang.api.utils.JCollectionAuth
|
import cn.jiguang.api.utils.JCollectionAuth
|
||||||
import cn.jpush.android.api.JPushInterface
|
import cn.jpush.android.api.JPushInterface
|
||||||
@@ -30,21 +36,29 @@ import com.aiosman.riderpro.data.AccountService
|
|||||||
import com.aiosman.riderpro.data.AccountServiceImpl
|
import com.aiosman.riderpro.data.AccountServiceImpl
|
||||||
import com.aiosman.riderpro.data.UserService
|
import com.aiosman.riderpro.data.UserService
|
||||||
import com.aiosman.riderpro.data.UserServiceImpl
|
import com.aiosman.riderpro.data.UserServiceImpl
|
||||||
|
import com.aiosman.riderpro.model.ApkInstallReceiver
|
||||||
|
import com.aiosman.riderpro.model.UpdateInfo
|
||||||
import com.aiosman.riderpro.ui.Navigation
|
import com.aiosman.riderpro.ui.Navigation
|
||||||
import com.aiosman.riderpro.ui.NavigationRoute
|
import com.aiosman.riderpro.ui.NavigationRoute
|
||||||
import com.aiosman.riderpro.ui.navigateToPost
|
import com.aiosman.riderpro.ui.navigateToPost
|
||||||
import com.aiosman.riderpro.ui.post.NewPostViewModel
|
import com.aiosman.riderpro.ui.post.NewPostViewModel
|
||||||
import com.google.accompanist.systemuicontroller.rememberSystemUiController
|
import com.google.accompanist.systemuicontroller.rememberSystemUiController
|
||||||
import com.google.firebase.analytics.FirebaseAnalytics
|
import com.google.firebase.analytics.FirebaseAnalytics
|
||||||
|
import com.google.gson.Gson
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
import okhttp3.OkHttpClient
|
||||||
|
import okhttp3.Request
|
||||||
|
|
||||||
|
|
||||||
class MainActivity : ComponentActivity() {
|
class MainActivity : ComponentActivity() {
|
||||||
// Firebase Analytics
|
// Firebase Analytics
|
||||||
private lateinit var analytics: FirebaseAnalytics
|
private lateinit var analytics: FirebaseAnalytics
|
||||||
private val scope = CoroutineScope(Dispatchers.Main)
|
private val scope = CoroutineScope(Dispatchers.Main)
|
||||||
|
val context = this
|
||||||
|
private val apkInstallReceiver = ApkInstallReceiver()
|
||||||
|
|
||||||
// 请求通知权限
|
// 请求通知权限
|
||||||
private val requestPermissionLauncher = registerForActivityResult(
|
private val requestPermissionLauncher = registerForActivityResult(
|
||||||
@@ -57,6 +71,76 @@ class MainActivity : ComponentActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@RequiresApi(Build.VERSION_CODES.P)
|
||||||
|
fun getVersionCode(context: Context): Int {
|
||||||
|
val packageManager = context.packageManager
|
||||||
|
val packageInfo = packageManager.getPackageInfo(context.packageName,0)
|
||||||
|
return packageInfo.longVersionCode.toInt()
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequiresApi(Build.VERSION_CODES.P)
|
||||||
|
private fun checkUpdate() {
|
||||||
|
lifecycleScope.launch(Dispatchers.IO) {
|
||||||
|
try {
|
||||||
|
val client = OkHttpClient()
|
||||||
|
val request = Request.Builder()
|
||||||
|
.url("https://rider-pro.aiosman.com/beta_api/static/update/beta/version.json")
|
||||||
|
.build()
|
||||||
|
val response = client.newCall(request).execute()
|
||||||
|
|
||||||
|
if (response.isSuccessful) {
|
||||||
|
val responseBody = response.body?.string()
|
||||||
|
val updateInfo = Gson().fromJson(responseBody, UpdateInfo::class.java)
|
||||||
|
|
||||||
|
val versionCode = getVersionCode(context)
|
||||||
|
// 检查是否有新版本
|
||||||
|
Log.d("MainActivity", "Current version code: $versionCode")
|
||||||
|
Log.d("MainActivity", "Server version code: ${updateInfo.versionCode}")
|
||||||
|
if (updateInfo.versionCode > versionCode) {
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
showUpdateDialog(updateInfo)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
// 处理网络请求失败
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun showUpdateDialog(updateInfo: UpdateInfo) {
|
||||||
|
val builder = AlertDialog.Builder(this)
|
||||||
|
builder.setTitle("发现新版本 v${updateInfo.versionName}")
|
||||||
|
builder.setMessage(updateInfo.updateContent)
|
||||||
|
builder.setPositiveButton("立即更新") { dialog, _ ->
|
||||||
|
|
||||||
|
downloadApk(updateInfo.downloadUrl,updateInfo.versionName)
|
||||||
|
dialog.dismiss()
|
||||||
|
}
|
||||||
|
if (!updateInfo.forceUpdate) {
|
||||||
|
builder.setNegativeButton("稍后再说") { dialog, _ ->
|
||||||
|
dialog.dismiss()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
builder.setCancelable(false)
|
||||||
|
}
|
||||||
|
builder.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun downloadApk(downloadUrl: String,versionName: String) {
|
||||||
|
// 使用 DownloadManager 下载 APK 文件
|
||||||
|
val downloadManager = getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
|
||||||
|
val request = DownloadManager.Request(Uri.parse(downloadUrl))
|
||||||
|
val apkFileName = "RiderPro_v${versionName.replace(".","_")}.apk"
|
||||||
|
request.setMimeType("application/vnd.android.package-archive") // 添加这行代码
|
||||||
|
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, apkFileName)
|
||||||
|
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
|
||||||
|
val downloadId = downloadManager.enqueue(request)
|
||||||
|
Log.d("MainActivity", "Download enqueued with ID: $downloadId")
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取账号信息
|
* 获取账号信息
|
||||||
*/
|
*/
|
||||||
@@ -70,6 +154,7 @@ class MainActivity : ComponentActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@RequiresApi(Build.VERSION_CODES.P)
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
// 监听应用生命周期
|
// 监听应用生命周期
|
||||||
@@ -99,6 +184,12 @@ class MainActivity : ComponentActivity() {
|
|||||||
}
|
}
|
||||||
enableEdgeToEdge()
|
enableEdgeToEdge()
|
||||||
|
|
||||||
|
// 注册广播接收器
|
||||||
|
val intentFilter = IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE)
|
||||||
|
registerReceiver(apkInstallReceiver, intentFilter, RECEIVER_NOT_EXPORTED)
|
||||||
|
|
||||||
|
checkUpdate()
|
||||||
|
|
||||||
// 初始化腾讯云通信 SDK
|
// 初始化腾讯云通信 SDK
|
||||||
|
|
||||||
|
|
||||||
@@ -176,6 +267,12 @@ class MainActivity : ComponentActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onDestroy() {
|
||||||
|
super.onDestroy()
|
||||||
|
// 取消注册广播接收器
|
||||||
|
unregisterReceiver(apkInstallReceiver)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 请求通知权限
|
* 请求通知权限
|
||||||
*/
|
*/
|
||||||
@@ -225,3 +322,4 @@ val LocalAnimatedContentScope = compositionLocalOf<AnimatedContentScope> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
43
app/src/main/java/com/aiosman/riderpro/model/UpdateInfo.kt
Normal file
43
app/src/main/java/com/aiosman/riderpro/model/UpdateInfo.kt
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
package com.aiosman.riderpro.model
|
||||||
|
|
||||||
|
import android.app.DownloadManager
|
||||||
|
import android.content.BroadcastReceiver
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.net.Uri
|
||||||
|
import android.util.Log
|
||||||
|
import androidx.core.net.toUri
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
data class UpdateInfo(
|
||||||
|
val versionCode: Int,
|
||||||
|
val versionName: String,
|
||||||
|
val updateContent: String,
|
||||||
|
val downloadUrl: String,
|
||||||
|
val forceUpdate: Boolean
|
||||||
|
)
|
||||||
|
|
||||||
|
class ApkInstallReceiver : BroadcastReceiver() {
|
||||||
|
override fun onReceive(context: Context, intent: Intent) {
|
||||||
|
Log.d("ApkInstallReceiver", "onReceive() called") // 添加日志输出
|
||||||
|
if (DownloadManager.ACTION_DOWNLOAD_COMPLETE == intent.action) {
|
||||||
|
Log.d("ApkInstallReceiver", "Download complete") // 添加日志输出
|
||||||
|
val downloadId = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1)
|
||||||
|
val downloadManager = context.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
|
||||||
|
|
||||||
|
// 方案二:通过 DownloadManager 的 API 获取 Uri
|
||||||
|
val uri = downloadManager.getUriForDownloadedFile(downloadId)
|
||||||
|
if (uri != null) {
|
||||||
|
installApk(context, uri)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun installApk(context: Context, uri: Uri) {
|
||||||
|
Log.d("ApkInstallReceiver", "installApk() called with: context = $context, uri = $uri") // 添加日志输出
|
||||||
|
val installIntent = Intent(Intent.ACTION_VIEW)
|
||||||
|
installIntent.setDataAndType(uri, "application/vnd.android.package-archive")
|
||||||
|
installIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_GRANT_READ_URI_PERMISSION
|
||||||
|
context.startActivity(installIntent)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user