Trasferire i dati di Wear OS su un nuovo dispositivo mobile

Quando gli utenti configurano un dispositivo Wear OS, lo connettono a un determinato dispositivo mobile. In un secondo momento, l'utente potrebbe decidere di acquistare un nuovo dispositivo mobile e collegare il proprio dispositivo Wear OS esistente a questo nuovo dispositivo mobile. Alcuni dati relativi a un dispositivo Wear OS vengono archiviati sul dispositivo mobile attualmente connesso.

A partire da Wear OS 4, quando gli utenti si connettono a un nuovo dispositivo mobile, possono trasferire i dati di Wear OS sul nuovo dispositivo mobile. I dati vengono sincronizzati automaticamente quando vengono trasferiti.

Quando l'utente richiede un trasferimento, il Livello dati per dispositivi indossabili invia gli oggetti DataItem, originariamente archiviati su un dispositivo mobile, all'altro dispositivo mobile. In questo modo, gli utenti della tua app avranno un'esperienza fluida.

Questo documento descrive come configurare l'app Wear OS e la relativa app mobile complementare per supportare questo scenario.

Preparazione

Il processo di trasferimento dei dati gestisce gli oggetti DataItem in modo diverso, a seconda dell'app proprietaria dei dati:

Oggetti di proprietà dell'app Wear OS
Questi oggetti vengono conservati sul dispositivo Wear OS.
Oggetti di proprietà dell'app mobile

Questi oggetti vengono archiviati sul vecchio dispositivo. Il sistema pacchettizza quindi i dati archiviati in un oggetto DataItemBuffer e li invia all'app mobile installata sul nuovo dispositivo mobile.

Immediatamente dopo l'invio dell'archivio, Wearable Data Layer invoca l'ascoltatore onNodeMigrated(), in modo simile a come viene inviata una notifica all'app quando i dati vengono scritti dal dispositivo Wear OS.

Conservare i dati trasferiti

È responsabilità della tua app preservare gli oggetti DataItem trasferiti. Poco dopo che i dati sono stati caricati sul nuovo dispositivo mobile, l'archivio viene eliminato dal vecchio dispositivo.

Assicurati che siano soddisfatte le seguenti condizioni:

  1. La tua app sia installata su entrambi i dispositivi mobili coinvolti nel trasferimento.
  2. Le app mobile installate su ogni dispositivo mobile hanno firme del pacchetto corrispondenti.

In caso contrario, gli oggetti DataItem archiviati non vengono pubblicati e vengono invece eliminati.

Ricevere i dati dal vecchio dispositivo mobile

Per ricevere sul nuovo dispositivo mobile i dati archiviati sul vecchio dispositivo mobile, la tua app mobile deve implementare il callback onNodeMigrated(), che fa parte della classe WearableListenerService. Per farlo, segui questa procedura.

  1. Nel file di compilazione dell'app mobile, includi una dipendenza dalla versione più recente della libreria per dispositivi indossabili in Google Play Services:

    dependencies {
        ...
        implementation 'com.google.android.gms:play-services-wearable:19.0.0'
    }
  2. Dichiara ed esporta WearableListenerService nel file manifest della tua app:

    <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. Crea una classe di servizio che estenda WearableListenerService e sostituisca 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.
        }
    }