You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

带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
    }
}

排查关键点

  1. Direct Boot模式下的数据库访问权限

    • ACTION_LOCKED_BOOT_COMPLETED触发时处于Direct Boot模式,默认Room数据库存储在设备加密区,此时无法访问。
    • 解决:使用Context.createDeviceProtectedStorageContext()获取上下文初始化数据库,将闹钟数据存储到凭据加密区。
  2. 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)
      
  3. 广播接收器的兼容性配置

    • 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>
      
  4. 补充监听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>
      
  5. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 16:45:43