Przenoszenie danych z Wear OS na nowe urządzenie mobilne

Gdy użytkownicy konfigurują urządzenie z Wear OS, łączą je z określonym urządzeniem mobilnym. Użytkownik może później zdecydować się na zakup nowego urządzenia mobilnego i połączyć z nim dotychczasowe urządzenie z Wear OS. Niektóre dane związane z urządzeniem z Wear OS są przechowywane na aktualnie połączonym urządzeniu mobilnym.

Od Wear OS 4, gdy użytkownicy połączą się z nowym urządzeniem mobilnym, będą mogli przenieść na nie dane z Wear OS. Dane są synchronizowane automatycznie podczas przenoszenia.

Gdy użytkownik poprosi o przeniesienie danych, warstwa danych urządzenia do noszenia dostarczy obiekty DataItem, które były pierwotnie przechowywane na jednym urządzeniu mobilnym, na drugie urządzenie mobilne. Zapewnia to użytkownikom aplikacji płynną obsługę.

Z tego dokumentu dowiesz się, jak skonfigurować aplikację na Wear OS i jej aplikację towarzyszącą na urządzenia mobilne, aby obsługiwały ten scenariusz.

Przygotowanie

Proces przenoszenia danych obsługuje obiekty DataItem w różny sposób w zależności od tego, która aplikacja jest właścicielem danych:

Obiekty należące do aplikacji na Wear OS
Te obiekty są zachowywane na urządzeniu z Wear OS.
Obiekty należące do aplikacji mobilnej

Te obiekty są archiwizowane na starym urządzeniu. System pakuje następnie zarchiwizowane dane w obiekt DataItemBuffer i przesyła je do aplikacji mobilnej zainstalowanej na nowym urządzeniu.

Natychmiast po dostarczeniu archiwum warstwa danych urządzenia do noszenia wywołuje odbiornik onNodeMigrated(), podobnie jak aplikacja jest powiadamiana, gdy dane są zapisywane przez urządzenie z Wear OS.

Zachowywanie przeniesionych danych

Obowiązkiem aplikacji jest zachowanie przeniesionych obiektów DataItem. Krótko po dostarczeniu danych na nowe urządzenie mobilne archiwum zostanie usunięte ze starego urządzenia.

Upewnij się, że spełnione są te warunki:

  1. Aplikacja jest zainstalowana na obu urządzeniach mobilnych biorących udział w przenoszeniu.
  2. Aplikacje mobilne zainstalowane na poszczególnych urządzeniach mobilnych mają pasujące do siebie podpisy pakietów.

W przeciwnym razie zarchiwizowane obiekty DataItem nie są dostarczane, ale odrzucane.

Odbieranie danych ze starego urządzenia mobilnego

Aby otrzymywać na nowym urządzeniu mobilnym dane zarchiwizowane na starym urządzeniu mobilnym, aplikacja mobilna musi implementować wywołanie zwrotne onNodeMigrated(), które jest częścią klasy WearableListenerService. Aby to zrobić, wykonaj te czynności:

  1. W pliku kompilacji aplikacji mobilnej uwzględnij zależność od najnowszej wersji biblioteki Wear w Usługach Google Play:

    dependencies {
        ...
        implementation 'com.google.android.gms:play-services-wearable:19.0.0'
    }
  2. Zadeklaruj i wyeksportuj WearableListenerService w pliku manifestu aplikacji:

    <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. Utwórz klasę usługi, która rozszerza WearableListenerService i zastępuje 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.
        }
    }