Wysyłanie i odbieranie wiadomości na Wear

Wysyłasz wiadomości za pomocą interfejsu API MessageClient i dołączasz do nich te elementy:

  • Opcjonalny ładunek dowolny
  • Ścieżka jednoznacznie identyfikująca działanie wiadomości

W przeciwieństwie do elementów danych synchronizacja między aplikacjami na komputerze i urządzeniach do noszenia nie jest synchronizowana. Komunikaty to jednokierunkowy mechanizm komunikacji przydatny w przypadku zdalnych wywołań procedur (RPC), na przykład wysyłanie wiadomości do urządzenia do noszenia, aby rozpocząć działanie.

Do urządzenia mobilnego użytkownika można podłączyć wiele urządzeń do noszenia. Każde połączone urządzenie w sieci jest uważane za węzeł.

W przypadku wielu połączonych urządzeń musisz zdecydować, które węzły otrzymają wiadomości. Na przykład w aplikacji transkrypcji głosowej, która odbiera dane głosowe na urządzeniu do noszenia, wyślij wiadomość do węzła o mocy obliczeniowej i mocy baterii do obsługi żądania (np. do urządzenia mobilnego).

Uwaga: określając szczegóły wiadomości, weź pod uwagę możliwość połączenia wielu węzłów. Sprawdź, czy wiadomość została dostarczona do właściwych urządzeń lub węzłów.

Przykłady użycia znajdziesz poniżej.

Wysyłanie wiadomości

Aplikacja do noszenia może udostępniać użytkownikom funkcje takie jak transkrypcja głosu. Użytkownicy mogą mówić do mikrofonu urządzenia do noszenia i zapisywać transkrypcję w notatce. Urządzenia do noszenia zwykle nie mają mocy obliczeniowej ani pojemności baterii, które są wymagane do obsługi transkrypcji głosowej, więc aplikacja musi przenieść te zadania na bardziej wydajne połączone urządzenie.

Z kolejnych sekcji dowiesz się, jak reklamować węzły urządzeń, które mogą przetwarzać żądania dotyczące aktywności, wykrywać węzły spełniające zamierzone potrzeby i wysyłać do nich komunikaty.

Aby uruchomić aktywność na urządzeniu mobilnym z poziomu urządzenia do noszenia, wyślij żądanie za pomocą klasy MessageClient. Ponieważ z urządzeniem mobilnym można podłączyć wiele urządzeń do noszenia, aplikacja do noszenia musi określić, czy połączony węzeł może uruchomić aktywność. W aplikacji mobilnej zamieść informację, że węzeł, w którym działa, ma określone możliwości.

Aby reklamować możliwości swojej aplikacji mobilnej:

  1. W katalogu res/values/ swojego projektu utwórz plik konfiguracji XML i nazwij go wear.xml.
  2. Dodaj zasób o nazwie android_wear_capabilities do projektu wear.xml.
  3. Określ funkcje urządzenia.

Uwaga: Możliwości to zdefiniowane przez Ciebie ciągi niestandardowe, które muszą być unikalne w aplikacji.

Poniższy przykład pokazuje, jak dodać możliwość o nazwie voice_transcription do 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>

Pobieranie węzłów z wymaganymi funkcjami

Początkowo możesz wykryć węzły, które spełniają wymagania, wywołując metodę getCapability klasy CapabilityClient. Aby można było użyć tej metody, aplikacje na Wear OS i telefon muszą mieć ten sam identyfikator aplikacji. Z przykładu poniżej dowiesz się, jak ręcznie pobierać wyniki osiągalnych węzłów za pomocą funkcji 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);
}

Aby wykryć odpowiednie węzły, gdy łączą się z urządzeniem do noszenia, zarejestruj wystąpienie odbiornika, a w szczególności OnCapabilityChangedListener obiektu CapabilityClient. Poniższy przykład pokazuje, jak zarejestrować detektor i pobrać wynik z osiągalnymi węzłami, które obsługują funkcję 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);
}

Po wykryciu węzłów obsługujących tę funkcję określ, dokąd należy wysłać wiadomość. Wybierz węzeł, który znajduje się blisko urządzenia do noszenia, aby zminimalizować kierowanie wiadomości przez wiele węzłów. Pobliski węzeł to taki, który jest bezpośrednio połączony z urządzeniem. Aby sprawdzić, czy węzeł znajduje się w pobliżu, na przykład połączony przez Bluetooth, wywołaj metodę Node.isNearby(). Jeśli w pobliżu znajduje się więcej niż 1 węzeł, wybierz jeden z nich. Podobnie, jeśli w pobliżu nie ma żadnego odpowiedniego węzła, wybierz ten, który spełnia wymagania.

Z przykładu poniżej dowiesz się, jak wybrać najlepszy węzeł do użycia:

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

Dostarczenie wiadomości

Po wybraniu węzła do użycia wyślij wiadomość za pomocą klasy MessageClient.

Poniższy przykład pokazuje, jak wysłać wiadomość z urządzenia do noszenia do węzła obsługującego transkrypcję. To wywołanie jest synchroniczne i blokuje przetwarzanie, dopóki system nie umieści wiadomości w kolejce do dostarczenia.

Uwaga: poprawny kod wyniku nie gwarantuje dostarczenia wiadomości. Jeśli aplikacja wymaga niezawodności danych, rozważ przesyłanie danych między urządzeniami za pomocą obiektów DataItem lub klasy 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
    }
}

Uwaga: więcej informacji o asynchronicznych i synchronicznych wywołaniach Usług Google Play oraz o tym, kiedy ich używać, znajdziesz w artykule Tasks API.

Możesz też rozgłaszać komunikaty do wszystkich połączonych węzłów. Aby pobrać wszystkie połączone węzły, do których możesz wysyłać wiadomości, zaimplementuj ten kod:

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

Odbieranie wiadomości

Aby otrzymywać powiadomienia o otrzymanych wiadomościach, zaimplementuj interfejs MessageClient.OnMessageReceivedListener z odbiornikiem zdarzeń wiadomości. Następnie zarejestruj odbiornik za pomocą metody addListener. Ten przykład pokazuje, jak można zaimplementować odbiornik, aby sprawdzić VOICE_TRANSCRIPTION_MESSAGE_PATH. Jeśli ten warunek to true, rozpocznij aktywność, aby przetworzyć dane głosowe.

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

Ten kod wymaga więcej szczegółów implementacji. Informacje o tym, jak wdrożyć działanie lub usługę detektora pełnej usługi detektora, znajdziesz w sekcji Nasłuchiwanie zdarzeń warstwy danych.