Wear OS开发:如何实现手表离线时仍可触发的跨设备提醒?
解决方案:手表本地独立提醒 + 在线同步手机
你的核心需求是手表离线(手机关机)时仍能触发提醒,同时配对手机在线时也能同步触发,之前依赖手机在线插入日历的方案显然不满足需求。下面是可行的实现思路:
1. 手表端实现本地独立提醒
Wear OS 无法直接通过 CalendarContract 插入本地日历事件(手表日历默认同步手机端,无本地写入权限),需用本地定时任务框架实现独立提醒,推荐用 WorkManager(兼容低版本,支持后台执行):
用 WorkManager 实现单次提醒
// 手表端代码 import android.content.Context import androidx.core.app.NotificationCompat import androidx.core.app.NotificationManagerCompat import androidx.work.OneTimeWorkRequestBuilder import androidx.work.WorkManager import androidx.work.Worker import androidx.work.WorkerParameters import androidx.work.workDataOf import java.util.concurrent.TimeUnit // 提醒触发时的执行器 class WearReminderWorker(context: Context, params: WorkerParameters) : Worker(context, params) { override fun doWork(): Result { val title = inputData.getString("title") ?: "待办提醒" showWearNotification(title) return Result.success() } private fun showWearNotification(title: String) { // 构建Wear OS专属通知,支持手表交互 val notification = NotificationCompat.Builder(applicationContext, "WEAR_REMINDER_CHANNEL") .setContentTitle(title) .setSmallIcon(R.drawable.ic_reminder) .setPriority(NotificationCompat.PRIORITY_HIGH) .setCategory(NotificationCompat.CATEGORY_ALARM) .build() NotificationManagerCompat.from(applicationContext).notify( (System.currentTimeMillis() % 10000).toInt(), notification ) } } // 调度手表本地提醒的方法 fun scheduleWearReminder(context: Context, title: String, triggerTime: Long) { val delayMillis = triggerTime - System.currentTimeMillis() if (delayMillis <= 0) return val workRequest = OneTimeWorkRequestBuilder<WearReminderWorker>() .setInitialDelay(delayMillis, TimeUnit.MILLISECONDS) .setInputData(workDataOf("title" to title)) .build() WorkManager.getInstance(context).enqueue(workRequest) }
手表端权限配置
在Manifest中添加必要权限:
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" /> <uses-permission android:name="android.permission.WAKE_LOCK" /> <!-- 可选,确保提醒唤醒手表屏幕 -->
2. 在线时同步提醒到手机
当手表与手机连接时,将提醒数据同步到手机,手机端接收后创建本地提醒,确保手机开机后也能触发:
手表端发送同步消息(用MessageClient更高效)
// 手表端代码 import com.google.android.gms.wearable.MessageClient import com.google.android.gms.wearable.Wearable fun syncReminderToPhone(context: Context, title: String, triggerTime: Long) { // 空nodeId表示发送到所有配对设备 Wearable.getMessageClient(context).sendMessage( "", "/sync_reminder", "$title|$triggerTime".toByteArray() ) }
手机端接收并创建本地提醒
实现 WearableListenerService 接收消息,用 AlarmManager 设置精确闹钟:
// 手机端代码 import android.app.AlarmManager import android.app.PendingIntent import android.content.BroadcastReceiver import android.content.Context import android.content.Intent import androidx.core.app.NotificationCompat import androidx.core.app.NotificationManagerCompat import com.google.android.gms.wearable.MessageEvent import com.google.android.gms.wearable.WearableListenerService class ReminderSyncService : WearableListenerService() { override fun onMessageReceived(messageEvent: MessageEvent) { super.onMessageReceived(messageEvent) if (messageEvent.path == "/sync_reminder") { val data = String(messageEvent.data).split("|") val title = data[0] val triggerTime = data[1].toLong() schedulePhoneReminder(this, title, triggerTime) } } private fun schedulePhoneReminder(context: Context, title: String, triggerTime: Long) { val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager val intent = Intent(context, PhoneReminderReceiver::class.java).apply { putExtra("title", title) } val pendingIntent = PendingIntent.getBroadcast( context, (triggerTime % 10000).toInt(), intent, PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT ) // 设置精确闹钟,支持待机时触发 alarmManager.setExactAndAllowWhileIdle( AlarmManager.RTC_WAKEUP, triggerTime, pendingIntent ) } } // 手机端提醒触发接收器 class PhoneReminderReceiver : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { val title = intent.getStringExtra("title") ?: "同步提醒" val notification = NotificationCompat.Builder(context, "PHONE_REMINDER_CHANNEL") .setContentTitle(title) .setSmallIcon(R.drawable.ic_notification) .setPriority(NotificationCompat.PRIORITY_HIGH) .build() NotificationManagerCompat.from(context).notify( (System.currentTimeMillis() % 10000).toInt(), notification ) } }
手机端Manifest配置
<service android:name=".ReminderSyncService" android:exported="true"> <intent-filter> <action android:name="com.google.android.gms.wearable.MESSAGE_RECEIVED" /> <data android:host="*" android:pathPrefix="/sync_reminder" android:scheme="wear" /> </intent-filter> </service> <receiver android:name=".PhoneReminderReceiver" />
3. 针对你之前无效方案的说明
- WearableCalendarContract:该Contract为只读接口,仅用于查询同步到手表的日历数据,不支持插入/修改操作,抛出异常是正常行为。
- 手表端直接用CalendarContract:手表端的CalendarProvider仅同步手机端数据,无本地写入权限,即使调用insert不抛异常,数据也不会生效。
- 调用手机提醒APP的API:Android无公开系统API直接调用第三方提醒APP,仅能通过隐式Intent打开APP的添加页面,无法自动创建提醒。
最终执行流程
- 用户在手表APP创建提醒时,先调用
scheduleWearReminder安排手表本地提醒。 - 检查手表与手机的连接状态,若在线则调用
syncReminderToPhone同步数据到手机。 - 手表离线时,本地WorkManager到点触发提醒;手机在线时接收同步数据创建闹钟,开机后到点触发。
内容的提问来源于stack exchange,提问作者John Poust
相关产品推荐
相关产品推荐

