نقل بيانات Wear OS إلى جهاز جوّال جديد

عندما يُعدّ المستخدمون جهاز Wear OS، فإنّهم يربطون جهاز Wear OS بجهاز جوّال معيّن. قد يقرّر المستخدم لاحقًا الحصول على جهاز جوّال جديد وربط جهاز Wear OS الحالي به. يتم تخزين بعض البيانات المرتبطة بجهاز Wear OS على الجهاز الجوّال المتصل حاليًا.

اعتبارًا من الإصدار 4 من Wear OS، عندما يربط المستخدمون الساعة بجهاز جوّال جديد، يمكنهم نقل بيانات Wear OS إلى الجهاز الجوّال الجديد. تتم مزامنة البيانات تلقائيًا عند نقلها.

عندما يطلب المستخدم نقل البيانات، تقدّم طبقة بيانات الأجهزة القابلة للارتداء عناصر DataItem المخزّنة في الأصل على أحد الأجهزة الجوّالة إلى الجهاز الجوّال الآخر. ويتيح ذلك تجربة سلسة لمستخدمي تطبيقك.

يوضّح هذا المستند كيفية ضبط تطبيق Wear OS وتطبيق الجوّال المصاحب له لإتاحة هذا السيناريو.

الإعداد

تتعامل عملية نقل البيانات مع عناصر DataItem بشكل مختلف، وذلك حسب التطبيق الذي يملك البيانات:

العناصر التي يملكها تطبيق Wear OS
يتم الاحتفاظ بهذه العناصر على جهاز Wear OS.
العناصر التي يملكها تطبيق الأجهزة الجوّالة

يتم أرشفة هذه العناصر على الجهاز القديم. بعد ذلك، يحوّل النظام البيانات المؤرشفة إلى عنصر DataItemBuffer ويسلّم هذه البيانات إلى التطبيق المتوافق مع الأجهزة الجوّالة المثبَّت على الجهاز الجوّال الجديد.

بعد تسليم الأرشيف مباشرةً، تستدعي "طبقة بيانات الأجهزة القابلة للارتداء" أداة الاستماع onNodeMigrated()، على غرار الطريقة التي يتم بها إعلام تطبيقك عند كتابة البيانات بواسطة جهاز Wear OS.

الاحتفاظ بالبيانات المنقولة

يقع على عاتق تطبيقك مسؤولية الحفاظ على عناصر DataItem التي تم نقلها. بعد وقت قصير من تسليم البيانات إلى الجهاز الجوّال الجديد، يتم حذف الأرشيف من الجهاز القديم.

تأكَّد من توفُّر الشروط التالية:

  1. يجب أن يكون تطبيقك مثبَّتًا على كلا الجهازَين الجوّالَين المشاركَين في عملية النقل.
  2. تحتوي تطبيقات الأجهزة الجوّالة المثبَّتة على كل جهاز جوّال على تواقيع حزمة متطابقة.

وبخلاف ذلك، لن يتم تسليم عناصر DataItem المؤرشفة، وسيتم بدلاً من ذلك تجاهلها.

تلقّي البيانات من الجهاز الجوّال القديم

لتلقّي البيانات على الجهاز الجوّال الجديد التي تم أرشفتها على الجهاز الجوّال القديم، يجب أن ينفّذ تطبيقك على الجهاز الجوّال وظيفة الاستدعاء onNodeMigrated()، وهي جزء من فئة WearableListenerService. لإجراء ذلك، أكمل الخطوات التالية:

  1. في ملف الإصدار لتطبيقك على الأجهزة الجوّالة، أدرِج عنصرًا تابعًا لأحدث إصدار من مكتبة الأجهزة القابلة للارتداء في "خدمات Google Play":

    dependencies {
        ...
        implementation 'com.google.android.gms:play-services-wearable:19.0.0'
    }
  2. عليك تعريف WearableListenerService وتصديره في ملف البيان الخاص بتطبيقك:

    <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. أنشئ فئة خدمة توسّع WearableListenerService وتتجاوز 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.
        }
    }