Chuyển dữ liệu trên Wear OS sang thiết bị di động mới

Khi thiết lập thiết bị Wear OS, người dùng sẽ kết nối thiết bị Wear OS đó với một thiết bị di động cụ thể. Sau đó, người dùng có thể quyết định mua một thiết bị di động mới và kết nối thiết bị Wear OS hiện tại của họ với thiết bị di động mới này. Một số dữ liệu liên quan đến thiết bị Wear OS được lưu trữ trên thiết bị di động hiện đã kết nối.

Kể từ Wear OS 4, khi người dùng kết nối với một thiết bị di động mới, họ có thể chuyển dữ liệu Wear OS sang thiết bị di động mới đó. Các dữ liệu này sẽ được đồng bộ hoá tự động khi được chuyển đi.

Khi người dùng yêu cầu chuyển dữ liệu, Lớp dữ liệu trên thiết bị đeo sẽ phân phối các đối tượng DataItem (ban đầu được lưu trữ trên một thiết bị di động) sang thiết bị di động khác. Điều này giúp mang lại một trải nghiệm liền mạch cho người dùng ứng dụng của bạn.

Tài liệu này mô tả cách bạn có thể định cấu hình ứng dụng Wear OS và ứng dụng đồng hành cho thiết bị di động để hỗ trợ trường hợp này.

Chuẩn bị

Quá trình chuyển dữ liệu xử lý các đối tượng DataItem theo nhiều cách, tuỳ thuộc vào việc ứng dụng nào sở hữu dữ liệu này:

Các đối tượng do ứng dụng Wear OS sở hữu
Các đối tượng này được lưu giữ trên thiết bị Wear OS.
Đối tượng do ứng dụng di động sở hữu

Các đối tượng này được lưu trữ trên thiết bị cũ. Sau đó, hệ thống sẽ đóng gói dữ liệu được lưu trữ vào một đối tượng DataItemBuffer rồi phân phối dữ liệu này sang ứng dụng di động được cài đặt trên thiết bị di động mới.

Ngay sau khi tệp lưu trữ được phân phối, Lớp dữ liệu trên thiết bị đeo sẽ gọi trình nghe onDataChanged(), tương tự như cách ứng dụng được thông báo khi thiết bị Wear OS ghi dữ liệu.

Giữ nguyên dữ liệu được chuyển

Ứng dụng của bạn có trách nhiệm lưu giữ các đối tượng DataItem được chuyển. Ngay sau khi dữ liệu được phân phối đến thiết bị di động mới, bản lưu trữ sẽ được xoá khỏi thiết bị cũ.

Hãy đảm bảo mọi điều kiện sau đây đều được đáp ứng:

  1. Ứng dụng của bạn được cài đặt trên cả hai thiết bị di động có tham gia vào quá trình chuyển đổi.
  2. Các ứng dụng di động (được cài đặt trên từng thiết bị di động) có chữ ký gói trùng khớp với nhau.

Nếu không, các đối tượng DataItem đã lưu trữ sẽ không được phân phối và thay vào đó, các đối tượng này sẽ bị loại bỏ.

Nhận dữ liệu từ thiết bị di động cũ

Để nhận dữ liệu trên thiết bị di động mới đã được lưu trữ trên thiết bị di động cũ, ứng dụng di động của bạn phải triển khai lệnh gọi lại onNodeMigrated(), một phần của lớp WearableListenerService. Để làm như vậy, vui lòng hoàn thành các bước sau:

  1. Trong tệp bản dựng của ứng dụng di động, hãy đưa phần phụ thuộc vào phiên bản mới nhất của thư viện thiết bị đeo trong Dịch vụ Google Play:

    dependencies {
        ...
        implementation 'com.google.android.gms:play-services-wearable:18.1.0'
    }
    
  2. Khai báo rồi xuất WearableListenerService trong tệp kê khai của ứng dụng:

    <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. Tạo một lớp dịch vụ mở rộng WearableListenerService rồi ghi đè 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();
        }
    }