最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

android - Impossible to send data from Wear OS app to phone app (kotlin) with DataClient (Google services) - Stack Overflow

programmeradmin1浏览0评论

I am using the latest version of Android Studio. I own a Samsung Galaxy Watch 6 classic and a Samsung S24 ultra (both fully up to date firmware-wise).

I coded in Kotlin a Wear OS app for ice skaters. It records several types of data during the session, like the session date, duration, average and max speed, skated distance, heart rate, calories burnt etc.

I also coded, in the same project, the companion phone app (a second module) that is supposed to receive the data. On the phone app, I click on "free skating session", and the date of the session is supposed to show up, click on the date and display the other values in a lazy column.

The problem is, I can't get the data to be sent to the phone app.

On my watch app, I am using a ViewModel that retrieves and updates the values.

When the session is done, the data are "parcelized" (I have the data class SessionData on a third module named common, it is shared between the watch and phone app) and I use putDataMapRequest to send them:

suspend fun sendSessionDataToDataLayer(sessionData: SessionData, context: Context) {
    val bundle = Bundle().apply {
        putParcelable("sessionData", sessionData)
    }
    val putDataMapRequest = PutDataMapRequest.create("/session-data").apply {
        dataMap.putAll(DataMap.fromBundle(bundle))
    }
    val putDataRequest = putDataMapRequest.asPutDataRequest()

    try {
        Log.d("sendSessionDataToDataLayer", "Sending session data: $sessionData")
        Wearable.getDataClient(context).putDataItem(putDataRequest).await()
        Log.d("sendSessionDataToDataLayer", "Data sent successfully")

        // Show a toast to the user on the watch
        Toast.makeText(context, "Data queued for transfer", Toast.LENGTH_SHORT).show()

        resetSession() // Only reset after successful data transfer
    } catch (e: Exception) {
        Log.e("sendSessionDataToDataLayer", "Failed to send session data", e)
        // Optionally show an error toast
        Toast.makeText(context, "Data send failed: ${e.message}", Toast.LENGTH_SHORT).show()
    }
}

The path is "/session-data", the same in the watch and phone app. The toast I get from this: "data queued for transfer"

Then I have my listener on the phone app with the OnDatachanged function. It is supposed to retrieve the data and deparcelize them. But the OnDataChanged never fires...

class MyDataLayerListenerService : WearableListenerService() {
override fun onDataChanged(dataEvents: DataEventBuffer) {
    // Indicate that onDataChanged was called at all
    Toast.makeText(this, "onDataChanged triggered!", Toast.LENGTH_SHORT).show()

    dataEvents.forEach { event ->
        if (event.type == DataEvent.TYPE_CHANGED && event.dataItem.uri.path == "/session-data") {
            try {
                val dataMap = DataMapItem.fromDataItem(event.dataItem).dataMap
                val bundle = dataMap.toBundle()
                val sessionData: SessionData? = bundle.getParcelable("sessionData")

                if (sessionData != null) {
                    Toast.makeText(this, "Received session data!", Toast.LENGTH_SHORT).show()
                    saveSessionDataLocally(sessionData)
                } else {
                    Toast.makeText(this, "SessionData is null", Toast.LENGTH_SHORT).show()
                }
            } catch (e: Exception) {
                Toast.makeText(this, "Failed to parse session data: ${e.message}", Toast.LENGTH_LONG).show()
            }
        }
    }
}

private fun saveSessionDataLocally(sessionData: SessionData) {
    // e.g. show a final toast
    Toast.makeText(this, "Session data saved: ${sessionData.distanceSkated}", Toast.LENGTH_SHORT).show()
}

}

From this, I don't get any toasts. On the phone screen, I should see a row with the dates sessions, which does not happen. Data are not transfered.

I added helping toasts to have an idea where this fails. When the session is done, the watch toast says "data queued for transfer". So it looks like the watch thinks the job is correctly done. I also implemented toasts on the phone but they never show. Just a blank page instead of the skating session date.

