透過 Wear 收發訊息

您可以使用 MessageClient API 傳送訊息,並附加下列項目:

  • 選用的任何酬載
  • 可識別訊息動作的唯一路徑

與資料項目的情況不同,手持裝置應用程式和穿戴式裝置應用程式之間不會進行同步處理。訊息是單向的溝通機制,適用於遠端程序呼叫 (RPC),例如藉由傳送訊息到穿戴式裝置的方式啟動活動。

使用者的一部手持裝置可以連結至多部穿戴式裝置。網路中的每部連結裝置都可以視為一個「節點」。

有多部連結裝置時,必須考慮要由哪個節點接收訊息。舉例來說,如果是透過穿戴式裝置接收語音資料的語音轉錄應用程式,應將訊息傳送到具有處理能力和電池容量來處理這項要求的節點,例如特定手持裝置。

注意:指定訊息詳細資料時,請考量可能有多個連結節點的情況。請確保可將訊息傳送至指定裝置或節點。

如需使用範例,請參考以下範例應用程式: 資料層

傳送訊息

穿戴式應用程式可為使用者提供語音轉錄等功能。使用者可以向穿戴式裝置的麥克風說話,並將轉錄稿儲存到筆記中。由於穿戴式裝置通常無法提供處理語音轉錄活動所需的處理能力和電池容量,應用程式需要卸載這項工作,交由能力更強的連線裝置處理。

以下章節將說明如何通告可處理活動要求的裝置節點、找出可執行要求需求的節點,以及傳送訊息給這些節點。

如要透過穿戴式裝置在手持裝置上啟動活動,請使用 MessageClient 類別傳送要求。由於手持裝置可以連線至多部穿戴式裝置,穿戴式應用程式需要判斷某個連線節點是否能夠啟動活動。請在手持裝置應用程式中,通告其執行所在的節點提供特定能力。

如果要通告手持裝置應用程式的能力,請執行下列操作:

  1. 在專案的 res/values/ 目錄中建立 XML 設定檔,並命名為 wear.xml
  2. wear.xml 中新增名為 android_wear_capabilities 的資源。
  3. 定義裝置提供的能力。

注意:能力是由您定義的自訂字串,在應用程式內不得重複。

以下範例說明如何為 wear.xml 新增名為 voice_transcription 的能力:

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

擷取具有必要能力的節點

一開始,您可以呼叫 CapabilityClient 類別的 getCapability 方法,偵測具有所需能力的節點。如要使用這個方法,Wear OS 應用程式和手機應用程式的應用程式 ID 必須相同。以下範例說明如何手動擷取具有 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);
}

如果想在連線到穿戴式裝置時偵測有能力的節點,請註冊事件監聽器的例項,也就是 CapabilityClient 物件的 OnCapabilityChangedListener。以下範例說明如何註冊事件監聽器,並擷取具有 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);
}

偵測到有能力的節點後,請判定訊息的傳送目標。選擇節點 手機靠近穿戴式裝置 訊息轉送鄰近節點的定義為直接連線 。如果想判斷某個節點是否在附近 (例如透過藍牙連線),請呼叫 Node.isNearby() 方法,增加圍繞地圖邊緣的邊框間距。如果有多個鄰近節點,可選擇其中任一個節點。同樣地,如果沒有具能力的鄰近節點,則可任意選擇一個具能力的節點。

以下範例說明如何判斷最適用的節點:

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

傳送訊息

確定要使用的節點後,請用 MessageClient 類別傳送訊息。

以下範例說明如何從穿戴式裝置,將訊息傳送至有能力處理語音轉錄的節點。這項呼叫為同步性質,且會停止處理程序,直到系統將訊息排入傳送佇列為止。

注意:成功的結果代碼不保證會傳送訊息。如果應用程式要求資料穩定性,建議使用 DataItem 物件或 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
    }
}

注意:如要進一步瞭解對 Google Play 服務的非同步與同步呼叫,以及這兩種呼叫的各別使用時機,請參閱「Tasks API」。

您也可以向所有連線的節點廣播訊息。如要擷取所有可以接收訊息的連線節點,請實作以下程式碼:

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

接收訊息

如要接收收到訊息的通知,可以實作 MessageClient.OnMessageReceivedListener 介面,提供訊息事件的事件監聽器。接著,使用 addListener 方法註冊事件監聽器。以下範例說明如何實作事件監聽器來檢查 VOICE_TRANSCRIPTION_MESSAGE_PATH。如果這項條件為 true,即可啟動用於處理語音資料的活動。

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

這段程式碼需要更詳細的實作資料。如要瞭解如何實作完整的事件監聽器服務或活動,請參閱「監聽資料層事件」。