如何在BroadcastReceiver中唤醒设备?API兼容问题求助
解决BroadcastReceiver中无法唤醒设备的问题
错误根源
你遇到的java.lang.IllegalArgumentException: Must specify a valid wake lock level.是因为**WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON根本不是PowerManager WakeLock的合法级别**。这个Flag是用来给Activity或View设置"保持屏幕常亮"的,完全不能传递给PowerManager.newWakeLock()方法。
同时PowerManager.SCREEN_BRIGHT_WAKE_LOCK确实已被废弃,我们需要根据Android版本选择正确的唤醒方案:
正确实现方案
1. Android 12(API 31)及以上版本
从API 31开始,Google推荐使用更简洁的PowerManager.wakeUp()方法直接唤醒设备,无需创建WakeLock:
private fun wakeDevice(context: Context) { val powerManager = context.getSystemService(Context.POWER_SERVICE) as PowerManager // 先判断设备是否处于非交互状态(屏幕熄灭/锁屏) if (!powerManager.isInteractive) { // 唤醒设备,参数传当前时间戳即可,第二个参数是唤醒原因的标签 powerManager.wakeUp(System.currentTimeMillis(), "MyApp:NotificationWakeup") } }
2. Android 11(API 30)及以下版本
对于旧版本,我们可以使用未完全废弃的WakeLock级别,配合ACQUIRE_CAUSES_WAKEUP标志强制唤醒设备:
private fun wakeDevice(context: Context) { val powerManager = context.getSystemService(Context.POWER_SERVICE) as PowerManager // 用SCREEN_DIM_WAKE_LOCK(未废弃)加上ACQUIRE_CAUSES_WAKEUP标志,实现主动唤醒 val wakeLockLevel = PowerManager.SCREEN_DIM_WAKE_LOCK or PowerManager.ACQUIRE_CAUSES_WAKEUP val myWakeLock = powerManager.newWakeLock(wakeLockLevel, "MyApp:NotificationWakelockTag") // 持有WakeLock 5秒,确保用户能看到通知 myWakeLock.acquire(5 * 1000L) // 注意:带超时参数的acquire()会自动释放WakeLock,这里不用手动调用release() }
3. 兼容所有版本的整合写法
通过版本判断把两种方案结合起来:
private fun wakeDevice(context: Context) { val powerManager = context.getSystemService(Context.POWER_SERVICE) as PowerManager if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { if (!powerManager.isInteractive) { powerManager.wakeUp(System.currentTimeMillis(), "MyApp:NotificationWakeup") } } else { val wakeLockLevel = PowerManager.SCREEN_DIM_WAKE_LOCK or PowerManager.ACQUIRE_CAUSES_WAKEUP val myWakeLock = powerManager.newWakeLock(wakeLockLevel, "MyApp:NotificationWakelockTag") myWakeLock.acquire(5 * 1000L) } }
关键注意事项
- 权限确认:确保Manifest中已添加
WAKE_LOCK权限:
若你的应用需要在Android 13及以上显示通知,还需添加:<uses-permission android:name="android.permission.WAKE_LOCK" /><uses-permission android:name="android.permission.POST_NOTIFICATIONS" /> - WakeLock释放逻辑:使用
acquire(long timeout)时,系统会自动在超时后释放锁,不要提前调用release(),否则设备会立刻熄灭。 - 唤醒标志的必要性:
ACQUIRE_CAUSES_WAKEUP是主动唤醒熄灭设备的核心,没有这个标志,WakeLock只会保持屏幕常亮,无法唤醒已熄灭的设备。
内容的提问来源于stack exchange,提问作者Mikhail
相关产品推荐
相关产品推荐

