Transferir dados do Wear OS para um novo dispositivo móvel

Quando os usuários configuram um dispositivo Wear OS, eles o conectam a um dispositivo móvel específico. Mais tarde, o usuário pode decidir comprar um novo dispositivo móvel e conectar o dispositivo Wear OS a ele. Alguns dados relacionados a um dispositivo Wear OS são armazenados no dispositivo móvel conectado no momento.

A partir do Wear OS 4, os usuários podem transferir dados do Wear OS para um novo dispositivo móvel. Esses dados são sincronizados automaticamente ao serem transferidos.

Quando o usuário solicita uma transferência, a camada de dados wearable envia objetos DataItem, originalmente armazenados em um dispositivo móvel, para outro dispositivo. Isso proporciona a melhor experiência aos usuários do seu app.

Este documento descreve como configurar o app para Wear OS e o app complementar para dispositivos móveis, para dar suporte a esse cenário.

Preparação

O processo de transferência de dados processa objetos DataItem de maneira diferente, dependendo de qual app é o proprietário dos dados:

Objetos que pertencem ao app para Wear OS
Esses objetos são preservados no dispositivo Wear OS.
Objetos que pertencem ao app para dispositivos móveis

Esses objetos são arquivados no dispositivo antigo. Em seguida, o sistema empacota os dados arquivados em um objeto DataItemBuffer e os entrega ao app para dispositivos móveis instalado no novo dispositivo.

Imediatamente após o envio do arquivo, a camada de dados wearable invoca o listener onNodeMigrated(), da mesma forma que o app é notificado quando os dados são gravados pelo dispositivo Wear OS.

Preservar dados transferidos

É responsabilidade do app preservar os objetos DataItem transferidos. Logo após a entrega dos dados ao novo dispositivo móvel, o arquivo é excluído do dispositivo antigo.

Confira se todas as condições abaixo são verdadeiras:

  1. O app está instalado nos dois dispositivos móveis envolvidos na transferência.
  2. Os apps instalados em cada dispositivo móvel têm assinaturas de pacote correspondentes.

Caso contrário, os objetos DataItem arquivados não serão entregues e serão descartados.

Receber dados do dispositivo móvel antigo

Para receber dados que foram arquivado no dispositivo móvel antigo no novo dispositivo móvel, seu app precisa implementar o callback onNodeMigrated(), parte da classe WearableListenerService. Para isso, siga estas etapas:

  1. No arquivo de build do app para dispositivos móveis, inclua uma dependência da versão mais recente da biblioteca de wearables no Google Play Services:

    dependencies {
        ...
        implementation 'com.google.android.gms:play-services-wearable:18.2.0'
    }
  2. Declare e exporte o WearableListenerService no arquivo de manifesto do seu 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. Crie uma classe de serviço que estenda WearableListenerService e modifique 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.
        }
    }