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

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

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

当用户请求传输时,Wearable Data Layer 会将最初存储在一台移动设备上的 DataItem 对象传输到另一台移动设备。这为您的应用用户带来了无缝体验。

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

准备工作

数据传输过程根据数据归属的应用不同,会以不同的方式处理 DataItem 对象

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

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

存档交付后,Wearable Data Layer 会立即调用 onNodeMigrated() 监听器,类似于您的应用在 Wear OS 设备写入数据时收到通知的方式。

保留传输的数据

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

确保以下每个条件都为真

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

否则,存档的 DataItem 对象将不会交付,而是被丢弃。

从旧移动设备接收数据

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

  1. 在您的移动应用的构建文件中,添加对 Google Play services 中最新版可穿戴设备库的依赖项

    dependencies {
        ...
        implementation 'com.google.android.gms:play-services-wearable:19.0.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.
        }
    }