您可以使用 MessageClient
API 发送消息,并将以下项目附加到消息中
- 可选的任意有效负载
- 唯一标识消息操作的路径
与数据项不同,手持设备和可穿戴设备应用之间不会发生同步。消息是一种单向通信机制,可用于远程过程调用 (RPC),例如向可穿戴设备发送消息以启动活动。
多个可穿戴设备可以连接到用户的手机设备。网络中的每个连接设备都被视为一个节点。
对于多个连接的设备,您必须考虑哪些节点接收消息。例如,在可穿戴设备上接收语音数据的语音转录应用中,将消息发送到具有处理能力和电池容量以处理请求的节点,例如手持设备。
注意:在指定消息详细信息时,请考虑多个连接节点的可能性。确保消息传递到预期的设备或节点。
请参阅以下示例应用以获取使用示例: DataLayer
发送消息
可穿戴设备应用可以为用户提供功能,例如语音转录。用户可以对着可穿戴设备的麦克风说话,并将转录内容保存到笔记中。由于可穿戴设备通常没有处理语音转录活动所需的处理能力和电池容量,因此应用需要将此工作卸载到功能更强大的连接设备上。
以下部分将向您展示如何宣传可以处理活动请求的设备节点、发现能够满足请求需求的节点以及向这些节点发送消息。
宣传功能
要从可穿戴设备启动手持设备上的活动,请使用 MessageClient
类发送请求。由于多个可穿戴设备可以连接到手持设备,因此可穿戴设备应用需要确定连接的节点是否能够启动活动。在您的手持设备应用中,宣传其运行所在的节点提供了特定的功能。
要宣传手持设备应用的功能,请执行以下操作
- 在项目的
res/values/
目录中创建一个 XML 配置文件,并将其命名为wear.xml
。 - 将名为
android_wear_capabilities
的资源添加到wear.xml
中。 - 定义设备提供的功能。
注意:功能是您定义的自定义字符串,必须在您的应用中唯一。
以下示例显示了如何将名为 voice_transcription
的功能添加到 wear.xml
中
<resources xmlns:tools="http://schemas.android.com/tools" tools:keep="@array/android_wear_capabilities"> <string-array name="android_wear_capabilities"> <item>voice_transcription</item> </string-array> </resources>
检索具有所需功能的节点
最初,您可以通过调用 CapabilityClient
类的 getCapability
方法来检测功能节点。要使用此方法,您的 Wear OS 应用和手机应用必须具有相同的应用 ID。以下示例显示了如何手动检索具有 voice_transcription
功能的可到达节点的结果
Kotlin
private const val VOICE_TRANSCRIPTION_CAPABILITY_NAME = "voice_transcription" ... private fun setupVoiceTranscription() { val capabilityInfo: CapabilityInfo = Tasks.await( Wearable.getCapabilityClient(context) .getCapability( VOICE_TRANSCRIPTION_CAPABILITY_NAME, CapabilityClient.FILTER_REACHABLE ) ) // capabilityInfo has the reachable nodes with the transcription capability updateTranscriptionCapability(capabilityInfo) }
Java
private static final String VOICE_TRANSCRIPTION_CAPABILITY_NAME = "voice_transcription"; ... private void setupVoiceTranscription() { CapabilityInfo capabilityInfo = Tasks.await( Wearable.getCapabilityClient(context).getCapability( VOICE_TRANSCRIPTION_CAPABILITY_NAME, CapabilityClient.FILTER_REACHABLE)); // capabilityInfo has the reachable nodes with the transcription capability updateTranscriptionCapability(capabilityInfo); }
要检测连接到可穿戴设备的功能节点,请注册侦听器实例,特别是 CapabilityClient
对象的 OnCapabilityChangedListener
。以下示例显示了如何注册侦听器并检索具有 voice_transcription
功能的可到达节点的结果
Kotlin
private fun setupVoiceTranscription() { updateTranscriptionCapability(capabilityInfo).also { capabilityListener -> Wearable.getCapabilityClient(context).addListener( capabilityListener, VOICE_TRANSCRIPTION_CAPABILITY_NAME ) } }
Java
private void setupVoiceTranscription() { ... // This example uses a Java 8 Lambda. You can use named or anonymous classes. CapabilityClient.OnCapabilityChangedListener capabilityListener = capabilityInfo -> { updateTranscriptionCapability(capabilityInfo); }; Wearable.getCapabilityClient(context).addListener( capabilityListener, VOICE_TRANSCRIPTION_CAPABILITY_NAME); }
检测到功能节点后,确定发送消息的位置。选择靠近可穿戴设备的节点以最大程度地减少通过多个节点的消息路由。附近的节点定义为直接连接到设备的节点。要确定节点是否在附近(例如通过蓝牙连接),请调用 Node.isNearby()
方法。如果有多个节点在附近,则任意选择一个;类似地,如果没有功能节点在附近,则任意选择一个功能节点。
以下示例显示了如何确定要使用的最佳节点
Kotlin
private var transcriptionNodeId: String? = null private fun updateTranscriptionCapability(capabilityInfo: CapabilityInfo) { transcriptionNodeId = pickBestNodeId(capabilityInfo.nodes) } private fun pickBestNodeId(nodes: Set<Node>): String? { // Find a nearby node or pick one arbitrarily. return nodes.firstOrNull { it.isNearby }?.id ?: nodes.firstOrNull()?.id }
Java
private String transcriptionNodeId = null; private void updateTranscriptionCapability(CapabilityInfo capabilityInfo) { Set<Node> connectedNodes = capabilityInfo.getNodes(); transcriptionNodeId = pickBestNodeId(connectedNodes); } private String pickBestNodeId(Set<Node> nodes) { String bestNodeId = null; // Find a nearby node or pick one arbitrarily. for (Node node : nodes) { if (node.isNearby()) { return node.getId(); } bestNodeId = node.getId(); } return bestNodeId; }
传递消息
确定要使用的节点后,请使用 MessageClient
类发送消息。
以下示例显示了如何从可穿戴设备向支持转录的节点发送消息。此调用是同步的,并在系统将消息排队以进行传递之前阻塞处理。
注意:成功的结果代码不能保证消息传递。如果您的应用需要数据可靠性,请考虑使用 DataItem
对象或 ChannelClient
类在设备之间发送数据。
Kotlin
const val VOICE_TRANSCRIPTION_MESSAGE_PATH = "/voice_transcription" ... private fun requestTranscription(voiceData: ByteArray) { transcriptionNodeId?.also { nodeId -> val sendTask: Task<*> = Wearable.getMessageClient(context).sendMessage( nodeId, VOICE_TRANSCRIPTION_MESSAGE_PATH, voiceData ).apply { addOnSuccessListener { ... } addOnFailureListener { ... } } } }
Java
public static final String VOICE_TRANSCRIPTION_MESSAGE_PATH = "/voice_transcription"; private void requestTranscription(byte[] voiceData) { if (transcriptionNodeId != null) { Task<Integer> sendTask = Wearable.getMessageClient(context).sendMessage( transcriptionNodeId, VOICE_TRANSCRIPTION_MESSAGE_PATH, voiceData); // You can add success and/or failure listeners, // Or you can call Tasks.await() and catch ExecutionException sendTask.addOnSuccessListener(...); sendTask.addOnFailureListener(...); } else { // Unable to retrieve node with transcription capability } }
注意:要详细了解对 Google Play 服务的异步和同步调用以及何时使用每个调用,请参阅 Tasks API。
您还可以向所有连接的节点广播消息。要检索可以向其发送消息的所有连接节点,请实现以下代码
Kotlin
private fun getNodes(): Collection<String> { return Tasks.await(Wearable.getNodeClient(context).connectedNodes).map { it.id } }
Java
private Collection<String> getNodes() { HashSet <String>results = new HashSet<String>(); List<Node> nodes = Tasks.await(Wearable.getNodeClient(context).getConnectedNodes()); for (Node node : nodes.getNodes()) { results.add(node.getId()); } return results; }
接收消息
要接收消息通知,请实现MessageClient.OnMessageReceivedListener
接口以提供消息事件的监听器。然后,使用addListener
方法注册监听器。以下示例演示了如何实现监听器以检查VOICE_TRANSCRIPTION_MESSAGE_PATH
。如果此条件为true
,则启动一个活动来处理语音数据。
Kotlin
fun onMessageReceived(messageEvent: MessageEvent) { if (messageEvent.path == VOICE_TRANSCRIPTION_MESSAGE_PATH) { val startIntent = Intent(this, MainActivity::class.java).apply { addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) putExtra("VOICE_DATA", messageEvent.data) } startActivity(this, startIntent) } }
Java
@Override public void onMessageReceived(MessageEvent messageEvent) { if (messageEvent.getPath().equals(VOICE_TRANSCRIPTION_MESSAGE_PATH)) { Intent startIntent = new Intent(this, MainActivity.class); startIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startIntent.putExtra("VOICE_DATA", messageEvent.getData()); startActivity(this, startIntent); } }
此代码需要更多实现细节。了解如何在监听数据层事件中实现完整的监听器服务或活动。