Trasferire i dati di Wear OS su un nuovo dispositivo mobile

Quando gli utenti configurano un dispositivo Wear OS, lo connettono a un dispositivo mobile specifico. L'utente potrebbe decidere in un secondo momento di acquistare un nuovo dispositivo mobile e collegare il dispositivo Wear OS esistente a questo nuovo dispositivo mobile. Alcuni dati relativi a un dispositivo Wear OS vengono memorizzati sul dispositivo mobile attualmente collegato.

A partire da Wear OS 4, quando gli utenti si connettono a un nuovo dispositivo mobile, possono trasferirvi i dati di Wear OS. I dati vengono sincronizzati automaticamente al momento del trasferimento.

Quando l'utente richiede un trasferimento, il livello dati indossabile recapita DataItem oggetti, originariamente memorizzati su un dispositivo mobile, all'altro dispositivo mobile. Ciò consente agli utenti della tua app di avere un'esperienza fluida.

Questo documento descrive come configurare l'app Wear OS e la relativa app mobile associata in modo da 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 quindi pacchettizza i dati archiviati in un oggetto DataItemBuffer e li invia all'app mobile installata sul nuovo dispositivo mobile.

Subito dopo la consegna dell'archivio, il livello dati indossabile richiama il listener onDataChanged(), in modo simile a come l'app riceve una notifica quando i dati vengono scritti dal dispositivo Wear OS.

Conserva i dati trasferiti

È responsabilità dell'app conservare gli oggetti DataItem trasferiti. Poco dopo che i dati sono stati inviati al nuovo dispositivo mobile, l'archivio viene eliminato dal vecchio dispositivo.

Assicurati che ciascuna delle seguenti condizioni sia vera:

  1. La tua app è installata su entrambi i dispositivi mobili coinvolti nel trasferimento.
  2. Le app mobile, installate su ciascun dispositivo mobile, hanno le firme dei pacchetti corrispondenti.

In caso contrario, gli oggetti DataItem archiviati non vengono consegnati e vengono invece scartati.

Ricevi i dati dal vecchio dispositivo mobile

Per ricevere i dati sul nuovo dispositivo mobile archiviato su quello precedente, la tua app mobile deve implementare il callback onNodeMigrated(), parte della classe WearableListenerService. Per farlo, segui questi passaggi:

  1. Nel file di build della tua app mobile, includi una dipendenza per la versione più recente della libreria indossabile in Google Play Services:

    dependencies {
        ...
        implementation 'com.google.android.gms:play-services-wearable:18.1.0'
    }
    
  2. Dichiara ed esporta WearableListenerService nel file manifest dell'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 si estende WearableListenerService e esegua l'override 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 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)
                }
            }
        }
    }
    
    

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