In an 10 y.o. topic, they recommended that the phone and the watch must have the same application ID. Likewise, I thought I needed node IDs to send the data but it is only for MessageCLient, not DataClient.

I also did some basic checks: watch and phone properly connected to one another, also logged into the same Google account (and same Samsung account for what it's worth), on the same WIfi. I unpaired the watch and repaired. I reset completely the watch and repaired it to the phone. The google services on my watch is up to date as of January 2025 (24.49.33-705592033) and on the phone, Google play services is fully allowed and on high priority.

In the phone manifest, Google services wearable are there. I have the wearable.Bind.Listener and the wearable.data.changed. The data path is good e.g. "/session-data".

Phone manifest:

<service
        android:name=".MyDataLayerListenerService"
        android:exported="true"
        android:permission="com.google.android.gms.permission.WEARABLE_BIND_LISTENER">

        <!-- If you want to listen for data changes at a specific path, declare a DATA_CHANGED action
             and optionally specify a pathPrefix to filter for certain paths (like "/session-data"). -->
        <intent-filter>
            <!-- Listen for data changes -->
            <action android:name="com.google.android.gms.wearable.DATA_CHANGED" />

            <!-- (Optional) If you only care about a specific path in the data layer, add <data>: -->
            <data
                android:scheme="wear"
                android:host="*"
                android:pathPrefix="/session-data"  />
        </intent-filter>

    </service>

All the modules (watch, phone, common for the data class) are recognized and declared in the gradle files.

I tried to develop a simple project just to pass a simple string from my watch to phone but couldn't get it to work.

I am using the latest version of Android Studio. I own a Samsung Galaxy Watch 6 classic and a Samsung S24 ultra (both fully up to date firmware-wise).

I coded in Kotlin a Wear OS app for ice skaters. It records several types of data during the session, like the session date, duration, average and max speed, skated distance, heart rate, calories burnt etc.

I also coded, in the same project, the companion phone app (a second module) that is supposed to receive the data. On the phone app, I click on "free skating session", and the date of the session is supposed to show up, click on the date and display the other values in a lazy column.

The problem is, I can't get the data to be sent to the phone app.

On my watch app, I am using a ViewModel that retrieves and updates the values.

When the session is done, the data are "parcelized" (I have the data class SessionData on a third module named common, it is shared between the watch and phone app) and I use putDataMapRequest to send them:

suspend fun sendSessionDataToDataLayer(sessionData: SessionData, context: Context) {
    val bundle = Bundle().apply {
        putParcelable("sessionData", sessionData)
    }
    val putDataMapRequest = PutDataMapRequest.create("/session-data").apply {
        dataMap.putAll(DataMap.fromBundle(bundle))
    }
    val putDataRequest = putDataMapRequest.asPutDataRequest()

    try {
        Log.d("sendSessionDataToDataLayer", "Sending session data: $sessionData")
        Wearable.getDataClient(context).putDataItem(putDataRequest).await()
        Log.d("sendSessionDataToDataLayer", "Data sent successfully")

        // Show a toast to the user on the watch
        Toast.makeText(context, "Data queued for transfer", Toast.LENGTH_SHORT).show()

        resetSession() // Only reset after successful data transfer
    } catch (e: Exception) {
        Log.e("sendSessionDataToDataLayer", "Failed to send session data", e)
        // Optionally show an error toast
        Toast.makeText(context, "Data send failed: ${e.message}", Toast.LENGTH_SHORT).show()
    }
}

The path is "/session-data", the same in the watch and phone app. The toast I get from this: "data queued for transfer"

Then I have my listener on the phone app with the OnDatachanged function. It is supposed to retrieve the data and deparcelize them. But the OnDataChanged never fires...

class MyDataLayerListenerService : WearableListenerService() {
override fun onDataChanged(dataEvents: DataEventBuffer) {
    // Indicate that onDataChanged was called at all
    Toast.makeText(this, "onDataChanged triggered!", Toast.LENGTH_SHORT).show()

    dataEvents.forEach { event ->
        if (event.type == DataEvent.TYPE_CHANGED && event.dataItem.uri.path == "/session-data") {
            try {
                val dataMap = DataMapItem.fromDataItem(event.dataItem).dataMap
                val bundle = dataMap.toBundle()
                val sessionData: SessionData? = bundle.getParcelable("sessionData")

                if (sessionData != null) {
                    Toast.makeText(this, "Received session data!", Toast.LENGTH_SHORT).show()
                    saveSessionDataLocally(sessionData)
                } else {
                    Toast.makeText(this, "SessionData is null", Toast.LENGTH_SHORT).show()
                }
            } catch (e: Exception) {
                Toast.makeText(this, "Failed to parse session data: ${e.message}", Toast.LENGTH_LONG).show()
            }
        }
    }
}

private fun saveSessionDataLocally(sessionData: SessionData) {
    // e.g. show a final toast
    Toast.makeText(this, "Session data saved: ${sessionData.distanceSkated}", Toast.LENGTH_SHORT).show()
}

}

From this, I don't get any toasts. On the phone screen, I should see a row with the dates sessions, which does not happen. Data are not transfered.

I added helping toasts to have an idea where this fails. When the session is done, the watch toast says "data queued for transfer". So it looks like the watch thinks the job is correctly done. I also implemented toasts on the phone but they never show. Just a blank page instead of the skating session date.

In an 10 y.o. topic, they recommended that the phone and the watch must have the same application ID. Likewise, I thought I needed node IDs to send the data but it is only for MessageCLient, not DataClient.

I also did some basic checks: watch and phone properly connected to one another, also logged into the same Google account (and same Samsung account for what it's worth), on the same WIfi. I unpaired the watch and repaired. I reset completely the watch and repaired it to the phone. The google services on my watch is up to date as of January 2025 (24.49.33-705592033) and on the phone, Google play services is fully allowed and on high priority.

In the phone manifest, Google services wearable are there. I have the wearable.Bind.Listener and the wearable.data.changed. The data path is good e.g. "/session-data".

Phone manifest:

<service
        android:name=".MyDataLayerListenerService"
        android:exported="true"
        android:permission="com.google.android.gms.permission.WEARABLE_BIND_LISTENER">

        <!-- If you want to listen for data changes at a specific path, declare a DATA_CHANGED action
             and optionally specify a pathPrefix to filter for certain paths (like "/session-data"). -->
        <intent-filter>
            <!-- Listen for data changes -->
            <action android:name="com.google.android.gms.wearable.DATA_CHANGED" />

            <!-- (Optional) If you only care about a specific path in the data layer, add <data>: -->
            <data
                android:scheme="wear"
                android:host="*"
                android:pathPrefix="/session-data"  />
        </intent-filter>

    </service>

All the modules (watch, phone, common for the data class) are recognized and declared in the gradle files.

I tried to develop a simple project just to pass a simple string from my watch to phone but couldn't get it to work.

Share Improve this question edited Feb 7 at 19:25 TofferJ 4,7941 gold badge41 silver badges51 bronze badges asked Jan 13 at 23:03 Sébastien PouySébastien Pouy 11 bronze badge 3
  • 1 Please edit your question and condense it to the necessary parts only. And most importantly, please add a minimal reproducible example of what you have so far that demonstrates what isn't working. – tyg Commented Jan 13 at 23:13
  • Without any code, sample data, expected vs actual behavior, specific issues, etc, there's really nothing that can be done. You provided a general description, but the details are important (a minimal reproducible example as pointed out in the other comment) – David Makogon Commented Jan 14 at 22:42
  • Does this answer your question? – Gustavo Pagani Commented Jan 14 at 22:44
Add a comment  | 

1 Answer 1

Reset to default 0

Please review the following security requirements, otherwise your apps won't communicate to each other:

  • The package name must match across devices.
  • The signature of the package must match across devices.

Other sources of information/tutorial on this subject:

  1. DataLayer sample from Wear OS samples repo in github;
    • I would recommend running the apps from this sample in your phone and watch and see them working for you.
  2. DataLayer helpers from Horologist repo in github;

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论