带PIN/图案/密码锁时,开机广播重设闹钟失效问题求助
问题排查:带锁屏时设备重启后闹钟失效
核心需求:设置闹钟后设备重启,即使未解锁设备,闹钟仍需在指定时间响起。
问题现象:
- 无PIN/图案/密码锁(仅滑动或无锁)时功能正常
- 存在PIN/图案/密码锁时,即便用户解锁设备,闹钟也不会响起
已做配置:
- 给相关组件添加
android:directBootAware="true" - 申请
android.permission.RECEIVE_BOOT_COMPLETED权限 - 监听
ACTION_LOCKED_BOOT_COMPLETED广播
相关代码
Android清单文件(敏感信息已移除)
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="[REDACTED]"> <uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" /> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> <uses-permission android:name="android.permission.USE_FULL_SCREEN_INTENT" /> <uses-permission android:name="android.permission.VIBRATE" /> <uses-permission android:name="android.permission.POST_NOTIFICATIONS" /> <application android:name=".app.AlarmApplication" android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="[REDACTED]"> <activity android:name=".features.alarmring.RingActivity" android:exported="false" /> <activity android:name=".features.mainscreen.MainActivity" android:exported="true" android:showOnLockScreen="true"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <receiver android:name=".features.alarmscheduling.AlarmBroadcastReceiver" android:directBootAware="true" android:exported="false"> </receiver> <receiver android:directBootAware="true" android:name=".features.alarmscheduling.RescheduleOnBootBroadcastReceiver" android:exported="false"> <intent-filter> <action android:name="android.intent.action.LOCKED_BOOT_COMPLETED" /> </intent-filter> </receiver> <service android:name=".features.alarmring.AlarmService" /> <service android:name=".features.alarmscheduling.RescheduleOnBootService" /> </application> </manifest>
RescheduleOnBootBroadcastReceiver代码
class RescheduleOnBootBroadcastReceiver : BroadcastReceiver() { override fun onReceive(context: Context?, intent: Intent?) { if (intent?.action == Intent.ACTION_LOCKED_BOOT_COMPLETED) { Toast.makeText(context, "Reschedule on reboot received", Toast.LENGTH_SHORT).show() startRescheduleOnBootService(context) } } private fun startRescheduleOnBootService(context: Context?) { val intentService = Intent(context, RescheduleOnBootService::class.java) context?.startForegroundService(intentService) } }
RescheduleOnBootService代码
class RescheduleOnBootService : LifecycleService() { override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { super.onStartCommand(intent, flags, startId) val db = AlarmDatabase.getDatabase(applicationContext) val repository = AlarmRepository(db.alarmDao()) repository.allAlarms.asLiveData().observe(this) { alarms -> for (alarm in alarms) { if (alarm.isOn) scheduleAlarm(applicationContext, alarm) } } return START_STICKY } override fun onBind(intent: Intent): IBinder? { super.onBind(intent) return null } }
排查关键点
Direct Boot模式下的数据库访问权限
ACTION_LOCKED_BOOT_COMPLETED触发时处于Direct Boot模式,默认Room数据库存储在设备加密区,此时无法访问。- 解决:使用
Context.createDeviceProtectedStorageContext()获取上下文初始化数据库,将闹钟数据存储到凭据加密区。
ForegroundService的通知强制要求
- Android 12+中,调用
startForegroundService()后必须在5秒内调用startForeground()显示通知,否则系统会终止服务。当前服务未实现此逻辑,导致重启调度失败。 - 解决:在
onStartCommand开头添加前台通知代码,示例:val notification = NotificationCompat.Builder(this, "ALARM_CHANNEL") .setSmallIcon(R.drawable.ic_alarm) .setContentTitle("恢复闹钟设置") .setContentText("正在重新调度重启前的闹钟") .setPriority(NotificationCompat.PRIORITY_LOW) .build() startForeground(1, notification)
- Android 12+中,调用
广播接收器的兼容性配置
RescheduleOnBootBroadcastReceiver设为android:exported="false",部分厂商ROM可能无法正常接收系统广播。建议改为true并添加权限过滤:<receiver android:directBootAware="true" android:name=".features.alarmscheduling.RescheduleOnBootBroadcastReceiver" android:exported="true"> <intent-filter> <action android:name="android.intent.action.LOCKED_BOOT_COMPLETED" /> </intent-filter> <permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> </receiver>
补充监听ACTION_BOOT_COMPLETED
- 若Direct Boot模式下调度失败,解锁后系统会发送
ACTION_BOOT_COMPLETED广播,当前接收器未监听该事件,导致无重试机会。建议同时添加该动作:<intent-filter> <action android:name="android.intent.action.LOCKED_BOOT_COMPLETED" /> <action android:name="android.intent.action.BOOT_COMPLETED" /> </intent-filter>
- 若Direct Boot模式下调度失败,解锁后系统会发送
RingActivity的锁屏显示配置
- 当前仅
MainActivity配置了锁屏显示属性,RingActivity需要添加以下属性才能在锁屏时正常弹出:<activity android:name=".features.alarmring.RingActivity" android:exported="false" android:showOnLockScreen="true" android:showWhenLocked="true" android:turnScreenOn="true" />
- 当前仅
内容的提问来源于stack exchange,提问作者Alex Bolgarov
相关产品推荐
相关产品推荐

