Przenoszenie danych z Wear OS na nowe urządzenie mobilne

Gdy użytkownicy skonfigurują urządzenie z Wear OS, połączą je z konkretnym 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 dotyczące urządzenia z Wear OS są przechowywane na aktualnie połączonym urządzeniu mobilnym.

Od wersji Wear OS 4 użytkownicy mogą przenosić dane z Wear OS na nowe urządzenie mobilne po połączeniu z nim. Dane są synchronizowane automatycznie po ich przeniesieniu.

Gdy użytkownik poprosi o przeniesienie, warstwę danych na urządzeniu do noszenia przesyła obiekty DataItem, które były pierwotnie przechowywane na jednym urządzeniu mobilnym, na inne urządzenie mobilne. Dzięki temu użytkownicy aplikacji mogą korzystać z usługi bezproblemowo.

Z tego dokumentu dowiesz się, jak skonfigurować aplikację na Wear OS i jej aplikację mobilną, aby obsługiwała ten scenariusz.

Przygotowanie

Proces przenoszenia danych obsługuje obiekty DataItem w różny sposób w zależności od tego, do której aplikacji należą dane:

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

Te obiekty są archiwizowane na starym urządzeniu. Następnie system pakuje zapisane dane w obiekt DataItemBuffer i przekazuje je do aplikacji mobilnej zainstalowanej na nowym urządzeniu mobilnym.

Bezpośrednio po dostarczeniu archiwu warstwy danych urządzenia noszonego wywołuje się odbiornik onNodeMigrated(), podobnie jak w przypadku powiadomień aplikacji o zapisywaniu danych przez urządzenie z Wear OS.

Zachowanie przeniesionych danych

Twoja aplikacja musi zachować przeniesione obiekty DataItem. Krótko po przesłaniu 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, które biorą udział w przenoszeniu.
  2. Aplikacje mobilne zainstalowane na każdym urządzeniu mobilnym mają odpowiadające sobie podpisy pakietów.

W przeciwnym razie zapisane obiekty DataItem nie są dostarczane, tylko 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ć funkcję wywołania zwrotnego onNodeMigrated(), która jest częścią klasy WearableListenerService. Aby to zrobić:

  1. W pliku kompilacji aplikacji mobilnej dodaj zależność od najnowszej wersji biblioteki na urządzenia noszące 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 klasę WearableListenerService i zastępuje klasę 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.
        }
    }