Перенос данных Wear OS на новое мобильное устройство

Когда пользователи настраивают устройство Wear OS , они подключают устройство Wear OS к определенному мобильному устройству. Позже пользователь может решить приобрести новое мобильное устройство и подключить существующее устройство Wear OS к этому новому мобильному устройству. Некоторые данные, относящиеся к устройству Wear OS, хранятся на подключенном в данный момент мобильном устройстве.

Начиная с Wear OS 4, когда пользователи подключаются к новому мобильному устройству, они могут передавать данные Wear OS на новое мобильное устройство. Данные синхронизируются автоматически при передаче.

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

В этом документе описывается, как настроить приложение Wear OS и сопутствующее мобильное приложение для поддержки этого сценария.

Подготовка

Процесс передачи данных обрабатывает объекты DataItem по-разному, в зависимости от того, какое приложение владеет данными:

Объекты, принадлежащие приложению Wear OS
Эти объекты сохраняются на устройстве Wear OS.
Объекты, принадлежащие мобильному приложению

Эти объекты заархивированы на старом устройстве. Затем система упаковывает архивированные данные в объект DataItemBuffer и доставляет эти данные в мобильное приложение, установленное на новом мобильном устройстве.

Сразу после доставки архива уровень носимых данных вызывает прослушиватель onDataChanged() , аналогично тому, как ваше приложение уведомляется, когда данные записываются устройством 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() .

    Котлин

    
    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 suspend 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())
                }
            }
    
            CoroutineScope(Job() + Dispatchers.IO).launch {
                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 void 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;
                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());
                }
            }
    
            Thread thread = new Thread(() -> {
                for (DataItem dataItem : dataItemsToHandle) {
                    handleDataItem(nodeId, dataItem);
                }
            });
            thread.start();
        }
    }
    
    
{% дословно %} {% дословно %} {% дословно %} {% дословно %}