Как перенести данные 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:20.0.1'
    }
    
  2. Объявите и экспортируйте WearableListenerService в файле манифеста приложения:

    <service
        android:name=".snippets.datalayer.MyWearableListenerService"
        android:exported="true"
        tools:ignore="ExportedService">
        <intent-filter>
            <action android:name="com.google.android.gms.wearable.NODE_MIGRATED" />
            <data android:scheme="wear" android:host="*" />
        </intent-filter>
    </service>

  3. Создайте класс сервиса, который расширяет WearableListenerService и переопределяет onNodeMigrated().

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