Android关机重启广播监听全解析:从原理到兼容性实现

📅 2026/7/31 8:28:52
Android关机重启广播监听全解析:从原理到兼容性实现
1. 项目概述为什么监听关机重启广播是个“技术活”在Android开发中监听系统广播是获取设备状态变化最直接、最常用的手段之一。无论是应用需要保存最后的状态还是服务需要在设备重启后自动拉起亦或是实现一些特殊的系统级功能都离不开对系统广播的监听。其中ACTION_SHUTDOWN关机广播和ACTION_REBOOT重启广播无疑是两个重量级的系统事件。乍一看这似乎是个简单的BroadcastReceiver注册问题但真正深入进去你会发现从权限申请、接收器注册方式、到不同Android版本的适配、乃至后台限制的规避每一步都藏着“坑”。很多开发者包括一些有经验的同行都曾在这里踩过雷——比如监听不到、接收延迟或者在Android 8.0API 26之后直接失效。今天我们就来彻底拆解这个“技术活”从原理到实践从兼容性到避坑指南手把手带你实现一个稳定可靠的关机重启监听方案。无论你是需要实现数据安全保存、服务保活还是开发系统工具类应用这篇文章都能给你提供可直接落地的参考。2. 核心原理与广播机制深度解析2.1 Android广播系统的工作机制要理解如何监听关机重启广播首先得明白Android的广播Broadcast系统是怎么运转的。你可以把它想象成一个全小区的大喇叭系统和每家每户的对讲机应用。当系统发生某个特定事件比如停电关机、物业通知重启电梯时大喇叭就会喊一嗓子。那些事先表示“我对停电通知感兴趣”的住户注册了对应BroadcastReceiver的应用他们的对讲机就会响起来。在技术层面这个过程涉及几个核心角色发送者BroadcastSender通常是Android系统框架ActivityManagerService等系统服务。对于关机重启发送者就是系统在关机/重启流程的某个环节。广播Intent这是一个携带了行动指令Action和可能附带数据Extras的消息对象。关机广播的Action是Intent.ACTION_SHUTDOWN重启广播的Action是Intent.ACTION_REBOOT。接收者BroadcastReceiver我们编写的用于响应特定广播的类。它只有一个核心方法onReceive(Context context, Intent intent)当匹配的广播到来时系统会调用这个方法。注册中心ActivityManagerService负责管理广播的发送和接收匹配。应用通过清单文件静态注册或代码动态注册向它“订阅”感兴趣的广播。对于关机重启这类有序广播Ordered Broadcast系统还会设定优先级Priority允许高优先级的接收者先接收甚至可以中止广播的继续传递虽然对于系统广播开发者通常无权中止。理解这个机制是后续解决监听问题的理论基础。2.2 关机与重启广播的独特性ACTION_SHUTDOWN和ACTION_REBOOT广播与普通的应用间广播有显著不同这也正是其监听复杂性的根源系统级权限它们是受保护的广播。从Android 3.1开始系统加强了对广播的限制许多系统广播不再能被第三方应用随意监听。关机重启广播正在此列。这意味着仅仅在清单文件中声明receiver是远远不够的。发送时机关键广播的发送时机非常靠前位于关机/重启流程的早期。系统会先发送广播然后再逐一关闭应用进程、卸载存储等。这给了应用一个短暂但宝贵的窗口期来执行紧急操作比如将内存中的关键数据刷入数据库或本地文件。但这个窗口期很短通常只有几秒钟所以onReceive方法中的操作必须轻量、快速绝对不允许执行耗时操作如网络请求。静态注册的局限性在Android 8.0之后谷歌为了优化系统性能和电池续航对后台执行施加了严格限制。其中一条就是大多数隐式广播implicit broadcast即不指定具体包名的广播不允许在清单文件中进行静态注册。而ACTION_SHUTDOWN和ACTION_REBOOT恰恰就是隐式广播。这意味着在Android 8.0及以上的设备上仅通过静态注册的接收器将完全无法收到这两个广播。这是一个至关重要的分水岭也是很多监听方案在新系统上失效的根本原因。3. 实现方案选型与适配策略面对不同Android版本的差异我们需要设计一个兼容性的方案。核心思路是静态注册与动态注册相结合并针对高版本系统进行特殊处理。3.1 方案一静态注册针对Android 8.0以下设备这是最传统、理论上最可靠的方式因为即使应用进程不在运行系统也能在发送广播时唤醒你的接收器。实现步骤在AndroidManifest.xml中声明接收器并申请权限uses-permission android:nameandroid.permission.SHUTDOWN / !-- 注意SHUTDOWN权限的protectionLevel是signature|privileged 普通应用无法直接获取但声明它有时是必要的具体见下文分析 -- application ... receiver android:name.ShutdownReceiver android:enabledtrue android:exportedtrue intent-filter android:priority1000 !-- 设置高优先级 -- action android:nameandroid.intent.action.ACTION_SHUTDOWN / action android:nameandroid.intent.action.ACTION_REBOOT / /intent-filter /receiver /application注意android.permission.SHUTDOWN是一个系统级签名权限signature|privileged。这意味着只有使用系统平台证书签名的应用即系统应用或预装在/system/分区的应用才能获得此权限。普通第三方应用声明此权限是无效的。那为什么我们还要声明在某些旧的或特定厂商定制的系统上系统检查可能不那么严格声明它可能有助于通过某些检查。但对于绝大多数标准设备监听的关键不在此权限而在于接收器能否被调用。实现BroadcastReceiver类class ShutdownReceiver : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { when (intent.action) { Intent.ACTION_SHUTDOWN - { Log.d(“ShutdownReceiver”, “设备正在关机...”) // 执行紧急保存操作例如 // 1. 将SharedPreferences提交commit不能用apply // 2. 关闭数据库连接并确保事务完成 // 3. 向持久化服务发送一个保存命令通过startService或发送有序广播 // 切记这里不能做任何异步或耗时操作 performEmergencySave(context) } Intent.ACTION_REBOOT - { Log.d(“ShutdownReceiver”, “设备正在重启...”) // 重启广播的处理逻辑通常与关机类似 performEmergencySave(context) } } } private fun performEmergencySave(context: Context) { // 示例同步保存状态到SharedPreferences val prefs context.getSharedPreferences(“app_state”, Context.MODE_PRIVATE) prefs.edit().putBoolean(“was_shutting_down”, true).commit() // 必须用commit // 可以发送一个启动服务的Intent但服务必须在onStartCommand中快速处理 val serviceIntent Intent(context, EmergencySaveService::class.java) context.startService(serviceIntent) } }此方案的局限性如前所述在Android 8.0 (API 26) 及以上针对隐式广播的静态注册限制将导致此接收器失效。用户关机时你的应用将收不到任何通知。3.2 方案二动态注册应对Android 8.0的限制为了绕过高版本的限制我们必须让应用进程在关机事件发生时是活跃的并通过代码动态注册广播接收器。动态注册的广播接收器其生命周期与注册它的组件如Activity、Service绑定。核心思路创建一个前台服务Foreground Service在该服务的onCreate()中动态注册关机重启广播的接收器。只要服务保持运行接收器就有效。实现步骤创建一个前台服务class ShutdownMonitorService : Service() { private lateinit var shutdownReceiver: BroadcastReceiver override fun onCreate() { super.onCreate() // 创建广播接收器实例 shutdownReceiver object : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { handleShutdownOrReboot(context, intent) } } // 动态注册接收器 val filter IntentFilter().apply { addAction(Intent.ACTION_SHUTDOWN) addAction(Intent.ACTION_REBOOT) priority IntentFilter.SYSTEM_HIGH_PRIORITY // 尝试设置高优先级 } registerReceiver(shutdownReceiver, filter) // 启动前台服务避免被系统杀死 startForegroundService() } private fun startForegroundService() { if (Build.VERSION.SDK_INT Build.VERSION_CODES.O) { val channel NotificationChannel( “shutdown_monitor_channel”, “关机监听服务”, NotificationManager.IMPORTANCE_LOW ).apply { description “用于监听设备关机重启事件” } (getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager) .createNotificationChannel(channel) val notification Notification.Builder(this, “shutdown_monitor_channel”) .setContentTitle(“运行中”) .setContentText(“正在监听关机重启事件”) .setSmallIcon(R.drawable.ic_notification) .build() startForeground(1, notification) // 通知ID必须非零 } } override fun onBind(intent: Intent): IBinder? null override fun onDestroy() { super.onDestroy() // 务必在服务销毁时解注册防止内存泄漏 unregisterReceiver(shutdownReceiver) } }在AndroidManifest.xml中声明服务并请求前台服务权限uses-permission android:nameandroid.permission.FOREGROUND_SERVICE / !-- Android 9 还需要注意电源白名单策略 -- application ... service android:name.ShutdownMonitorService android:enabledtrue android:exportedfalse / !-- 通常不需要导出 -- !-- 保留静态接收器用于兼容旧版本 -- receiver android:name.ShutdownReceiver” ... ... /receiver /application在应用启动时如主Activity或Application类中启动该服务// 在MainActivity的onCreate或自定义Application的onCreate中 val intent Intent(this, ShutdownMonitorService::class.java) if (Build.VERSION.SDK_INT Build.VERSION_CODES.O) { startForegroundService(intent) } else { startService(intent) }此方案的挑战服务保活即使用前台服务在极端内存压力下或用户强制停止后服务仍可能被杀死。一旦服务进程死亡动态注册的接收器自然失效。用户体验前台服务会显示一个常驻通知可能引起用户反感用户可能会手动关闭通知或禁止应用后台运行。厂商限制不同手机厂商小米、华为、OPPO、vivo等有各自的后台启动管理和省电策略可能会阻止你的服务长期存活。3.3 方案三双保险策略与厂商适配在实际生产环境中最稳健的做法是采用“静态注册兜底 动态注册增强 厂商白名单引导”的组合拳。兼容性判断与自动选择在应用启动时判断系统版本。fun setupShutdownMonitor(context: Context) { // 始终尝试启动动态监听服务针对Android 8.0 startShutdownMonitorService(context) // 对于Android 8.0以下的设备静态接收器是主力。 // 对于Android 8.0静态接收器虽然系统限制不调用但保留无妨。 // 动态服务是主要监听手段。 }处理onReceive中的紧急操作无论通过哪种方式接收到广播onReceive中的逻辑都必须遵循“快速、同步、持久化”的原则。一个常见的模式是在onReceive中立即向一个IntentService或JobIntentService发送一个命令将耗时的保存操作转移到另一个线程但前提是这个Service必须能极大概率在进程被杀死前完成任务。更可靠的做法是在onReceive中直接进行同步的文件写入或数据库提交。应对厂商后台限制引导用户添加电池白名单在应用内检测到是特定厂商设备时友好地提示用户去系统设置中将你的应用加入“电池优化忽略名单”、“允许后台活动”等白名单。这能大幅提升服务存活率。使用厂商推送通道保活一些厂商提供了自己的推送服务如小米推送、华为推送接入后可以利用其系统级通道来间接感知设备状态变化但这并非直接监听关机广播。使用AlarmManager设置精确闹钟结合RTC_WAKEUP类型的闹钟可以定期唤醒应用检查服务是否存活若死亡则重新启动。但这需要SCHEDULE_EXACT_ALARM权限Android 12需要单独申请且策略需谨慎设计避免耗电。4. 实操过程与核心代码实现让我们整合一个完整的、考虑兼容性的实现示例。这个示例包含一个静态接收器用于旧系统、一个动态监听服务用于新系统、以及一个处理实际保存逻辑的IntentService。4.1 核心组件定义1. 静态广播接收器 (LegacyShutdownReceiver)// 主要用于 API 25 及以下 class LegacyShutdownReceiver : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { Log.i(“ShutdownMonitor”, “Legacy Receiver: ${intent.action}”) // 立即启动一个IntentService来处理保存利用其独立工作线程 val serviceIntent Intent(context, EmergencySaveService::class.java).apply { this.action intent.action } context.startService(serviceIntent) // 关键如果知道是关机重启可以尝试发送一个有序广播 // 让高优先级的系统组件先处理但这需要系统级权限普通应用作用有限。 // abortBroadcast() // 普通应用通常无法中止系统有序广播 } }2. 紧急保存服务 (EmergencySaveService)// 继承自IntentService它在后台线程执行任务执行完毕后自动停止。 class EmergencySaveService : IntentService(“EmergencySaveService”) { override fun onHandleIntent(intent: Intent?) { intent?.action?.let { action - Log.w(“EmergencySaveService”, “紧急保存触发动作: $action”) // 在这里执行实际的保存逻辑 saveCriticalData() // 例如关闭数据库连接提交所有Pending的事务 // 例如将内存缓存写入文件 // 注意所有操作必须是同步的、本地的。 } } private fun saveCriticalData() { // 示例同步写入文件 try { val file File(filesDir, “last_state.json”) file.writeText(“{\“shutdown_time\”: \”${System.currentTimeMillis()}\”}”) // 强制同步到磁盘 val fos FileOutputStream(file) fos.fd.sync() fos.close() } catch (e: Exception) { Log.e(“EmergencySaveService”, “保存数据失败”, e) } } }3. 动态监听前台服务 (ShutdownMonitorForegroundService)class ShutdownMonitorForegroundService : Service() { private var dynamicReceiver: BroadcastReceiver? null override fun onCreate() { super.onCreate() Log.d(“ShutdownMonitor”, “前台监听服务启动”) startForegroundNotification() registerDynamicReceiver() // 可以在这里初始化一些需要长期持有的资源 } private fun startForegroundNotification() { if (Build.VERSION.SDK_INT Build.VERSION_CODES.O) { val channel NotificationChannel( “monitor_channel”, “系统事件监听”, NotificationManager.IMPORTANCE_LOW ).apply { lockscreenVisibility Notification.VISIBILITY_SECRET } // 可设置锁屏不可见 getSystemService(NotificationManager::class.java).createNotificationChannel(channel) } val notification NotificationCompat.Builder(this, “monitor_channel”) .setContentTitle(“系统服务运行中”) .setContentText(“正在监听关机等系统事件”) .setSmallIcon(R.drawable.ic_system_monitor) // 使用一个合适的、用户可接受的图标 .setPriority(NotificationCompat.PRIORITY_LOW) .setOngoing(true) .build() startForeground(NOTIFICATION_ID, notification) } private fun registerDynamicReceiver() { dynamicReceiver object : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { Log.i(“ShutdownMonitor”, “Dynamic Receiver: ${intent.action}”) // 同样启动IntentService处理 val saveIntent Intent(context, EmergencySaveService::class.java).apply { this.action intent.action } context.startService(saveIntent) } }.also { receiver - val filter IntentFilter().apply { addAction(Intent.ACTION_SHUTDOWN) addAction(Intent.ACTION_REBOOT) // 可以尝试监听其他相关广播如屏幕关闭、电源连接等作为辅助判断 addAction(Intent.ACTION_SCREEN_OFF) priority 1000 // 设置高优先级 } registerReceiver(receiver, filter) } } override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { // 返回START_STICKY服务被异常杀死后系统会尝试重启服务但不保证立即重启 return START_STICKY } override fun onDestroy() { dynamicReceiver?.let { unregisterReceiver(it) } Log.d(“ShutdownMonitor”, “前台监听服务停止”) super.onDestroy() } override fun onBind(intent: Intent): IBinder? null companion object { private const val NOTIFICATION_ID 1001 fun startService(context: Context) { val intent Intent(context, ShutdownMonitorForegroundService::class.java) if (Build.VERSION.SDK_INT Build.VERSION_CODES.O) { context.startForegroundService(intent) } else { context.startService(intent) } } } }4.2 清单文件配置?xml version“1.0” encoding“utf-8”? manifest xmlns:android“http://schemas.android.com/apk/res/android” !-- 声明前台服务权限 (Android 9.0) -- uses-permission android:name“android.permission.FOREGROUND_SERVICE” / !-- 声明关机权限尽管普通应用无效但保留以示用途某些定制系统可能需要 -- uses-permission android:name“android.permission.SHUTDOWN” / application android:allowBackup“true” android:icon“mipmap/ic_launcher” android:label“string/app_name” android:supportsRtl“true” !-- 静态接收器用于兼容旧版Android -- receiver android:name“.LegacyShutdownReceiver” android:enabled“true” android:exported“true” intent-filter android:priority“1000” action android:name“android.intent.action.ACTION_SHUTDOWN” / action android:name“android.intent.action.ACTION_REBOOT” / !-- 某些设备或ROM可能使用其他Action可按需添加 -- !-- action android:name“android.intent.action.QUICKBOOT_POWEROFF” / -- !-- HTC等 -- /intent-filter /receiver !-- 紧急保存服务 -- service android:name“.EmergencySaveService” android:exported“false” / !-- 动态监听前台服务 -- service android:name“.ShutdownMonitorForegroundService” android:enabled“true” android:exported“false” android:stopWithTask“false” / !-- 防止被任务管理器清理时连带停止 -- activity android:name“.MainActivity” intent-filter action android:name“android.intent.action.MAIN” / category android:name“android.intent.category.LAUNCHER” / /intent-filter /activity /application /manifest4.3 应用初始化与保活策略在应用的入口点例如主Activity或自定义Application类启动监听服务并实施简单的保活策略。class MyApplication : Application() { override fun onCreate() { super.onCreate() initShutdownMonitor() setupKeepAlive() } private fun initShutdownMonitor() { // 无论版本都尝试启动前台服务动态监听 ShutdownMonitorForegroundService.startService(this) // 静态接收器已在清单中声明系统会自动管理 Log.d(“MyApp”, “关机重启监听器初始化完成”) } private fun setupKeepAlive() { // 简单的保活注册一个监听网络状态或时间变化的广播 // 当服务意外停止时尝试重新启动需谨慎使用避免耗电 val keepAliveReceiver object : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { // 检查前台服务是否在运行如果不在则重新启动 if (!isServiceRunning(context, ShutdownMonitorForegroundService::class.java)) { Log.w(“MyApp”, “监听服务已停止尝试重启”) ShutdownMonitorForegroundService.startService(context) } } } val filter IntentFilter().apply { addAction(ConnectivityManager.CONNECTIVITY_ACTION) // 网络变化 addAction(Intent.ACTION_TIME_TICK) // 每分钟一次慎用 } registerReceiver(keepAliveReceiver, filter) // 注意需要在合适的时机如应用退出主界面时解注册此接收器避免内存泄漏。 // 更复杂的保活策略需结合JobScheduler或WorkManager进行定时检查。 } private fun isServiceRunning(context: Context, serviceClass: Class*): Boolean { val manager context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager Suppress(“DEPRECATION”) return manager.getRunningServices(Integer.MAX_VALUE).any { it.service.className serviceClass.name } } }5. 常见问题、排查技巧与厂商适配实录即使代码写得再完美在实际设备上测试时你仍可能遇到各种“玄学”问题。下面是我在实际项目中踩过的坑和总结的排查经验。5.1 监听完全失效症状无论是静态还是动态接收器都收不到关机/重启广播。排查步骤检查系统版本首先确认设备是否是Android 8.0。如果是静态注册失效是预期行为必须依赖动态注册。检查服务存活对于动态注册确保ShutdownMonitorForegroundService正在运行。可以通过adb shell dumpsys activity services | grep your.package.name命令查看。如果服务没起来检查是否成功调用了startForegroundService并快速调用了startForeground。在Android 8.0startForegroundService后必须在数秒内调用startForeground否则会引发ANR且服务被停止。检查厂商后台限制这是最大的“坑”。进入手机“设置”-“应用”-“你的应用”-“电池”或“权限”-“后台管理”。查看是否被限制了后台活动。小米的“神隐模式”、华为的“启动管理”、OPPO/vivo的“后台冻结”等都可能阻止你的服务长期运行。解决方案在应用内添加检测逻辑引导用户手动去设置页开启“允许后台运行”、“允许自启动”、“忽略电池优化”等选项。检查广播Action极少数设备或定制ROM可能使用了非标准的Action字符串。可以尝试在Logcat中过滤“android.intent.action”关键词观察关机时系统到底发出了哪些广播。有时ACTION_SHUTDOWN可能被替换或额外发送了其他广播。使用adb命令模拟广播在设备开机状态下通过adb发送广播来测试接收器是否正常工作。adb shell am broadcast -a android.intent.action.ACTION_SHUTDOWN注意模拟的广播可能无法完全模拟真实关机流程但可以验证接收器注册和基本逻辑是否正确。5.2 监听不稳定时好时坏症状有时能收到广播有时收不到尤其是在设备长时间休眠后。可能原因与解决进程被杀死动态注册的接收器依附于进程。如果应用进程被系统或安全软件“清理”了接收器自然失效。确保你的前台服务通知持续存在并且引导用户将应用加入白名单。省电模式系统全局的省电模式如“低电量模式”、“超级省电模式”会严格限制后台活动。在这种模式下你的服务很可能被挂起或限制运行。需要在代码中检测省电模式并提示用户功能可能受限。使用AlarmManager进行心跳保活设置一个不频繁的、RTC_WAKEUP类型的Alarm例如每30分钟一次在闹钟接收器中检查服务状态并重启。但自Android 6.0的Doze模式和App Standby特性推出后Alarm也会被推迟。Android 10对setExactAndAllowWhileIdle也有频率限制。5.3 收到广播但保存操作未完成症状日志显示onReceive被调用了但数据没有成功保存。关键原因BroadcastReceiver的onReceive方法运行在主线程且系统只给予很短的时间通常10秒左右但实际更短。如果在其中执行耗时操作系统可能会强制结束你的进程。解决方案绝对异步使用goAsync()API 11来获取更多处理时间但依然要快。转移任务最佳实践是在onReceive中立即启动一个IntentService或使用JobIntentService.enqueueWork()兼容旧版。IntentService会在独立工作线程处理任务且会尽量完成onHandleIntent中的工作即使应用进程随后被杀死。同步保存对于最关键的数据在onReceive中直接使用同步、阻塞的方式写入。例如用SharedPreferences.Editor.commit()而不是apply用FileOutputStream写入文件后调用FileDescriptor.sync()强制刷盘。5.4 厂商特定问题与白名单引导代码示例不同厂商的后台管理策略名称和入口不同。这里提供一个简单的工具类用于检测并跳转到常见厂商的后台设置页注意这些URI可能随系统版本更新而失效需要持续维护。object BatteryOptimizationUtil { fun isIgnoringBatteryOptimizations(context: Context): Boolean { if (Build.VERSION.SDK_INT Build.VERSION_CODES.M) { val powerManager context.getSystemService(Context.POWER_SERVICE) as PowerManager return powerManager.isIgnoringBatteryOptimizations(context.packageName) } return true // 低于M版本无此限制 } fun requestIgnoreBatteryOptimizations(activity: Activity, requestCode: Int) { if (Build.VERSION.SDK_INT Build.VERSION_CODES.M) { if (!isIgnoringBatteryOptimizations(activity)) { val intent Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS).apply { data Uri.parse(“package:” activity.packageName) } // 注意频繁请求此权限可能导致应用被商店下架或用户反感。 // 仅在功能确实需要且解释清楚后使用。 activity.startActivityForResult(intent, requestCode) } } } fun goToManufacturerBackgroundSetting(activity: Activity) { val intent Intent() intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) when { isXiaomi() - { // 小米 intent.component ComponentName(“com.miui.securitycenter”, “com.miui.permcenter.autostart.AutoStartManagementActivity”) } isHuawei() - { // 华为 intent.component ComponentName(“com.huawei.systemmanager”, “com.huawei.systemmanager.startupmgr.ui.StartupNormalAppListActivity”) } isOppo() - { // OPPO intent.component ComponentName(“com.coloros.safecenter”, “com.coloros.safecenter.permission.startup.StartupAppListActivity”) } isVivo() - { // Vivo intent.component ComponentName(“com.vivo.permissionmanager”, “com.vivo.permissionmanager.activity.BgStartUpManagerActivity”) } else - { // 其他设备跳转到系统应用信息页用户手动寻找“电池”或“后台”选项 intent.action Settings.ACTION_APPLICATION_DETAILS_SETTINGS intent.data Uri.parse(“package:” activity.packageName) } } try { activity.startActivity(intent) } catch (e: Exception) { // 组件可能不存在跳转到通用设置页 intent.action Settings.ACTION_APPLICATION_DETAILS_SETTINGS intent.data Uri.parse(“package:” activity.packageName) activity.startActivity(intent) } } // 简单的厂商判断基于Build.MANUFACTURER或Build.BRAND private fun isXiaomi(): Boolean Build.MANUFACTURER.equals(“xiaomi”, ignoreCase true) private fun isHuawei(): Boolean Build.MANUFACTURER.equals(“huawei”, ignoreCase true) private fun isOppo(): Boolean Build.MANUFACTURER.equals(“oppo”, ignoreCase true) || Build.BRAND.equals(“realme”, ignoreCase true) // realme通常也适用OPPO设置 private fun isVivo(): Boolean Build.MANUFACTURER.equals(“vivo”, ignoreCase true) }在你的应用设置页面或首次启动引导中可以这样使用// 检查电池优化 if (!BatteryOptimizationUtil.isIgnoringBatteryOptimizations(this)) { // 显示一个解释性对话框说明监听关机需要忽略电池优化然后调用 // BatteryOptimizationUtil.requestIgnoreBatteryOptimizations(this, REQUEST_CODE_IGNORE_OPTIMIZATION) } // 引导用户去设置后台自启动/关联启动 showDialog(“为了确保关机时能保存数据请允许应用在后台运行”) { BatteryOptimizationUtil.goToManufacturerBackgroundSetting(thisMainActivity) }5.5 测试策略测试关机重启监听非常麻烦因为不可能频繁重启真机。可以采用以下策略单元测试测试BroadcastReceiver的onReceive逻辑和IntentService的保存逻辑。集成测试ADB模拟使用adb shell am broadcast命令发送广播验证接收和后续服务启动流程。真机有限测试在少数几台关键测试设备覆盖不同Android版本和厂商上进行实际关机重启测试。测试前务必通过logcat或写入特定文件的方式记录关键日志开机后检查日志或文件是否生成。模拟器测试Android模拟器可以方便地重启但要注意模拟器的系统行为可能与真机有差异尤其是厂商定制部分。监听Android关机重启广播是一个典型的“原理简单实现坎坷”的需求。它要求开发者不仅理解广播机制更要深刻认识Android系统在不同版本、不同厂商设备上的后台行为限制。最可靠的方案永远是动态注册的前台服务 引导用户添加电池和后台白名单 在onReceive中极简且同步的持久化操作。同时要做好功能降级的准备因为在高限制环境下无法保证100%的成功率。在实际项目中我们往往需要将这种监听作为数据安全策略的一部分而不是唯一依赖结合定期自动保存等其他机制共同保障数据的完整性。