目录

App Continuation for Data Migration

Overview

For app continuation, you need to select a proper data migration solution. Selecting a migration solution is directly related to data volume and whether file migration is involved, as described in the following table.

  

< 100 KB

> 100 KB

File migration is required

Migrating File Assets

Migrating File Assets

File migration is not required

Using want.param for Data Migration

Basic Data Migration

How to Implement

For details about the implementation principles, see Working Principles.

How to Develop

To implement app continuation, you need to enable the app continuation capability, configure the app launch type, save migration data on the source device, and restore data on the target device. For details about the development process, see App Continuation Overview. This topic only describes how to select a data migration solution in different scenarios.

Using want.param for Data Migration

  1. Save migration data on the source device.
    // ...
    export default class EntryAbility extends UIAbility {
      // ...
      onContinue(wantParam: Record<string, Object>) {
        const continueInput = 'Data to migrate';
        if (continueInput) {
          wantParam['data'] = continueInput;
        }
        // ...
        return AbilityConstant.OnContinueResult.AGREE;
      }
      // ...
    }
  2. Restore data on the target device.
    export default class EntryAbility extends UIAbility {
      storage: LocalStorage = new LocalStorage();
      onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
        if (launchParam.launchReason === AbilityConstant.LaunchReason.CONTINUATION) {
          let continueInput = '';
          if (want.parameters !== undefined) {
            continueInput = JSON.stringify(want.parameters.data);
            console.info(`continue input ${continueInput}`)
          }
          // ...
          this.context.restoreWindowStage(this.storage);
        }
        // ...
      }
    
      // ...
    }

Using Distributed Data Objects for Data Migration

[h2]Basic Data Migration

  1. Save migration data on the source device.

    Create a distributed data object in onContinue() of the source UIAbility and save the data. The execution process is as follows:

    1. Call create() in onContinue() to create a distributed data object and fill the data to be migrated into the distributed data object.
    2. Call genSessionId() to generate a networking ID for the distributed data object. The distributed data object calls setSessionId() to pass the ID to activate the distributed data object.
    3. Call save() to persist the activated distributed data object. This ensures that the app on the target device can continue to access the data even if the app on the source device exits.
    4. Pass the generated sessionId to the target app through want. The sessionId is used to activate the distributed data object of the target app and transfer data to the target app.
    • The distributed data object needs to be activated and then persisted. Therefore, save() must be called after setSessionId() is called.
    • To prevent the app on the source device from exiting before the data migrated to the target device is saved, use await to wait until save() is complete. Starting from API version 12, an asynchronous onContinue() API is provided for this scenario.
    • Currently, the sessionId field in wantParams is used by the system during migration. You are advised to define other key values in wantParams to store the session ID generated for the distributed data object to avoid exceptions.
    import { UIAbility, AbilityConstant, Want } from '@kit.AbilityKit';
    import { distributedDataObject } from '@kit.ArkData';
    import { BusinessError } from '@kit.BasicServicesKit';
    import { hilog } from '@kit.PerformanceAnalysisKit';
    // ...
    
    const TAG: string = '[MigrationAbility]';
    const DOMAIN_NUMBER: number = 0xFF00;
    class ParentObject {
      mother: string
      father: string
    
      constructor(mother: string, father: string) {
        this.mother = mother
        this.father = father
      }
    }
    
    class SourceObject {
      name: string | undefined
      age: number | undefined
      isVis: boolean | undefined
      parent: ParentObject | undefined
    
      constructor(name: string | undefined, age: number | undefined, isVis: boolean | undefined, parent: ParentObject | undefined) {
        this.name = name
        this.age = age
        this.isVis = isVis
        this.parent = parent
      }
    }
    
    export default class MigrationAbility extends UIAbility {
      d_object?: distributedDataObject.DataObject;
      // ...
    
      // ...
    
      async onContinue(wantParam: Record<string, Object>): Promise<AbilityConstant.OnContinueResult> {
        // ...
        let parentSource: ParentObject = new ParentObject('jack mom', 'jack Dad');
        let source: SourceObject = new SourceObject('jack', 18, false, parentSource);
    
        this.d_object = distributedDataObject.create(this.context, source);
    
        let dataSessionId: string = distributedDataObject.genSessionId();
        this.d_object.setSessionId(dataSessionId);
    
        wantParam['dataSessionId'] = dataSessionId;
    
        
        try {
          await this.d_object.save(wantParam.targetDevice as string);
        } catch (error) {
          hilog.error(DOMAIN_NUMBER, TAG, 'Failed to save. Error: ', JSON.stringify(error) ?? '');
        }
    
        // ...
      }
    
      // ...
    }
  2. Restore data on the target device.

    In onCreate() or onNewWant() of the target UIAbility, add the same networking ID to the distributed data object on the target device to restore data. The process is as follows:

    1. Create an empty distributed data object for receiving data to be restored.
    2. Read the networking ID of the distributed data object from want.
    3. Register on() to listen for data changes of the distributed data object. In the callback of the event whose status is restore, implement the operation to be performed when the data restoration is complete.
    4. Call setSessionId() to connect the target app to the network and activate the distributed data object.
    • The distributed data object of the target app connected to the network cannot be a temporary variable. Since on() for the distributed data object uses an asynchronous callback and may be executed after onCreate() or onNewWant() is complete. The temporary variable will be released, which causes a null pointer exception. You can use class member variables to avoid this exception.
    • Before a distributed data object on the target device is activated, set the attribute of the object used to create the distributed data object to undefined. Otherwise, the data on the source device will be overwritten by new data after the distributed data object is connected to the network, and data restore will fail.
    • Before activating a distributed data object, call on() of the object to register listening to prevent data restore failure caused by missing the restore event.
    const TAG: string = '[MigrationAbility]';
    const DOMAIN_NUMBER: number = 0xFF00;
    
    export default class MigrationAbility extends UIAbility {
      d_object?: distributedDataObject.DataObject;
      // ...
    
      onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
        if (launchParam.launchReason === AbilityConstant.LaunchReason.CONTINUATION) {
          this.handleDistributedData(want);
        }
      }
    
      onNewWant(want: Want, launchParam: AbilityConstant.LaunchParam): void {
        if (launchParam.launchReason === AbilityConstant.LaunchReason.CONTINUATION) {
          if (want.parameters !== undefined) {
            this.handleDistributedData(want);
          }
        }
      }
    
      handleDistributedData(want: Want) {
        let remoteSource: SourceObject = new SourceObject(undefined, undefined, undefined, undefined);
        this.d_object = distributedDataObject.create(this.context, remoteSource);
        let dataSessionId = '';
        if (want.parameters !== undefined) {
          dataSessionId = want.parameters.dataSessionId as string;
        }
        this.d_object.on('status', (sessionId: string, networkId: string, status: 'online' | 'offline' | 'restored') => {
          hilog.info(DOMAIN_NUMBER, TAG, 'status changed ' + sessionId + ' ' + status + ' ' + networkId);
          if (status === 'restored') {
            if (this.d_object) {
              hilog.info(DOMAIN_NUMBER, TAG, 'restored name:' + this.d_object['name']);
              hilog.info(DOMAIN_NUMBER, TAG, 'restored parents:' + JSON.stringify(this.d_object['parent']));
              // ...
            }
          }
        });
        this.d_object.setSessionId(dataSessionId);
      }
    
      // ...
    
      // ...
    }

[h2]Migrating File Assets