Transférer des données Wear OS vers un nouvel appareil mobile

Lorsque les utilisateurs configurent un appareil Wear OS, ils le connectent à un appareil mobile particulier. L'utilisateur peut ensuite décider d'acquérir un nouvel appareil mobile et d'y connecter son appareil Wear OS existant. Certaines données liées à un appareil Wear OS sont stockées sur un appareil mobile actuellement connecté.

À partir de Wear OS 4, lorsque les utilisateurs se connectent à un nouvel appareil mobile, ils peuvent y transférer des données Wear OS. Les données sont automatiquement synchronisées lors de leur transfert.

Lorsque l'utilisateur demande un transfert, l'API Wearable Data Layer envoie les objets DataItem, initialement stockés sur un appareil mobile, à l'autre. Cela permet aux utilisateurs de votre application de bénéficier d'une expérience fluide.

Ce document explique comment configurer votre application Wear OS et son application mobile associée pour prendre en charge ce scénario.

Préparation

Le processus de transfert de données gère les objets DataItem différemment, en fonction de l'application propriétaire des données :

Objets appartenant à l'application Wear OS
Ces objets sont conservés sur l'appareil Wear OS.
Objets appartenant à l'application mobile

Ces objets sont archivés sur l'ancien appareil. Le système empaquette ensuite les données archivées dans un objet DataItemBuffer, puis les transmet à l'application mobile installée sur le nouvel appareil mobile.

Immédiatement après la livraison de l'archive, Wearable Data Layer appelle l'écouteur onDataChanged(), de la même manière que votre application est avertie lorsque des données sont écrites par l'appareil Wear OS.

Préserver les données transférées

Il appartient à votre application de préserver les objets DataItem transférés. Peu de temps après la transmission des données au nouvel appareil mobile, l'archive est supprimée de l'ancien.

Assurez-vous que toutes les conditions suivantes sont remplies :

  1. Votre application est installée sur les deux appareils mobiles concernés par le transfert.
  2. Les applications mobiles, installées sur chaque appareil mobile, ont des signatures de package qui correspondent.

Dans le cas contraire, les objets DataItem archivés ne sont pas transmis et sont supprimés.

Recevoir les données de l'ancien appareil mobile

Pour recevoir sur le nouvel appareil mobile des données qui ont été archivées sur l'ancien, votre application doit implémenter le rappel onNodeMigrated(), qui fait partie de la classe WearableListenerService. Pour ce faire, procédez comme suit :

  1. Dans le fichier de compilation de votre application mobile, incluez une dépendance à la dernière version de la bibliothèque connectée dans les services Google Play :

    dependencies {
        ...
        implementation 'com.google.android.gms:play-services-wearable:18.1.0'
    }
    
  2. Déclarez et exportez le WearableListenerService dans le fichier manifeste de votre application :

    <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. Créez une classe de service qui étend WearableListenerService et remplace 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();
        }
    }