When users set up a Wear OS device, they connect the Wear OS device to a particular mobile device. The user might later decide to get a new mobile device and connect their existing Wear OS device to this new mobile device. Some data related to a Wear OS device is stored on the currently-connected mobile device.
Starting in Wear OS 4, when users connect to a new mobile device, they can transfer Wear OS data to the new mobile device. Data is synced automatically when it's transferred.
When the user requests a transfer, the Wearable Data Layer delivers
DataItem
objects, originally stored on one mobile device, to the other
mobile device. This allows a seamless experience for users of your app.
This document describes how you can configure your Wear OS app, and its companion mobile app, to support this scenario.
Preparation
The data transfer process handles DataItem
objects differently, depending on
which app owns the data:
- Objects owned by the Wear OS app
- These objects are preserved on the Wear OS device.
- Objects owned by the mobile app
These objects are archived on the old device. The system then packages the archived data into a
DataItemBuffer
object and delivers this data to the mobile app that's installed on the new mobile device.Immediately after the archive is delivered, the Wearable Data Layer invokes the
onNodeMigrated()
listener, similarly to how your app is notified when data is written by the Wear OS device.
Preserve transferred data
It's your app's responsibility to preserve the transferred DataItem
objects.
Shortly after the data is delivered to the new mobile device, the archive is
deleted off of the old device.
Make sure each of the following conditions is true:
- Your app is installed on both mobile devices that are involved in the transfer.
- The mobile apps, installed on each mobile device, have package signatures that match.
Otherwise, the archived DataItem
objects aren't delivered and are instead
discarded.
Receive data from the old mobile device
To receive data on the new mobile device that was archived on the old mobile
device, your mobile app must implement the onNodeMigrated()
callback,
part of the WearableListenerService
class. To do so, complete the following
steps:
In your mobile app's build file, include a dependency on the latest version of the wearable library in Google Play services:
dependencies { ... implementation 'com.google.android.gms:play-services-wearable:18.2.0' }
Declare and export the
WearableListenerService
in your app's manifest file:<service android:name=".MyWearableListenerService" android:exported="true"> <intent-filter> ... <action android:name="com.google.android.gms.wearable.NODE_MIGRATED" /> <data android:scheme="wear" /> </intent-filter> </service>
Create a service class which extends
WearableListenerService
and overridesonNodeMigrated()
.Kotlin
class MyWearableListenerService : WearableListenerService() { val dataClient: DataClient = Wearable.getDataClient(this) private fun shouldHandleDataItem(nodeId: String, dataItem: DataItem): Boolean { // Your logic here return dataItem.uri.path?.startsWith("/my_feature_path/") == true } private fun handleDataItem(nodeId: String, dataItem: DataItem) { val data = dataItem.data ?: return val path = dataItem.uri.path ?: return // Your logic here if (data.toString().startsWith("Please restore")) { dataClient.putDataItem( PutDataRequest.create(path).setData(data) ) } } override fun onNodeMigrated(nodeId: String, archive: DataItemBuffer) { val dataItemsToHandle = mutableListOf<DataItem>() for (dataItem in archive) { if (shouldHandleDataItem(nodeId, dataItem)) { dataItemsToHandle.add(dataItem.freeze()) } } // Callback stops automatically after 20 seconds of data processing. // If you think you need more time, delegate to a coroutine or thread. runBlocking { for (dataItem in dataItemsToHandle) { handleDataItem(nodeId, dataItem) } } } }
Java
public class MyWearableListenerService extends WearableListenerService { private final DataClient dataClient = Wearable.getDataClient(this); private boolean shouldHandleDataItem(String nodeId, DataItem dataItem) { // Your logic here return Objects.requireNonNull(dataItem.getUri().getPath()) .startsWith("/my_feature_path/"); } private Task<DataItem> handleDataItem(String nodeId, DataItem dataItem) { byte[] data = dataItem.getData(); String path = dataItem.getUri().getPath(); // Your logic here if (data != null && path != null && Arrays.toString(data) .startsWith("Please restore")) { assert path != null; return dataClient.putDataItem( PutDataRequest.create(path).setData(data)); } @Override public void onNodeMigrated(@NonNull String nodeId, DataItemBuffer archive) { List<DataItem> dataItemsToHandle = new ArrayList<>(); for (DataItem dataItem : archive) { if (shouldHandleDataItem(nodeId, dataItem)) { dataItemsToHandle.add(dataItem.freeze()); } } for (dataItem in dataItemsToHandle) { handleDataItem(nodeId, dataItem); } // Callback stops automatically after 20 seconds of data processing. // If you think you need more time, delegate to another thread. } }
Recommended for you
- Note: link text is displayed when JavaScript is off
- Integrate a Wear OS module
- Conserve power and battery