PhantomKnigh287

Gurpal Singh

@PhantomKnight287

Build Wear OS Apps and Connect with Android

Create Wear OS app and integrate them with Android, covering setup, permissions, and data sync.

Initial Setup

Start by creating an android app using your preferred framework and open your project in Android Studio (open the android folder if using cross-platform frameworks).

Phone App Setup

First, we need to bind a listener so we can listen to messages sent by our watch even when our app is closed/killed. This requires adding permissions and implementing the package. Don't worry about prompting users for permissions - its not needed as it is a normal permission.

Adding Dependencies

Add the following to your app level gradle file (app/build.gradle):

implementation("com.google.android.gms:play-services-wearable:19.0.0")

Don't forget to press Sync Now

Permissions Setup

Add the following code in the manifest block of AndroidManifest.xml:

<uses-permission android:name="com.google.android.wearable.permission.BIND_WEARABLE_LISTENER" />

Creating Message Receiver

Now, we'll write a service that will be android:exported. Create a new file WearMessageReceiver.kt in the same folder as MainActivity.kt:

package com.your.package

import android.content.Intent
import com.google.android.gms.wearable.MessageEvent
import com.google.android.gms.wearable.WearableListenerService

class WearMessageReceiver : WearableListenerService() {
    override fun onMessageReceived(event: MessageEvent) {
        when (event.path) {
            "/open" -> {
                val intent = packageManager.getLaunchIntentForPackage(packageName)?.apply {
                    addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
                    addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
                }
                startActivity(intent)
            }
        }
    }
}

The above code listens for the /open message and when received, it opens the app.

Registering the Service

We need to tell our phone about this service. Add the following code in the application block of AndroidManifest.xml:

<service
    android:name="[package name].WearMessageReceiver"
    android:exported="true">
    <intent-filter>
        <action android:name="com.google.android.gms.wearable.MESSAGE_RECEIVED" />
        <category android:name="android.intent.category.DEFAULT" />
        <data
            android:host="*"
            android:pathPattern=".*"
            android:scheme="wear" />
    </intent-filter>
</service>

Message Sending Function

This function sends messages from our phone to the watch. Add it to MainActivity.kt:

suspend fun sendMessageToWatch(
        context: Context,
        path: String,
        data: ByteArray = ByteArray(0)
    ) {
        withContext(Dispatchers.IO) {
            try {
                val nodes = Tasks.await(Wearable.getNodeClient(context).connectedNodes)
                // it is recommended to filter out nodes with `isNearby = false`
                nodes.forEach { node ->
                    Tasks.await(
                        Wearable.getMessageClient(context).sendMessage(
                            node.id,
                            path,
                            data,
                        )
                    )
                }
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }
    }

Read more on suspend functions here.

Watch App Setup

Here, you'll need a Wear OS device connected to your phone and connected to your PC via wireless debugging. Don't have a Wear OS device? No problem! Create a new emulator and run it following the setup instructions. Unlike Apple Watch simulator, it will connect to your physical phone or emulator.

Creating the Watch Project

  1. Go to Android Studio > File > New > New Project > Wear OS > Empty Wear App
  2. Keep the bundle identifier same as your phone app
  3. Connect a Wear OS device or create an emulator

Adding Permissions

Just like the phone app, we need to bind a listener and add permissions. Add to the manifest block in AndroidManifest.xml:

<uses-permission android:name="com.google.android.wearable.permission.BIND_WEARABLE_LISTENER" />

Creating Message Listener

Create MessageListenerService.kt:

// make sure the name of this class matches the one in AndroidManifest.xml
class MessageListenerService : WearableListenerService() {
    override fun onMessageReceived(event: MessageEvent) {
        super.onMessageReceived(event)
        when (event.path) {
            "/boot" -> {
                val intent = Intent(this, MainActivity::class.java).apply {
                    addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
                }
                startActivity(intent)
            }
        }
    }
}

Registering Watch Service

Add to the application block in AndroidManifest.xml:

<service
    android:name=".MessageListenerService"
    android:exported="true">
    <intent-filter>
        <action android:name="com.google.android.gms.wearable.MESSAGE_RECEIVED" />
            <data
                    android:host="*"
                    android:pathPattern=".*"
                    android:scheme="wear" />
        </intent-filter>
</service>

Message Sending Function

Add to MainActivity.kt:

private suspend fun sendMessageToPhone(path: String, data: ByteArray) {
    val connectedNodes = Wearable.getNodeClient(this).connectedNodes.await()
    println("Connected nodes: $connectedNodes")
    for (node in connectedNodes) {
        try {
            messageClient.sendMessage(node.id, path, data).await()
        } catch (e: Exception) {
            println("Failed to send message to node ${node.id}: ${e.message}")
        }
    }
}

Final Notes

  • Messages between devices are transferred in ByteArray format - remember to encode data in sender device and decode the data in receiver device
  • For cross-platform frameworks, you can call sendMessageToWatch using MethodChannel or equivalent
  • Name of services should match the name specified in AndroidManifest.xml