VersionUpdateManager.kt 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. package com.narutohuo.xindazhou.common.version
  2. import android.app.Activity
  3. import android.content.Context
  4. import android.content.pm.PackageManager
  5. import androidx.core.content.pm.PackageInfoCompat
  6. import androidx.fragment.app.FragmentActivity
  7. import androidx.lifecycle.LifecycleOwner
  8. import androidx.lifecycle.lifecycleScope
  9. import com.narutohuo.xindazhou.common.log.LogHelper
  10. import com.narutohuo.xindazhou.common.network.ApiManager
  11. import com.narutohuo.xindazhou.common.version.datasource.remote.VersionRemoteDataSourceImpl
  12. import com.narutohuo.xindazhou.common.version.repository.VersionRepository
  13. import com.narutohuo.xindazhou.common.version.ui.UpdateDialogFragment
  14. import kotlinx.coroutines.launch
  15. /**
  16. * 版本更新管理器
  17. *
  18. * 封装版本检查的完整逻辑,包括:
  19. * - 获取当前版本号
  20. * - 检查服务器版本
  21. * - 显示更新对话框
  22. * - 处理强制更新
  23. *
  24. * 使用方式:
  25. * ```kotlin
  26. * // 在 Application 中初始化
  27. * VersionUpdateManager.init(context)
  28. *
  29. * // 在 Activity 中检查更新(自动获取版本号)
  30. * VersionUpdateManager.checkUpdate(activity)
  31. *
  32. * // 或者手动指定版本号
  33. * VersionUpdateManager.checkUpdate(activity, platform = 1, versionCode = 100)
  34. * ```
  35. */
  36. object VersionUpdateManager {
  37. private const val PLATFORM_ANDROID = 1 // 平台类型:1-安卓,2-鸿蒙,3-iOS
  38. /**
  39. * 初始化版本更新管理器
  40. *
  41. * 需要在 Application.onCreate() 中调用
  42. *
  43. * @param context 上下文
  44. * @param platform 平台类型(默认 1-安卓)
  45. */
  46. fun init(context: Context, platform: Int = PLATFORM_ANDROID) {
  47. // 初始化 ApiManager 的 baseUrlProvider(如果还未设置)
  48. if (ApiManager.baseUrlProvider == null) {
  49. // 这里需要从 ServerConfigManager 获取,但为了避免循环依赖,
  50. // 建议在 Application 中先设置 ApiManager.baseUrlProvider
  51. LogHelper.w("VersionUpdateManager", "ApiManager.baseUrlProvider 未设置,版本检查可能失败")
  52. }
  53. }
  54. /**
  55. * 检查版本更新(自动获取当前版本号)
  56. *
  57. * @param activity Activity 实例(用于显示对话框和获取版本号)
  58. * @param platform 平台类型(默认 1-安卓)
  59. * @param onForceUpdateDismiss 强制更新时,用户关闭对话框的回调(可选,默认退出应用)
  60. */
  61. fun checkUpdate(
  62. activity: FragmentActivity,
  63. platform: Int = PLATFORM_ANDROID,
  64. onForceUpdateDismiss: (() -> Unit)? = null
  65. ) {
  66. val currentVersionCode = getCurrentVersionCode(activity)
  67. checkUpdate(activity, platform, currentVersionCode, onForceUpdateDismiss)
  68. }
  69. /**
  70. * 检查版本更新(手动指定版本号)
  71. *
  72. * @param activity Activity 实例(用于显示对话框)
  73. * @param platform 平台类型(默认 1-安卓)
  74. * @param currentVersionCode 当前版本号
  75. * @param onForceUpdateDismiss 强制更新时,用户关闭对话框的回调(可选,默认退出应用)
  76. */
  77. fun checkUpdate(
  78. activity: FragmentActivity,
  79. platform: Int,
  80. currentVersionCode: Int,
  81. onForceUpdateDismiss: (() -> Unit)? = null
  82. ) {
  83. // 使用 LifecycleOwner 的 lifecycleScope,自动管理协程生命周期
  84. activity.lifecycleScope.launch {
  85. try {
  86. // 创建数据源和 Repository
  87. val remoteDataSource = com.narutohuo.xindazhou.common.version.datasource.remote.VersionRemoteDataSourceImpl()
  88. val versionRepository = VersionRepository(remoteDataSource)
  89. // 检查版本(如果没有版本,返回 null,不影响启动)
  90. val versionResponse = versionRepository.checkVersion(platform, currentVersionCode)
  91. // 如果有新版本,显示更新对话框
  92. if (versionResponse != null && versionRepository.hasUpdate(versionResponse)) {
  93. val dialog = UpdateDialogFragment.create(
  94. versionResponse = versionResponse,
  95. onDismiss = {
  96. // 对话框关闭后的回调
  97. if (versionRepository.isForceUpdate(versionResponse)) {
  98. // 强制更新时,如果用户关闭对话框,执行回调或退出应用
  99. if (onForceUpdateDismiss != null) {
  100. onForceUpdateDismiss()
  101. } else {
  102. activity.finish()
  103. }
  104. }
  105. }
  106. )
  107. dialog.show(activity.supportFragmentManager, "UpdateDialogFragment")
  108. }
  109. } catch (e: Exception) {
  110. // 版本检查失败不影响应用启动
  111. // 可以记录日志,但不显示错误提示
  112. LogHelper.e("VersionUpdateManager", "版本检查失败", e)
  113. }
  114. }
  115. }
  116. /**
  117. * 检查版本更新(使用 LifecycleOwner,适用于 Fragment)
  118. *
  119. * @param lifecycleOwner LifecycleOwner(Activity 或 Fragment)
  120. * @param activity Activity 实例(用于显示对话框和获取版本号)
  121. * @param platform 平台类型(默认 1-安卓)
  122. * @param onForceUpdateDismiss 强制更新时,用户关闭对话框的回调(可选,默认退出应用)
  123. */
  124. fun checkUpdate(
  125. lifecycleOwner: LifecycleOwner,
  126. activity: FragmentActivity,
  127. platform: Int = PLATFORM_ANDROID,
  128. onForceUpdateDismiss: (() -> Unit)? = null
  129. ) {
  130. val currentVersionCode = getCurrentVersionCode(activity)
  131. lifecycleOwner.lifecycleScope.launch {
  132. try {
  133. // 创建数据源和 Repository
  134. val remoteDataSource = VersionRemoteDataSourceImpl()
  135. val versionRepository = VersionRepository(remoteDataSource)
  136. // 检查版本(如果没有版本,返回 null,不影响启动)
  137. val versionResponse = versionRepository.checkVersion(platform, currentVersionCode)
  138. // 如果有新版本,显示更新对话框
  139. if (versionResponse != null && versionRepository.hasUpdate(versionResponse)) {
  140. val dialog = UpdateDialogFragment.create(
  141. versionResponse = versionResponse,
  142. onDismiss = {
  143. // 对话框关闭后的回调
  144. if (versionRepository.isForceUpdate(versionResponse)) {
  145. // 强制更新时,如果用户关闭对话框,执行回调或退出应用
  146. if (onForceUpdateDismiss != null) {
  147. onForceUpdateDismiss()
  148. } else {
  149. activity.finish()
  150. }
  151. }
  152. }
  153. )
  154. dialog.show(activity.supportFragmentManager, "UpdateDialogFragment")
  155. }
  156. } catch (e: Exception) {
  157. // 版本检查失败不影响应用启动
  158. // 可以记录日志,但不显示错误提示
  159. LogHelper.e("VersionUpdateManager", "版本检查失败", e)
  160. }
  161. }
  162. }
  163. /**
  164. * 获取当前应用的版本号
  165. *
  166. * @param context 上下文
  167. * @return 版本号,如果获取失败返回 1
  168. */
  169. fun getCurrentVersionCode(context: Context): Int {
  170. return try {
  171. val packageManager = context.packageManager
  172. val packageInfo = packageManager.getPackageInfo(context.packageName, 0)
  173. // 使用 PackageInfoCompat 统一处理,兼容所有版本
  174. PackageInfoCompat.getLongVersionCode(packageInfo).toInt()
  175. } catch (e: PackageManager.NameNotFoundException) {
  176. // 记录异常
  177. LogHelper.e("VersionUpdateManager", "无法获取版本号", e)
  178. 1 // 默认版本号
  179. }
  180. }
  181. }