Nachrichten über Wear senden und empfangen

Sie senden Nachrichten mit der MessageClient API und hängen die folgenden Elemente an die Nachricht an:

  • Eine optionale beliebige Nutzlast
  • Ein Pfad, der die Aktion der Nachricht eindeutig identifiziert

Anders als bei Datenelementen erfolgt keine Synchronisierung zwischen den Handheld- und Wearable-Apps. Nachrichten sind ein einseitiger Kommunikationsmechanismus, der für Remoteprozeduraufrufe (RPC) nützlich ist, z. B. das Senden einer Nachricht an das Wearable, um eine Aktivität zu starten.

Mehrere Wearables können mit dem Handheld-Gerät eines Nutzers verbunden werden. Jedes verbundene Gerät im Netzwerk wird als Knoten betrachtet.

Bei mehreren verbundenen Geräten müssen Sie berücksichtigen, welche Knoten die Nachrichten empfangen. Senden Sie beispielsweise in einer Anwendung zur Sprachtranskription, die Sprachdaten auf dem Wearable-Gerät empfängt, an einen Knoten mit entsprechender Prozessor- und Akkukapazität zur Verarbeitung der Anfrage gesendet wird, z. B. an ein Handheld-Gerät.

Hinweis:Wenn Sie die Details Ihrer Nachricht angeben, berücksichtigen Sie die Möglichkeit mehrerer verbundener Knoten. Prüfen Sie, ob die Nachricht an die gewünschten Geräte oder Knoten gesendet wird.

Anwendungsbeispiele finden Sie in den folgenden Beispiel-Apps:

Eine Nachricht posten

Eine Wearable-App kann Nutzern Funktionen wie Sprachtranskription bieten. Nutzer können in das Mikrofon ihres Wearable-Geräts sprechen und ein Transkript in einer Notiz speichern lassen. Da ein Wearable in der Regel nicht die für die Verarbeitung der Sprachtranskription erforderliche Rechenleistung und Akkukapazität hat, muss die Anwendung diese Aufgaben auf ein leistungsfähigeres verbundenes Gerät übertragen.

In den folgenden Abschnitten wird gezeigt, wie Sie Geräteknoten bewerben, die Aktivitätsanfragen verarbeiten, Knoten ermitteln, die einen angeforderten Bedarf erfüllen, und Nachrichten an diese Knoten senden.

Wenn Sie von einem Wearable aus eine Aktivität auf einem Handheld-Gerät starten möchten, verwenden Sie die Klasse MessageClient, um die Anfrage zu senden. Da mehrere Wearables mit dem Handheld-Gerät verbunden werden können, muss die Wearable-App feststellen, ob ein verbundener Knoten in der Lage ist, die Aktivität zu starten. Geben Sie in Ihrer Handheld-Anwendung an, dass der Knoten, auf dem sie ausgeführt wird, bestimmte Funktionen bietet.

So bewerben Sie die Funktionen Ihrer Handheld-App:

  1. Erstellen Sie im Verzeichnis res/values/ Ihres Projekts eine XML-Konfigurationsdatei und nennen Sie sie wear.xml.
  2. Fügen Sie wear.xml eine Ressource mit dem Namen android_wear_capabilities hinzu.
  3. Definieren Sie die vom Gerät bereitgestellten Funktionen.

Hinweis:Funktionen sind benutzerdefinierte Strings, die Sie definieren und innerhalb Ihrer App eindeutig sein müssen.

Das folgende Beispiel zeigt, wie Sie eine Funktion namens voice_transcription zu wear.xml hinzufügen:

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

Knoten mit den erforderlichen Funktionen abrufen

Zu Beginn können Sie die geeigneten Knoten ermitteln, indem Sie die Methode getCapability der Klasse CapabilityClient aufrufen. Damit Sie diese Methode verwenden können, müssen Ihre Wear OS-App und Ihre Smartphone-App dieselbe App-ID haben. Das folgende Beispiel zeigt, wie Sie die Ergebnisse erreichbarer Knoten mit der Funktion voice_transcription manuell abrufen können:

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

Registrieren Sie eine Instanz eines Listeners, insbesondere eine OnCapabilityChangedListener eines CapabilityClient-Objekts, damit kompatible Knoten bei der Verbindung zum Wearable-Gerät erkannt werden. Das folgende Beispiel zeigt, wie Sie den Listener registrieren und ein Ergebnis mit erreichbaren Knoten mit der Funktion voice_transcription abrufen:

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

Nachdem Sie die geeigneten Knoten erkannt haben, legen Sie fest, wohin die Nachricht gesendet werden soll. Wählen Sie einen Knoten in der Nähe Ihres Wearable-Geräts aus, um die Nachrichtenweiterleitung über mehrere Knoten zu minimieren. Ein Knoten in der Nähe ist ein Knoten, der direkt mit dem Gerät verbunden ist. Rufen Sie die Methode Node.isNearby() auf, um festzustellen, ob sich ein Knoten in der Nähe befindet, z. B. über Bluetooth. Wenn sich mehr als ein Knoten in der Nähe befindet, wählen Sie einen beliebig aus. Wenn sich kein fähiger Knoten in der Nähe befindet, wählen Sie entsprechend einen geeigneten Knoten aus.

Das folgende Beispiel zeigt, wie Sie den besten zu verwendenden Knoten ermitteln können:

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

Die Botschaft übermitteln

Wenn Sie einen zu verwendenden Knoten identifiziert haben, senden Sie die Nachricht mit der Klasse MessageClient.

Das folgende Beispiel zeigt, wie Sie von einem Wearable-Gerät eine Nachricht an den transkriptionsfähigen Knoten senden. Dieser Aufruf ist synchron und blockiert die Verarbeitung, bis das System die Nachricht zur Zustellung in die Warteschlange stellt.

Hinweis:Ein erfolgreicher Ergebniscode garantiert nicht, dass die Nachricht zugestellt wird. Wenn deine App Datenzuverlässigkeit erfordert, kannst du DataItem-Objekte oder die Klasse ChannelClient verwenden, um Daten zwischen Geräten zu senden.

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

Hinweis:Weitere Informationen zu asynchronen und synchronen Aufrufen von Google Play-Diensten und ihrer Verwendung finden Sie in der Tasks API.

Sie können auch Nachrichten an alle verbundenen Knoten senden. Implementieren Sie den folgenden Code, um alle verbundenen Knoten abzurufen, an die Sie Nachrichten senden können:

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

Nachrichten empfangen

Wenn Sie über empfangene Nachrichten informiert werden möchten, implementieren Sie die MessageClient.OnMessageReceivedListener-Schnittstelle, um einen Listener für Nachrichtenereignisse bereitzustellen. Registrieren Sie dann den Listener mit der Methode addListener. Das folgende Beispiel zeigt, wie Sie den Listener implementieren können, um VOICE_TRANSCRIPTION_MESSAGE_PATH zu prüfen. Wenn diese Bedingung true ist, starten Sie eine Aktivität zur Verarbeitung der Sprachdaten.

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

Für diesen Code sind weitere Implementierungsdetails erforderlich. Informationen zum Implementieren eines vollständigen Listener-Dienstes oder einer -Aktivität finden Sie unter Auf Datenschichtereignisse warten.