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