Перенос данных 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 и доставляет эти данные в мобильное приложение, установленное на новом мобильном устройстве.

Сразу после доставки архива уровень данных носимых устройств вызывает прослушиватель onNodeMigrated() , аналогично тому, как ваше приложение уведомляется о записи данных устройством Wear OS.

Сохранение переданных данных

Ваше приложение несет ответственность за сохранение переданных объектов DataItem . Вскоре после доставки данных на новое мобильное устройство архив удаляется со старого устройства.

Убедитесь, что каждое из следующих условий выполняется:

  1. Ваше приложение установлено на обоих мобильных устройствах, участвующих в передаче.
  2. Мобильные приложения, установленные на каждом мобильном устройстве, имеют совпадающие подписи пакетов.

В противном случае заархивированные объекты DataItem не доставляются и удаляются.

Получите данные со старого мобильного устройства

Чтобы получить данные на новом мобильном устройстве, которые были заархивированы на старом мобильном устройстве, ваше мобильное приложение должно реализовать обратный вызов onNodeMigrated() , часть класса WearableListenerService . Для этого выполните следующие шаги:

  1. В файле сборки вашего мобильного приложения включите зависимость от последней версии библиотеки носимых устройств в сервисах Google Play:

    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() .

    Котлин

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

    Ява

    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.
        }
    }
{% дословно %} {% endverbatim %} {% дословно %} {% endverbatim %}