Enviar e receber mensagens no Wear

A API MessageClient pode ser usada para enviar mensagens e anexar os itens abaixo a elas:

  • Um payload arbitrário opcional
  • Um caminho que identifique de forma exclusiva a ação da mensagem.

Ao contrário do caso de itens de dados, não ocorre sincronização entre os apps de dispositivos móveis e de wearables. As mensagens são um mecanismo de comunicação unidirecional útil para chamadas de procedimento remoto (RPC), como uma mensagem enviada ao wearable para iniciar uma atividade.

Vários dispositivos wearable podem ser conectados ao dispositivo portátil de um usuário. Cada dispositivo conectado à rede é considerado um .

Com vários dispositivos conectados, você precisa considerar quais nós recebem as mensagens. Por exemplo, em um app de transcrição de voz que recebe dados de voz no dispositivo wearable, envie a mensagem para um nó com o poder de processamento e a capacidade de bateria para processar a solicitação, como um dispositivo portátil.

Observação: ao especificar os detalhes da mensagem, considere a possibilidade de existirem vários nós conectados. Garanta que a mensagem seja entregue aos dispositivos ou nós esperados.

Consulte o app de exemplo abaixo para conferir exemplos de uso: Camada de dados

Enviar uma mensagem

Um app para wearables pode fornecer funcionalidade para os usuários, como a transcrição de voz. O usuário pode falar no microfone do dispositivo wearable e ter a transcrição salva em formato de nota. Como um dispositivo wearable normalmente não tem o poder de processamento e a capacidade da bateria necessários para processar a atividade de transcrição de voz, o app precisa transferir esse trabalho para um dispositivo conectado mais potente.

As próximas seções mostram como anunciar nós de dispositivos que podem processar solicitações de atividades, descobrir os nós capazes de atender uma necessidade de solicitação e enviar mensagens para esses nós.

Para iniciar uma atividade em um dispositivo portátil usando um wearable, use a classe MessageClient para enviar a solicitação. Como vários wearables podem ser conectados ao dispositivo portátil, o app para wearables precisa determinar se um nó conectado é capaz de iniciar a atividade. No app para dispositivos portáteis, anuncie que o nó em que ele é executado tem recursos específicos.

Para anunciar os recursos do app para dispositivos portáteis, faça o seguinte:

  1. Crie um arquivo de configuração XML no diretório res/values/ do seu projeto e dê o nome wear.xml a ele.
  2. Adicione um recurso com o nome android_wear_capabilities ao arquivo wear.xml.
  3. Defina os recursos que o dispositivo oferece.

Observação: recursos são strings personalizadas que você define e precisam ser únicos dentro do app.

O exemplo abaixo mostra como adicionar um recurso com o nome voice_transcription ao arquivo 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>

Extrair nós com os recursos necessários

Inicialmente, você pode detectar os nós compatíveis chamando o método getCapability da classe CapabilityClient. Para usar esse método, o app para Wear OS e o app para smartphones precisam ter o mesmo ID do aplicativo. O exemplo abaixo mostra como extrair manualmente os resultados dos nós ao alcance com o recurso 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);
}

Para detectar nós compatíveis conforme eles forem conectados ao dispositivo wearable, registre uma instância de um listener, mais especificamente, um OnCapabilityChangedListener de um objeto CapabilityClient. O exemplo abaixo mostra como registrar o listener e extrair um resultado com nós ao alcance que têm o recurso 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);
}

Depois de detectar os nós compatíveis, determine o destino da mensagem. Escolha um nó que esteja próximo ao seu dispositivo wearable para minimizar o roteamento de mensagens por vários nós. Um nó próximo é um nó que está diretamente conectado ao dispositivo. Para determinar se um nó está próximo (por exemplo, conectado via Bluetooth), chame o método Node.isNearby(). Se houver mais de um nó próximo, escolha um arbitrariamente. Da mesma forma, se houver um nó compatível por perto, escolha um arbitrariamente.

O exemplo abaixo mostra como você pode determinar o melhor nó para usar:

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;
}

Entregar a mensagem

Depois de identificar um nó para usar, envie a mensagem usando a classe MessageClient.

O exemplo abaixo mostra como enviar uma mensagem para o nó compatível com transcrições usando um dispositivo wearable. Essa chamada é síncrona e bloqueia o processamento até o sistema colocar a mensagem na fila de entrega.

Observação: um código de resultado bem-sucedido não garante a entrega da mensagem. Se o app exigir confiabilidade de dados, use objetos DataItem ou a classe ChannelClient para enviar dados entre dispositivos.

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
    }
}

Observação: para saber mais sobre chamadas síncronas e assíncronas para o Google Play Services e quando usar cada uma delas, consulte a API Tasks.

Você também pode transmitir mensagens para todos os nós conectados. Para extrair todos os nós conectados aos quais você pode enviar mensagens, implemente o código abaixo:

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;
}

Receber uma mensagem

Para mostrar notificações de mensagens recebidas, implemente a interface MessageClient.OnMessageReceivedListener para fornecer um listener para eventos de mensagem. Em seguida, registre o listener com o método addListener. O exemplo abaixo mostra como implementar o listener para verificar o VOICE_TRANSCRIPTION_MESSAGE_PATH. Se essa condição for true, inicie uma atividade para processar os dados de voz.

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);
    }
}

Esse código requer mais detalhes de implementação. Aprenda como implementar uma atividade ou um serviço completo de listener em Ouvir eventos de camada de dados.