העברת נתוני Wear OS למכשיר נייד חדש

כשמשתמשים מגדירים מכשיר Wear OS, הם מחברים את מכשיר Wear OS למכשיר נייד מסוים. יכול להיות שהמשתמש יחליט מאוחר יותר לרכוש מכשיר נייד חדש ולחבר את מכשיר Wear OS הקיים שלו למכשיר הנייד החדש. חלק מהנתונים שקשורים למכשיר Wear OS מאוחסנים במכשיר הנייד המחובר כרגע.

החל מגרסה 4 של Wear OS, כשמשתמשים מתחברים למכשיר נייד חדש, הם יכולים להעביר את הנתונים מ-Wear OS למכשיר הנייד החדש. הנתונים מסתנכרנים באופן אוטומטי בזמן ההעברה.

כשהמשתמש מבקש העברה, שכבת הנתונים של מכשירי לבישה מעבירה את האובייקטים מסוג DataItem, שנשמרו במקור במכשיר נייד אחד, למכשיר הנייד השני. כך משתמשים באפליקציה נהנים מחוויה חלקה.

במאמר הזה מוסבר איך להגדיר את האפליקציה ל-Wear OS ואת האפליקציה לנייד שלה כדי לתמוך בתרחיש הזה.

הכנה

תהליך העברת הנתונים מטפל באובייקטים מסוג DataItem באופן שונה, בהתאם לאפליקציה שבבעלותה הנתונים:

אובייקטים שבבעלות אפליקציית Wear OS
האובייקטים האלה נשמרים במכשיר Wear OS.
אובייקטים שבבעלות האפליקציה לנייד

האובייקטים האלה מועברים לארכיון במכשיר הישן. לאחר מכן המערכת אורזת את הנתונים ששמורים בארכיון באובייקט DataItemBuffer ומעבירה את הנתונים האלה לאפליקציה לנייד שמותקנת במכשיר הנייד החדש.

מיד אחרי שהארכיון נמסר, שכבת הנתונים של Wearable מפעילה את המאזין onNodeMigrated(), בדומה לאופן שבו האפליקציה מקבלת התראה כשנתונים נכתבים על ידי מכשיר Wear OS.

שמירה של הנתונים המועברים

האפליקציה שלכם אחראית לשמור את אובייקטי ה-DataItem שהועברו. זמן קצר אחרי שהנתונים מועברים למכשיר הנייד החדש, הארכיון נמחק מהמכשיר הישן.

מוודאים שכל אחד מהתנאים הבאים מתקיים:

  1. האפליקציה מותקנת בשני המכשירים הניידים שמעורבים בהעברה.
  2. לחתימות החבילות של האפליקציות לנייד, שמותקנות בכל מכשיר נייד, יש תואם.

אחרת, אובייקטי ה-DataItem ששמורים בארכיון לא נשלחים, אלא נמחקים.

קבלת נתונים מהמכשיר הנייד הישן

כדי לקבל במכשיר הנייד החדש נתונים שהועברו לארכיון במכשיר הנייד הישן, האפליקציה לנייד צריכה להטמיע את פונקציית ה-callback‏ onNodeMigrated(), שמהווה חלק מהקלאס WearableListenerService. כדי לעשות זאת, מבצעים את השלבים הבאים:

  1. בקובץ ה-build של האפליקציה לנייד, צריך לכלול יחסי תלות לגרסה העדכנית של ספריית Google Play Services להתקנים לבישים:

    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.
        }
    }