feat(ota): OTA APK 下载更新模块
REQ-20260430-0041 新增 UpdateManager: - POST newAppVersion/queryWatch 检查版本(5分钟最小间隔) - OkHttp 下载 APK(进度回调,独立超时配置) - FileProvider + Intent ACTION_VIEW 触发系统安装 - 非 .apk 链接自动跳过 新增 UpdateDialogView: - 全屏覆盖弹窗,三种状态(发现新版本/下载中/下载失败) - 进度条支持百分比和未知大小两种模式 配置变更: - AndroidManifest: REQUEST_INSTALL_PACKAGES + FileProvider - CommonApi.checkVersion: GET→POST,传 version 参数 集成点: - HomeFragment.onResume → MainActivity.checkForUpdate() - MainActivity 管理弹窗交互和下载流程 - 更新时停止蓝牙扫描 + 保持屏幕常亮 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -9,9 +9,13 @@ import androidx.appcompat.app.AppCompatActivity
|
||||
import com.xiaoqu.watch.databinding.ActivityMainBinding
|
||||
import com.xiaoqu.watch.event.AppEvent
|
||||
import com.xiaoqu.watch.event.EventBus
|
||||
import com.xiaoqu.watch.device.screen.ScreenController
|
||||
import com.xiaoqu.watch.device.sensor.AccelerometerWakeController
|
||||
import com.xiaoqu.watch.service.manager.BluetoothScanManager
|
||||
import com.xiaoqu.watch.service.manager.NotificationManager
|
||||
import com.xiaoqu.watch.service.manager.SystemStateMonitor
|
||||
import com.xiaoqu.watch.service.manager.UpdateManager
|
||||
import com.xiaoqu.watch.ui.widget.UpdateDialogView
|
||||
import com.xiaoqu.watch.ui.widget.NotificationBannerView
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
@@ -37,6 +41,12 @@ class MainActivity : AppCompatActivity() {
|
||||
@Inject lateinit var eventBus: EventBus
|
||||
/** 加速度计抬手亮屏控制器 */
|
||||
@Inject lateinit var accelerometerWake: AccelerometerWakeController
|
||||
/** OTA 更新管理器 */
|
||||
@Inject lateinit var updateManager: UpdateManager
|
||||
@Inject lateinit var screenController: ScreenController
|
||||
@Inject lateinit var bluetoothScanManager: BluetoothScanManager
|
||||
/** OTA 更新弹窗 */
|
||||
lateinit var updateDialog: UpdateDialogView
|
||||
lateinit var notificationBanner: NotificationBannerView
|
||||
private val activityScope = CoroutineScope(Dispatchers.Main + SupervisorJob())
|
||||
|
||||
@@ -70,6 +80,10 @@ class MainActivity : AppCompatActivity() {
|
||||
// 初始化通知横幅
|
||||
notificationBanner = binding.notificationBanner
|
||||
|
||||
// 初始化 OTA 更新弹窗
|
||||
updateDialog = binding.updateDialog
|
||||
setupUpdateDialog()
|
||||
|
||||
// 监听 MQTT type=1 → 处理通知 + 显示横幅
|
||||
observeMqttMessages()
|
||||
|
||||
@@ -166,4 +180,64 @@ class MainActivity : AppCompatActivity() {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// ===== OTA 更新 =====
|
||||
|
||||
/** 设置更新弹窗按钮回调 */
|
||||
private fun setupUpdateDialog() {
|
||||
updateDialog.onActionClick = {
|
||||
startDownloadAndInstall()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查版本更新(由 HomeFragment.onResume 调用)
|
||||
* 有更新时显示弹窗,停止蓝牙扫描
|
||||
*/
|
||||
fun checkForUpdate() {
|
||||
if (updateManager.isUpdating) return
|
||||
activityScope.launch {
|
||||
val info = updateManager.checkUpdate() ?: return@launch
|
||||
// 停止蓝牙扫描
|
||||
bluetoothScanManager.stop()
|
||||
// 显示更新弹窗
|
||||
updateDialog.showDiscover()
|
||||
// 保存下载地址
|
||||
pendingUpdateUrl = info.url
|
||||
}
|
||||
}
|
||||
|
||||
/** 待下载的更新 URL */
|
||||
private var pendingUpdateUrl: String? = null
|
||||
|
||||
/** 开始下载并安装 APK */
|
||||
private fun startDownloadAndInstall() {
|
||||
val url = pendingUpdateUrl ?: return
|
||||
updateManager.isUpdating = true
|
||||
// 保持屏幕常亮
|
||||
screenController.turnOn()
|
||||
// 切换到下载状态
|
||||
updateDialog.showDownloading()
|
||||
|
||||
activityScope.launch {
|
||||
val file = updateManager.downloadApk(url) { progress, bytes ->
|
||||
// 进度回调在 IO 线程,切回主线程更新 UI
|
||||
launch(kotlinx.coroutines.Dispatchers.Main) {
|
||||
updateDialog.updateProgress(progress, bytes)
|
||||
}
|
||||
}
|
||||
|
||||
// 回到主线程处理结果
|
||||
kotlinx.coroutines.withContext(kotlinx.coroutines.Dispatchers.Main) {
|
||||
if (file != null) {
|
||||
// 下载成功 → 触发安装
|
||||
updateManager.installApk(file)
|
||||
} else {
|
||||
// 下载失败 → 显示错误
|
||||
updateManager.isUpdating = false
|
||||
updateDialog.showError()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user