Отправляйте и получайте сообщения на Wear

Вы отправляете сообщения с помощью API MessageClient и прикрепляете к сообщению следующие элементы:

  • Дополнительная произвольная полезная нагрузка
  • Путь, который однозначно определяет действие сообщения.

В отличие от элементов данных, между портативными и носимыми приложениями синхронизация не происходит. Сообщения — это механизм односторонней связи, полезный для удаленных вызовов процедур (RPC), например отправки сообщения на носимое устройство для начала действия.

К портативному устройству пользователя можно подключить несколько носимых устройств. Каждое подключенное устройство в сети считается узлом .

При наличии нескольких подключенных устройств необходимо учитывать, какие узлы получают сообщения. Например, в приложении для транскрипции голоса, которое получает голосовые данные на носимое устройство, отправьте сообщение на узел с вычислительной мощностью и емкостью аккумулятора для обработки запроса, например на портативное устройство.

Примечание. При указании деталей вашего сообщения учитывайте возможность подключения нескольких узлов. Убедитесь, что сообщение доставлено на нужные устройства или узлы.

Примеры использования см. в следующем примере приложения: DataLayer.

Отправить сообщение

Носимое приложение может предоставлять пользователям такие функции, как транскрипция голоса. Пользователи могут говорить в микрофон своего носимого устройства и сохранять стенограмму в заметке. Поскольку носимое устройство обычно не имеет вычислительной мощности и емкости аккумулятора, необходимых для обработки транскрипции голоса, приложению необходимо переложить эту работу на более мощное подключенное устройство.

В следующих разделах показано, как объявлять узлы устройств, которые могут обрабатывать запросы активности, обнаруживать узлы, способные удовлетворить запрошенные потребности, и отправлять сообщения этим узлам.

Чтобы запустить действие на портативном устройстве с носимого устройства, используйте класс MessageClient для отправки запроса. Поскольку к портативному устройству можно подключить несколько носимых устройств, носимому приложению необходимо определить, способен ли подключенный узел запускать действие. В своем портативном приложении сообщите, что узел, на котором оно работает, предоставляет определенные возможности.

Чтобы рекламировать возможности вашего портативного приложения, выполните следующие действия:

  1. Создайте файл конфигурации XML в каталоге res/values/ вашего проекта и назовите его wear.xml .
  2. Добавьте ресурс с именем android_wear_capabilities в wear.xml .
  3. Определите возможности, которые предоставляет устройство.

Примечание. Возможности — это определяемые вами пользовательские строки, которые должны быть уникальными в вашем приложении.

В следующем примере показано, как добавить возможность с именем 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);
}

Чтобы обнаружить работоспособные узлы при их подключении к носимому устройству, зарегистрируйте экземпляр прослушивателя, а именно 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);
    }
}

Этот код требует более подробной информации о реализации. Узнайте, как реализовать полноценную службу или действие прослушивателя, в разделе «Прослушивание событий уровня данных» .