Wear OS闹钟应用:如何从AlarmManager/BroadcastReceiver启动闹钟Activity
针对Pixel Watch 2闹钟Activity无法显示的解决方案
核心问题分析
Pixel Watch 2基于Wear OS,系统低功耗策略和锁屏限制会拦截普通的Activity启动请求,尤其是应用处于后台或设备锁屏时。需要结合Wear OS特性调整权限、PendingIntent配置和通知策略。
1. 调整权限与Manifest配置
首先补充必要权限,并修正AlarmActivity的属性:
添加权限到AndroidManifest.xml
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" /> <uses-permission android:name="android.permission.USE_FULL_SCREEN_INTENT" /> <uses-permission android:name="android.permission.WAKE_LOCK" /> <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
修改AlarmActivity的Manifest配置
<activity android:name=".activities.AlarmActivity" android:exported="true" android:showWhenLocked="true" android:showOnLockScreen="true" android:taskAffinity="" android:noHistory="true" android:excludeFromRecents="true" android:launchMode="singleTop" android:turnScreenOn="true" android:screenOrientation="portrait" />
android:exported="true":允许系统服务(如AlarmManager)启动该Activity,避免后台拦截android:showOnLockScreen="true":适配Wear OS锁屏显示规则android:screenOrientation="portrait":匹配Watch的竖屏布局
2. 重构闹钟设置逻辑,结合全屏通知
Wear OS要求闹钟类应用通过全屏通知唤起锁屏Activity,单纯依赖AlarmManager的PendingIntent无法绕过系统限制。修改setAlarm函数:
val Context.alarmManager: AlarmManager get() = this.getSystemService(Context.ALARM_SERVICE) as AlarmManager fun setAlarm(context: Context, millis: Long) { val alarmManager = context.alarmManager if (!alarmManager.canScheduleExactAlarms()) { return } // 1. 创建启动AlarmActivity的PendingIntent val alarmActivityIntent = Intent(context, AlarmActivity::class.java).apply { flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_REORDER_TO_FRONT or Intent.FLAG_ACTIVITY_NO_USER_ACTION } val alarmPendingIntent = PendingIntent.getActivity( context, 2, alarmActivityIntent, PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT ) // 2. 创建全屏通知(Wear OS强制要求) val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { val channel = NotificationChannel( "ALARM_CHANNEL", "Alarm Notifications", NotificationManager.IMPORTANCE_HIGH ).apply { description = "Trigger alarm full-screen activity" setSound(null, null) // 可自定义闹钟铃声 } notificationManager.createNotificationChannel(channel) } val fullScreenPendingIntent = PendingIntent.getActivity( context, 3, alarmActivityIntent, PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT ) val alarmNotification = NotificationCompat.Builder(context, "ALARM_CHANNEL") .setSmallIcon(R.drawable.ic_alarm) // 替换为你的应用图标 .setContentTitle("闹钟已触发") .setContentText("点击查看闹钟") .setPriority(NotificationCompat.PRIORITY_HIGH) .setCategory(NotificationCompat.CATEGORY_ALARM) .setFullScreenIntent(fullScreenPendingIntent, true) .build() // 3. 设置精确闹钟(适配低功耗模式) alarmManager.setExactAndAllowWhileIdle( AlarmManager.RTC_WAKEUP, millis, alarmPendingIntent ) // 提前发送通知,确保系统能捕捉到全屏Intent notificationManager.notify(1001, alarmNotification) }
setExactAndAllowWhileIdle:确保闹钟在设备低功耗空闲时也能触发- 全屏通知的
setFullScreenIntent:触发时自动唤起AlarmActivity,绕过锁屏限制
3. 完善AlarmActivity的唤醒逻辑
在Activity中添加唤醒锁定,确保屏幕持续点亮直到用户处理:
class AlarmActivity : ComponentActivity() { private lateinit var wakeLock: PowerManager.WakeLock override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) logd("on create alarm activity") // 申请唤醒锁定,保持屏幕点亮 val powerManager = getSystemService(Context.POWER_SERVICE) as PowerManager wakeLock = powerManager.newWakeLock( PowerManager.SCREEN_BRIGHT_WAKE_LOCK or PowerManager.ACQUIRE_CAUSES_WAKEUP, "AlarmApp:AlarmWakeLock" ) wakeLock.acquire(10 * 60 * 1000L) // 锁定10分钟,可按需调整 setTheme(android.R.style.Theme_DeviceDefault) setContent { MyTheme { Box(modifier = Modifier.fillMaxSize()) { Text("Alarm!!") // 在此添加贪睡、关闭按钮的UI与逻辑 } } } setTurnScreenOn(true) setShowWhenLocked(true) } override fun onDestroy() { super.onDestroy() // 释放唤醒锁定 if (::wakeLock.isInitialized && wakeLock.isHeld) { wakeLock.release() } } }
PowerManager.ACQUIRE_CAUSES_WAKEUP:强制点亮屏幕- 主动释放唤醒锁:避免不必要的电量消耗
关键注意事项
- 测试时需关闭应用后台,确保设备处于锁屏状态,模拟真实场景
- Android 13+需动态申请
POST_NOTIFICATIONS权限,否则通知无法发送 - 避免使用
setAlarmClock,Wear OS对该API的支持存在兼容性问题,优先用setExactAndAllowWhileIdle
内容的提问来源于stack exchange,提问作者Kevin van Mierlo
相关产品推荐
相关产品推荐

