将 Wear OS 数据传输到新的移动设备

当用户设置 Wear OS 设备时,他们会将 Wear OS 设备连接到特定的移动设备。用户以后可能决定获得新的移动设备,并将现有的 Wear OS 设备连接到此新的移动设备。与 Wear OS 设备相关的一些数据存储在当前连接的移动设备上。

从 Wear OS 4 开始,当用户连接到新的移动设备时,他们可以将 Wear OS 数据传输到新的移动设备。数据在传输时会自动同步。

当用户请求传输时,可穿戴数据层 将最初存储在一个移动设备上的DataItem 对象传输到另一个移动设备。这为您的应用用户提供了无缝的体验。

本文档介绍了如何配置您的 Wear OS 应用及其配套移动应用以支持此场景。

准备工作

数据传输过程处理DataItem 对象的方式不同,具体取决于哪个应用拥有数据。

Wear OS 应用拥有的对象
这些对象将保留在 Wear OS 设备上。
移动应用拥有的对象

这些对象将存档到旧设备上。然后,系统将存档数据打包到DataItemBuffer 对象中,并将此数据传递到安装在新移动设备上的移动应用。

存档传递后,可穿戴数据层会立即调用onNodeMigrated() 监听器,这与您的应用在 Wear OS 设备写入数据时收到通知的方式类似。

保留传输的数据

保留传输的DataItem 对象是您的应用的责任。数据传递到新移动设备后不久,旧设备上的存档就会被删除。

确保以下每个条件都为真

  1. 您的应用已安装在参与传输的两个移动设备上。
  2. 安装在每个移动设备上的移动应用具有匹配的包签名。

否则,存档的DataItem 对象不会被传递,而是会被丢弃。

接收来自旧移动设备的数据

要在新移动设备上接收在旧移动设备上存档的数据,您的移动应用必须实现onNodeMigrated() 回调(WearableListenerService 类的一部分)。为此,请完成以下步骤:

  1. 在您的移动应用的构建文件中,包含 Google Play 服务中最新版本的可穿戴库的依赖项。

    dependencies {
        ...
        implementation 'com.google.android.gms:play-services-wearable:18.2.0'
    }
  2. 在您的应用的清单文件中声明并导出WearableListenerService

    <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>
    
  3. 创建一个扩展WearableListenerService 并覆盖onNodeMigrated() 的服务类。

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