From 20a0389b07f365ab518ea8c3ac01392913b478c4 Mon Sep 17 00:00:00 2001 From: dongliang Date: Mon, 11 May 2026 11:40:15 +0930 Subject: [PATCH] =?UTF-8?q?fix:=20=E7=A7=BB=E9=99=A4=E5=89=8D=E5=8F=B0?= =?UTF-8?q?=E6=9C=8D=E5=8A=A1/=E7=94=B5=E6=B1=A0=E7=99=BD=E5=90=8D?= =?UTF-8?q?=E5=8D=95/AlarmManager=EF=BC=8C=E6=81=A2=E5=A4=8D=E6=97=A7?= =?UTF-8?q?=E7=89=88MQTT=E7=9B=B4=E8=BF=9E=E6=96=B9=E6=A1=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 定制ROM+Launcher应用不会被系统杀死,保活机制是多余的耗电源头。 回到和旧版一样的方案:SplashFragment直连MQTT + Paho自动重连。 Co-Authored-By: Claude Opus 4.6 (1M context) --- app/src/main/AndroidManifest.xml | 15 --- .../java/com/xiaoqu/watch/app/BootReceiver.kt | 14 +-- .../java/com/xiaoqu/watch/app/MainActivity.kt | 33 ----- .../xiaoqu/watch/service/MqttAlarmReceiver.kt | 76 ----------- .../com/xiaoqu/watch/service/MqttService.kt | 119 ------------------ .../xiaoqu/watch/ui/common/SplashFragment.kt | 11 +- 6 files changed, 5 insertions(+), 263 deletions(-) delete mode 100644 app/src/main/java/com/xiaoqu/watch/service/MqttAlarmReceiver.kt delete mode 100644 app/src/main/java/com/xiaoqu/watch/service/MqttService.kt diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index e495bb6..c48d569 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -27,11 +27,6 @@ - - - - - @@ -79,11 +74,6 @@ android:resource="@xml/file_paths" /> - - - - diff --git a/app/src/main/java/com/xiaoqu/watch/app/BootReceiver.kt b/app/src/main/java/com/xiaoqu/watch/app/BootReceiver.kt index 40e0a74..9a72564 100644 --- a/app/src/main/java/com/xiaoqu/watch/app/BootReceiver.kt +++ b/app/src/main/java/com/xiaoqu/watch/app/BootReceiver.kt @@ -3,27 +3,17 @@ package com.xiaoqu.watch.app import android.content.BroadcastReceiver import android.content.Context import android.content.Intent -import com.xiaoqu.watch.service.MqttAlarmReceiver -import com.xiaoqu.watch.service.MqttService import timber.log.Timber /** * 开机自启广播接收器 - * 收到 BOOT_COMPLETED 后启动 MQTT 服务 + MainActivity + * 收到 BOOT_COMPLETED 后启动 MainActivity(MQTT 在 SplashFragment 中连接) */ class BootReceiver : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { if (intent.action == Intent.ACTION_BOOT_COMPLETED) { - Timber.d("Boot completed, starting MqttService + MainActivity") - - // 先启动 MQTT 前台服务(尽早恢复连接) - MqttService.start(context) - - // 启动连接健康检查定时器 - MqttAlarmReceiver.schedule(context) - - // 启动主界面 + Timber.d("Boot completed, launching MainActivity") val launchIntent = Intent(context, MainActivity::class.java).apply { addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) } diff --git a/app/src/main/java/com/xiaoqu/watch/app/MainActivity.kt b/app/src/main/java/com/xiaoqu/watch/app/MainActivity.kt index 1058729..c5c042b 100644 --- a/app/src/main/java/com/xiaoqu/watch/app/MainActivity.kt +++ b/app/src/main/java/com/xiaoqu/watch/app/MainActivity.kt @@ -1,12 +1,7 @@ package com.xiaoqu.watch.app -import android.content.Intent import android.content.pm.ActivityInfo -import android.net.Uri -import android.os.Build import android.os.Bundle -import android.os.PowerManager -import android.provider.Settings import android.view.MotionEvent import android.view.View import androidx.navigation.findNavController @@ -98,9 +93,6 @@ class MainActivity : AppCompatActivity() { // 监听 MQTT type=1 → 处理通知 + 显示横幅 observeMqttMessages() - // 请求电池优化白名单(绕过 Doze 模式限制) - requestBatteryWhitelist() - Timber.d("MainActivity created") } @@ -235,31 +227,6 @@ class MainActivity : AppCompatActivity() { } } - // ===== 电池优化白名单 ===== - - /** - * 请求加入电池优化白名单(Doze 模式下允许后台网络访问) - * 已在白名单中则跳过,避免重复弹窗 - */ - private fun requestBatteryWhitelist() { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - val pm = getSystemService(PowerManager::class.java) - if (!pm.isIgnoringBatteryOptimizations(packageName)) { - try { - val intent = Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS).apply { - data = Uri.parse("package:$packageName") - } - startActivity(intent) - Timber.d("电池白名单: 已请求") - } catch (e: Exception) { - Timber.w(e, "电池白名单: 请求失败") - } - } else { - Timber.d("电池白名单: 已在白名单中") - } - } - } - // ===== OTA 更新 ===== /** 设置更新弹窗按钮回调 */ diff --git a/app/src/main/java/com/xiaoqu/watch/service/MqttAlarmReceiver.kt b/app/src/main/java/com/xiaoqu/watch/service/MqttAlarmReceiver.kt deleted file mode 100644 index d2b24f4..0000000 --- a/app/src/main/java/com/xiaoqu/watch/service/MqttAlarmReceiver.kt +++ /dev/null @@ -1,76 +0,0 @@ -package com.xiaoqu.watch.service - -import android.app.AlarmManager -import android.app.PendingIntent -import android.content.BroadcastReceiver -import android.content.Context -import android.content.Intent -import android.os.SystemClock -import com.xiaoqu.watch.service.manager.MqttManager -import dagger.hilt.android.AndroidEntryPoint -import timber.log.Timber -import javax.inject.Inject - -/** - * MQTT 连接健康检查广播接收器 - * - * 通过 AlarmManager 定期触发(不强制唤醒,等系统维护窗口), - * 检查 MQTT 连接状态,断连则重连。 - * 同时确保 MqttService 前台服务存活。 - */ -@AndroidEntryPoint -class MqttAlarmReceiver : BroadcastReceiver() { - - companion object { - /** 检查间隔:15 分钟(减少唤醒频率,前台服务+电池白名单已足够保活) */ - private const val CHECK_INTERVAL_MS = 15 * 60 * 1000L - - /** 启动定时健康检查 */ - fun schedule(context: Context) { - val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager - val intent = Intent(context, MqttAlarmReceiver::class.java) - val pendingIntent = PendingIntent.getBroadcast( - context, 0, intent, - PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE - ) - - // 不唤醒设备,等系统下次维护窗口时执行(省电) - alarmManager.set( - AlarmManager.ELAPSED_REALTIME, // 不强制唤醒 - SystemClock.elapsedRealtime() + CHECK_INTERVAL_MS, - pendingIntent - ) - Timber.d("MqttAlarm: 已设置 ${CHECK_INTERVAL_MS / 1000}s 后检查") - } - - /** 取消定时检查 */ - fun cancel(context: Context) { - val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager - val intent = Intent(context, MqttAlarmReceiver::class.java) - val pendingIntent = PendingIntent.getBroadcast( - context, 0, intent, - PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE - ) - alarmManager.cancel(pendingIntent) - Timber.d("MqttAlarm: 已取消定时检查") - } - } - - @Inject lateinit var mqttManager: MqttManager - - override fun onReceive(context: Context, intent: Intent) { - Timber.d("MqttAlarm: 健康检查触发, isConnected=${mqttManager.isConnected}") - - // 确保前台服务在运行 - MqttService.start(context) - - // MQTT 断连则重连 - if (!mqttManager.isConnected) { - Timber.w("MqttAlarm: 连接已断开,触发重连") - mqttManager.connect() - } - - // 重新设置下一次闹钟(setExactAndAllowWhileIdle 是一次性的) - schedule(context) - } -} diff --git a/app/src/main/java/com/xiaoqu/watch/service/MqttService.kt b/app/src/main/java/com/xiaoqu/watch/service/MqttService.kt deleted file mode 100644 index 82fd5f6..0000000 --- a/app/src/main/java/com/xiaoqu/watch/service/MqttService.kt +++ /dev/null @@ -1,119 +0,0 @@ -package com.xiaoqu.watch.service - -import android.app.Notification -import android.app.NotificationChannel -import android.app.NotificationManager -import android.app.Service -import android.content.Context -import android.content.Intent -import android.os.Build -import android.os.IBinder -import com.xiaoqu.watch.R -import com.xiaoqu.watch.service.manager.MqttManager -import dagger.hilt.android.AndroidEntryPoint -import timber.log.Timber -import javax.inject.Inject - -/** - * MQTT 前台服务 - * - * 保持 MQTT 连接在息屏/Doze 模式下不被系统杀死。 - * 通过 startForegroundService() 启动,显示常驻通知。 - * 不持有永久 WakeLock(省电),依赖: - * - 前台服务:防止进程被杀 - * - 电池白名单:绕过 Doze 网络限制 - * - Paho 库内置心跳机制:自动维护连接 - * - AlarmManager 健康检查:兜底重连 - */ -@AndroidEntryPoint -class MqttService : Service() { - - companion object { - /** 通知渠道 ID */ - private const val CHANNEL_ID = "mqtt_service" - /** 前台通知 ID */ - private const val NOTIFICATION_ID = 1 - - /** 启动服务 */ - fun start(context: Context) { - val intent = Intent(context, MqttService::class.java) - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - context.startForegroundService(intent) - } else { - context.startService(intent) - } - } - - /** 停止服务 */ - fun stop(context: Context) { - context.stopService(Intent(context, MqttService::class.java)) - } - } - - @Inject lateinit var mqttManager: MqttManager - - override fun onCreate() { - super.onCreate() - Timber.d("MqttService: onCreate") - - // 创建通知渠道 - createNotificationChannel() - - // 启动前台服务(必须在 5 秒内调用,否则 ANR) - startForeground(NOTIFICATION_ID, buildNotification()) - - // 连接 MQTT(Paho 库内部会管理自己的心跳和重连) - mqttManager.connect() - } - - override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { - Timber.d("MqttService: onStartCommand") - // 如果连接断了,重新连接 - if (!mqttManager.isConnected) { - mqttManager.connect() - } - // 被杀后自动重启 - return START_STICKY - } - - override fun onDestroy() { - super.onDestroy() - Timber.d("MqttService: onDestroy") - mqttManager.disconnect() - } - - override fun onBind(intent: Intent?): IBinder? = null - - /** 创建通知渠道(Android 8.0+) */ - private fun createNotificationChannel() { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - val channel = NotificationChannel( - CHANNEL_ID, - "消息连接", - NotificationManager.IMPORTANCE_LOW // 低优先级,不发声不振动 - ).apply { - description = "保持消息连接在线" - setShowBadge(false) - } - val nm = getSystemService(NotificationManager::class.java) - nm.createNotificationChannel(channel) - } - } - - /** 构建前台通知(常驻,低优先级) */ - private fun buildNotification(): Notification { - val builder = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - Notification.Builder(this, CHANNEL_ID) - } else { - @Suppress("DEPRECATION") - Notification.Builder(this) - } - return builder - .setSmallIcon(R.mipmap.ic_launcher) - .setContentTitle("小趣智清洁") - .setContentText("消息连接中") - .setOngoing(true) - .build() - } - -} diff --git a/app/src/main/java/com/xiaoqu/watch/ui/common/SplashFragment.kt b/app/src/main/java/com/xiaoqu/watch/ui/common/SplashFragment.kt index ea82b15..130b84d 100644 --- a/app/src/main/java/com/xiaoqu/watch/ui/common/SplashFragment.kt +++ b/app/src/main/java/com/xiaoqu/watch/ui/common/SplashFragment.kt @@ -13,8 +13,6 @@ import com.xiaoqu.watch.data.prefs.UserPrefs import com.xiaoqu.watch.network.ApiResult import com.xiaoqu.watch.network.api.CommonApi import com.xiaoqu.watch.network.safeApiCall -import com.xiaoqu.watch.service.MqttAlarmReceiver -import com.xiaoqu.watch.service.MqttService import com.xiaoqu.watch.service.manager.MqttManager import com.xiaoqu.watch.util.DeviceUtil import dagger.hilt.android.AndroidEntryPoint @@ -49,13 +47,10 @@ class SplashFragment : Fragment() { // 1. 初始化设备信息(首次启动时写入 SP) initDevicePrefs() - // 2. 启动 MQTT 前台服务(保持息屏后连接存活) - MqttService.start(requireContext()) + // 2. 连接 MQTT(定制 ROM + Launcher 应用,系统不会杀进程) + mqttManager.connect() - // 3. 启动连接健康检查定时器(Doze 模式下定期检查) - MqttAlarmReceiver.schedule(requireContext()) - - // 4. 检查绑定状态并导航 + // 3. 检查绑定状态并导航 checkBindStatus() }