您可以使用 MessageClient
API 发送消息,并附加以下项目:
- 一个可选的任意负载
- 唯一标识消息操作的路径
与数据项不同,手持设备和可穿戴设备应用之间不会进行同步。消息是一种单向通信机制,适用于远程过程调用 (RPC),例如向可穿戴设备发送消息以启动 Activity。
用户的手持设备可以连接多个可穿戴设备。网络中的每个已连接设备都被视为一个 节点。
当有多个设备连接时,您必须考虑哪些节点会收到消息。例如,在接收可穿戴设备上的语音数据的语音转录应用中,将消息发送到具有处理请求所需的处理能力和电池容量的节点,例如手持设备。
注意:指定消息详情时,请考虑可能存在多个连接节点的情况。确保消息发送到预期的设备或节点。
请参阅以下示例应用获取使用示例: DataLayer
发送消息
可穿戴设备应用可以为用户提供功能,例如语音转录。用户可以通过可穿戴设备的麦克风说话,并将转录内容保存到笔记中。由于可穿戴设备通常不具备处理语音转录活动所需的处理能力和电池容量,因此应用需要将这项工作分流到功能更强大的已连接设备。
以下章节将向您展示如何宣传可以处理 Activity 请求的设备节点,发现能够满足请求需求的节点,以及如何向这些节点发送消息。
宣传功能
要从可穿戴设备在手持设备上启动 Activity,请使用 MessageClient
类发送请求。由于手持设备可以连接多个可穿戴设备,因此可穿戴设备应用需要确定连接的节点是否能够启动 Activity。在您的手持设备应用中,宣传它运行的节点提供特定的功能。
要宣传您的手持设备应用的功能,请执行以下操作:
- 在您的项目
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 services 的异步和同步调用以及何时使用它们,请参阅 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
,则启动 Activity 来处理语音数据。
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); } }
此代码需要更多实现细节。请参阅监听数据层事件了解如何实现完整的监听器服务或 Activity。