You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何在WearOS中以编程方式重启表盘服务?

如何在Wear OS中编程重启CanvasWatchFaceService?

这种手动切换表盘的体验确实糟心,尤其是用户重装应用后看到占位符的情况,我来分享几个可行的方案,帮你解决这个问题:

一、核心思路:主动触发表盘切换

系统在权限变更或应用重装后不会自动重启你的表盘服务,所以我们需要主动调用系统API来切换回自己的表盘,本质上是让系统重新绑定并启动你的CanvasWatchFaceService

1. 使用WatchFaceControlApi(推荐)

这个API是Wear OS官方推荐的切换表盘方式,不需要特殊系统权限,步骤如下:

首先,获取你的表盘服务的ComponentName

val myWatchFaceComponent = ComponentName(context, YourCanvasWatchFaceService::class.java)

然后编写切换逻辑:

private fun switchToMyWatchFace(context: Context) {
    val capabilityClient = Wearable.getCapabilityClient(context)
    // 获取支持表盘控制的可到达节点
    capabilityClient.getCapability("watch_face_control", CapabilityClient.FILTER_REACHABLE)
        .addOnSuccessListener { capabilityInfo ->
            if (capabilityInfo.nodes.isNotEmpty()) {
                val targetNode = capabilityInfo.nodes.first()
                val messageClient = Wearable.getMessageClient(context)
                // 发送切换表盘的消息
                messageClient.sendMessage(
                    targetNode.id,
                    "/trigger_watch_face_switch",
                    myWatchFaceComponent.flattenToString().toByteArray()
                )
            }
        }
}

接下来,在你的Wear端应用中监听这个消息,收到后调用系统API设置表盘:

class WatchFaceMessageListenerService : WearableListenerService() {
    override fun onMessageReceived(messageEvent: MessageEvent) {
        super.onMessageReceived(messageEvent)
        if (messageEvent.path == "/trigger_watch_face_switch") {
            val componentStr = String(messageEvent.data)
            val watchFaceComponent = ComponentName.unflattenFromString(componentStr)
            watchFaceComponent?.let {
                // 使用系统API设置表盘
                val intent = Intent(WatchFaceIntents.ACTION_SET_WATCH_FACE)
                    .putExtra(WatchFaceIntents.EXTRA_WATCH_FACE_COMPONENT, it)
                    .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
                startActivities(arrayOf(intent))
            }
        }
    }
}

别忘了在Manifest中注册这个服务:

<service android:name=".WatchFaceMessageListenerService">
    <intent-filter>
        <action android:name="com.google.android.gms.wearable.MESSAGE_RECEIVED" />
        <data android:scheme="wear" android:host="*" android:pathPrefix="/trigger_watch_face_switch" />
    </intent-filter>
</service>

2. 监听权限变更,自动触发重启

针对你提到的权限变更导致表盘崩溃或无法重启的问题,我们可以注册广播接收器监听权限变化,一旦权限状态改变,就主动切换回自己的表盘:

创建广播接收器:

class PermissionChangeReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context?, intent: Intent?) {
        if (intent?.action == Intent.ACTION_PERMISSION_CHANGED) {
            // 不管权限是授予还是收回,都触发表盘切换
            switchToMyWatchFace(context!!)
        }
    }
}

在Manifest中注册接收器:

<receiver android:name=".PermissionChangeReceiver">
    <intent-filter>
        <action android:name="android.intent.action.PERMISSION_CHANGED" />
    </intent-filter>
</receiver>

3. 应用重装后自动恢复表盘

在应用的启动Activity(比如Wear端的MainActivity)中,添加检查逻辑,判断当前是否是你的表盘在运行,如果不是就自动切换:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    checkCurrentWatchFaceAndSwitch()
}

private fun checkCurrentWatchFaceAndSwitch() {
    val resolver = contentResolver
    val currentWatchFaceStr = Settings.Secure.getString(resolver, Settings.Secure.WATCH_FACE)
    val myWatchFaceStr = ComponentName(this, YourCanvasWatchFaceService::class.java).flattenToString()
    
    if (currentWatchFaceStr != myWatchFaceStr) {
        switchToMyWatchFace(this)
    }
}

二、结合你的权限实验分析

从你的实验结果来看:

  • 单独关闭某一项权限时,系统会尝试重启表盘服务,所以能正常运行;
  • 全部权限关闭时,服务直接崩溃,系统不会自动重启,这时候就需要我们主动触发切换,让系统重新初始化服务;
  • 分步关闭权限并等待后再打开,系统有足够时间处理状态,所以能正常运行。

上面的方案刚好能覆盖这些场景:权限变更时自动触发切换,重装应用时启动检查切换,彻底解决手动操作的问题。

内容的提问来源于stack exchange,提问作者Alexey Kolosov

火山引擎 最新活动