Вы отправляете сообщения с помощью API MessageClient
и прикрепляете к сообщению следующие элементы:
- Необязательная произвольная полезная нагрузка
- Путь, который однозначно идентифицирует действие сообщения
В отличие от элементов данных, синхронизация между приложениями на мобильном устройстве и носимом устройстве не производится. Сообщения — это механизм односторонней связи, полезный для удалённых вызовов процедур (RPC), например, для отправки сообщения на носимое устройство для запуска какого-либо действия.
К одному портативному устройству пользователя можно подключить несколько носимых устройств. Каждое подключенное устройство в сети считается узлом .
При подключении нескольких устройств необходимо учитывать, какие узлы получают сообщения. Например, в приложении для транскрипции голоса, принимающем голосовые данные на носимом устройстве, отправьте сообщение узлу с достаточной вычислительной мощностью и ёмкостью аккумулятора для обработки запроса, например, портативному устройству.
Примечание: При указании деталей сообщения учитывайте возможность подключения нескольких узлов. Убедитесь, что сообщение доставляется на нужные устройства или узлы.
Примеры использования см. в следующем примере приложения: DataLayer
Отправить сообщение
Приложение для носимых устройств может предоставлять пользователям такие функции, как транскрипция голоса. Пользователи могут говорить в микрофон своего устройства и сохранять расшифровку в заметке. Поскольку носимое устройство обычно не обладает достаточной вычислительной мощностью и ёмкостью аккумулятора для выполнения транскрипции голоса, приложению необходимо переложить эту задачу на более мощное подключённое устройство.
В следующих разделах показано, как рекламировать узлы устройств, которые могут обрабатывать запросы активности, обнаруживать узлы, способные удовлетворить запрошенную потребность, и отправлять сообщения этим узлам.
Рекламные возможности
Чтобы запустить действие на мобильном устройстве с носимого устройства, используйте класс MessageClient
для отправки запроса. Поскольку к мобильному устройству можно подключить несколько носимых устройств, носимому приложению необходимо определить, способен ли подключенный узел запустить это действие. В мобильном приложении укажите, что узел, на котором оно запущено, предоставляет определенные возможности.
Чтобы рекламировать возможности вашего мобильного приложения, выполните следующие действия:
- Создайте XML-файл конфигурации в каталоге
res/values/
вашего проекта и назовите его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>
Извлечь узлы с требуемыми возможностями
Изначально вы можете определить доступные узлы, вызвав метод getCapability
класса CapabilityClient
. Для использования этого метода ваше приложение Wear OS и приложение для телефона должны иметь одинаковый идентификатор приложения. В следующем примере показано, как вручную получить результаты о доступных узлах с помощью возможности voice_transcription
:
Котлин
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) }
Ява
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); }
Внимание: Перед использованием API Wearable Data Layer убедитесь, что он доступен на устройстве; в противном случае возникнет исключение. Используйте класс GoogleApiAvailability
, как реализовано в Horologist .
Чтобы обнаружить доступные узлы при их подключении к носимому устройству, зарегистрируйте экземпляр прослушивателя, а именно OnCapabilityChangedListener
объекта CapabilityClient
. В следующем примере показано, как зарегистрировать прослушиватель и получить результат с доступными узлами, имеющими возможность voice_transcription
:
Котлин
private fun setupVoiceTranscription() { updateTranscriptionCapability(capabilityInfo).also { capabilityListener -> Wearable.getCapabilityClient(context).addListener( capabilityListener, VOICE_TRANSCRIPTION_CAPABILITY_NAME ) } }
Ява
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); }
После обнаружения подходящих узлов определите, куда отправить сообщение. Выберите узел, находящийся в непосредственной близости от вашего носимого устройства, чтобы минимизировать маршрутизацию сообщений через несколько узлов. Ближайшим узлом считается узел, напрямую подключенный к устройству. Чтобы определить, находится ли узел поблизости, например, подключен по Bluetooth, вызовите метод Node.isNearby()
. Если поблизости находится несколько узлов, выберите один из них произвольно; аналогично, если поблизости нет подходящих узлов, выберите подходящий узел произвольно.
В следующем примере показано, как можно определить лучший узел для использования:
Котлин
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 }
Ява
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
для передачи данных между устройствами.
Котлин
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 { ... } } } }
Ява
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, а также о том, когда следует использовать каждый из них, см . API задач .
Вы также можете рассылать сообщения всем подключённым узлам. Чтобы получить список всех подключённых узлов, которым можно отправлять сообщения, реализуйте следующий код:
Котлин
private fun getNodes(): Collection<String> { return Tasks.await(Wearable.getNodeClient(context).connectedNodes).map { it.id } }
Ява
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
, запустите действие для обработки голосовых данных.
Котлин
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) } }
Ява
@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); } }
Для этого кода требуется более подробная реализация. Подробнее о реализации полноценной службы или активности прослушивателя см. в статье Прослушивание событий уровня данных .