Files
rider-pro-android-app/app/src/main/java/com/aiosman/riderpro/MainActivity.kt

326 lines
12 KiB
Kotlin
Raw Normal View History

2024-06-22 04:25:20 +08:00
package com.aiosman.riderpro
import android.Manifest
2024-10-26 06:02:30 +08:00
import android.app.AlertDialog
import android.app.DownloadManager
import android.app.NotificationChannel
import android.app.NotificationManager
import android.content.Context
2024-09-17 16:06:27 +08:00
import android.content.Intent
2024-10-26 06:02:30 +08:00
import android.content.IntentFilter
import android.content.pm.PackageManager
2024-09-17 16:06:27 +08:00
import android.net.Uri
import android.os.Build
2024-06-22 04:25:20 +08:00
import android.os.Bundle
2024-10-26 06:02:30 +08:00
import android.os.Environment
import android.util.Log
2024-06-22 04:25:20 +08:00
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
2024-09-05 22:04:41 +08:00
import androidx.activity.result.contract.ActivityResultContracts
2024-10-26 06:02:30 +08:00
import androidx.annotation.RequiresApi
2024-07-20 16:06:37 +08:00
import androidx.compose.animation.AnimatedContentScope
import androidx.compose.animation.ExperimentalSharedTransitionApi
import androidx.compose.animation.SharedTransitionScope
2024-10-24 23:53:51 +08:00
import androidx.compose.runtime.LaunchedEffect
2024-07-12 23:37:21 +08:00
import androidx.compose.runtime.compositionLocalOf
2024-10-24 23:53:51 +08:00
import androidx.compose.ui.graphics.Color
2024-09-05 22:04:41 +08:00
import androidx.core.content.ContextCompat
2024-07-13 17:41:51 +08:00
import androidx.core.view.WindowCompat
import androidx.lifecycle.ProcessLifecycleOwner
2024-10-26 06:02:30 +08:00
import androidx.lifecycle.lifecycleScope
2024-06-22 04:25:20 +08:00
import androidx.navigation.NavHostController
2024-09-18 17:03:26 +08:00
import cn.jiguang.api.utils.JCollectionAuth
import cn.jpush.android.api.JPushInterface
2024-07-31 14:50:55 +08:00
import com.aiosman.riderpro.data.AccountService
2024-08-23 18:31:14 +08:00
import com.aiosman.riderpro.data.AccountServiceImpl
2024-10-11 16:51:51 +08:00
import com.aiosman.riderpro.data.UserService
import com.aiosman.riderpro.data.UserServiceImpl
2024-10-26 06:02:30 +08:00
import com.aiosman.riderpro.model.ApkInstallReceiver
import com.aiosman.riderpro.model.UpdateInfo
2024-07-23 15:25:00 +08:00
import com.aiosman.riderpro.ui.Navigation
2024-07-30 16:57:25 +08:00
import com.aiosman.riderpro.ui.NavigationRoute
2024-09-22 15:35:42 +08:00
import com.aiosman.riderpro.ui.navigateToPost
2024-09-17 16:06:27 +08:00
import com.aiosman.riderpro.ui.post.NewPostViewModel
2024-10-24 23:53:51 +08:00
import com.google.accompanist.systemuicontroller.rememberSystemUiController
import com.google.firebase.analytics.FirebaseAnalytics
2024-10-26 06:02:30 +08:00
import com.google.gson.Gson
2024-07-30 16:57:25 +08:00
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
2024-10-26 06:02:30 +08:00
import kotlinx.coroutines.withContext
import okhttp3.OkHttpClient
import okhttp3.Request
2024-06-22 04:25:20 +08:00
2024-09-23 23:47:16 +08:00
2024-06-22 04:25:20 +08:00
class MainActivity : ComponentActivity() {
2024-09-05 22:04:41 +08:00
// Firebase Analytics
private lateinit var analytics: FirebaseAnalytics
2024-07-30 16:57:25 +08:00
private val scope = CoroutineScope(Dispatchers.Main)
2024-10-26 06:02:30 +08:00
val context = this
private val apkInstallReceiver = ApkInstallReceiver()
2024-09-05 22:04:41 +08:00
// 请求通知权限
private val requestPermissionLauncher = registerForActivityResult(
ActivityResultContracts.RequestPermission(),
) { isGranted: Boolean ->
if (isGranted) {
// FCM SDK (and your app) can post notifications.
} else {
2024-09-23 23:47:16 +08:00
2024-09-05 22:04:41 +08:00
}
}
2024-10-26 06:02:30 +08:00
@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")
}
2024-09-05 22:04:41 +08:00
/**
* 获取账号信息
*/
private suspend fun getAccount(): Boolean {
2024-08-23 18:31:14 +08:00
val accountService: AccountService = AccountServiceImpl()
2024-08-11 17:15:17 +08:00
try {
val resp = accountService.getMyAccount()
return true
2024-08-13 22:32:27 +08:00
} catch (e: Exception) {
2024-08-11 17:15:17 +08:00
return false
}
2024-07-30 16:57:25 +08:00
}
2024-08-11 17:15:17 +08:00
2024-10-26 06:02:30 +08:00
@RequiresApi(Build.VERSION_CODES.P)
2024-06-22 04:25:20 +08:00
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
2024-09-05 22:04:41 +08:00
// 监听应用生命周期
ProcessLifecycleOwner.get().lifecycle.addObserver(MainActivityLifecycleObserver())
// 创建通知渠道
createNotificationChannel()
// 沉浸式状态栏
2024-07-13 17:41:51 +08:00
WindowCompat.setDecorFitsSystemWindows(window, false)
2024-09-05 22:04:41 +08:00
// 初始化 Places SDK
2024-09-22 20:02:58 +08:00
2024-09-05 22:04:41 +08:00
// 初始化 Firebase Analytics
2024-09-18 17:03:26 +08:00
// analytics = Firebase.analytics
2024-09-05 22:04:41 +08:00
// 请求通知权限
askNotificationPermission()
// 加载一些本地化的配置
2024-07-30 16:57:25 +08:00
AppStore.init(this)
2024-09-18 17:03:26 +08:00
JPushInterface.setDebugMode(true);
// 调整点一初始化代码前增加setAuth调用
JCollectionAuth.setAuth(this, true)
JPushInterface.init(this)
2024-10-24 23:53:51 +08:00
if (AppState.darkMode) {
window.decorView.setBackgroundColor(android.graphics.Color.BLACK)
}
2024-06-22 04:25:20 +08:00
enableEdgeToEdge()
2024-07-30 16:57:25 +08:00
2024-10-26 06:02:30 +08:00
// 注册广播接收器
val intentFilter = IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE)
registerReceiver(apkInstallReceiver, intentFilter, RECEIVER_NOT_EXPORTED)
checkUpdate()
2024-09-23 23:47:16 +08:00
// 初始化腾讯云通信 SDK
2024-09-18 17:03:26 +08:00
2024-07-30 16:57:25 +08:00
scope.launch {
2024-09-05 22:04:41 +08:00
// 检查是否有登录态
2024-08-11 17:15:17 +08:00
val isAccountValidate = getAccount()
2024-07-30 16:57:25 +08:00
var startDestination = NavigationRoute.Login.route
2024-09-05 22:04:41 +08:00
// 如果有登录态,且记住登录状态,且账号有效,则初始化 FCM下一步进入首页
2024-08-11 17:15:17 +08:00
if (AppStore.token != null && AppStore.rememberMe && isAccountValidate) {
2024-09-23 23:47:16 +08:00
AppState.initWithAccount(scope, this@MainActivity)
2024-07-30 16:57:25 +08:00
startDestination = NavigationRoute.Index.route
}
2024-09-23 23:47:16 +08:00
2024-07-30 16:57:25 +08:00
setContent {
2024-10-24 23:53:51 +08:00
2024-09-05 22:04:41 +08:00
Navigation(startDestination) { navController ->
// 处理带有 postId 的通知点击
val postId = intent.getStringExtra("POST_ID")
2024-09-20 17:10:54 +08:00
var commentId = intent.getStringExtra("COMMENT_ID")
2024-10-11 16:51:51 +08:00
val action = intent.getStringExtra("ACTION")
2024-09-20 17:10:54 +08:00
if (action == "newFollow") {
navController.navigate(NavigationRoute.Followers.route)
return@Navigation
}
2024-09-22 15:35:42 +08:00
if (action == "followCount") {
navController.navigate(NavigationRoute.Followers.route)
return@Navigation
}
2024-10-11 16:51:51 +08:00
if (action == "TRTC_NEW_MESSAGE") {
val userService:UserService = UserServiceImpl()
val sender = intent.getStringExtra("SENDER")
sender?.let {
scope.launch {
try {
val profile = userService.getUserProfileByTrtcUserId(it)
navController.navigate(NavigationRoute.Chat.route.replace(
"{id}",
profile.id.toString()
))
}catch (e:Exception){
e.printStackTrace()
}
}
}
return@Navigation
}
2024-09-20 17:10:54 +08:00
if (commentId == null) {
commentId = "0"
}
2024-09-05 22:04:41 +08:00
if (postId != null) {
Log.d("MainActivity", "Navigation to Post$postId")
2024-09-22 15:35:42 +08:00
navController.navigateToPost(
id = postId.toInt(),
highlightCommentId = commentId.toInt(),
initImagePagerIndex = 0
2024-09-14 23:27:44 +08:00
)
2024-09-05 22:04:41 +08:00
}
2024-09-17 16:06:27 +08:00
// 处理分享过来的图片
if (intent?.action == Intent.ACTION_SEND || intent?.action == Intent.ACTION_SEND_MULTIPLE) {
val imageUris: List<Uri>? = if (intent.action == Intent.ACTION_SEND) {
listOf(intent.getParcelableExtra(Intent.EXTRA_STREAM)!!)
} else {
intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM)
}
NewPostViewModel.asNewPostWithImageUris(imageUris!!.map { it.toString() })
navController.navigate(NavigationRoute.NewPost.route)
}
2024-09-05 22:04:41 +08:00
}
2024-09-14 23:27:44 +08:00
2024-07-30 16:57:25 +08:00
}
2024-09-05 22:04:41 +08:00
2024-06-22 04:25:20 +08:00
}
}
2024-09-05 22:04:41 +08:00
2024-10-26 06:02:30 +08:00
override fun onDestroy() {
super.onDestroy()
// 取消注册广播接收器
unregisterReceiver(apkInstallReceiver)
}
2024-09-05 22:04:41 +08:00
/**
* 请求通知权限
*/
private fun askNotificationPermission() {
// This is only necessary for API level >= 33 (TIRAMISU)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) ==
PackageManager.PERMISSION_GRANTED
) {
// FCM SDK (and your app) can post notifications.
} else if (shouldShowRequestPermissionRationale(android.Manifest.permission.POST_NOTIFICATIONS)) {
} else {
// Directly ask for the permission
requestPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS)
}
}
}
/**
* 创建通知渠道
*/
private fun createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channelId = ConstVars.MOMENT_LIKE_CHANNEL_ID
val channelName = ConstVars.MOMENT_LIKE_CHANNEL_NAME
val channel =
NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_DEFAULT)
val notificationManager =
getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.createNotificationChannel(channel)
}
}
2024-06-22 04:25:20 +08:00
}
2024-07-12 23:37:21 +08:00
val LocalNavController = compositionLocalOf<NavHostController> {
error("NavController not provided")
}
2024-07-20 16:06:37 +08:00
@OptIn(ExperimentalSharedTransitionApi::class)
val LocalSharedTransitionScope = compositionLocalOf<SharedTransitionScope> {
error("SharedTransitionScope not provided")
}
val LocalAnimatedContentScope = compositionLocalOf<AnimatedContentScope> {
error("AnimatedContentScope not provided")
}
2024-10-26 06:02:30 +08:00