<100kb | >100kb | |
|---|---|---|
需要文件迁移 | ||
不需要文件迁移 |
export default class EntryAbility extends UIAbility {
// ...
async onContinue(wantParam: Record<string, Object | undefined>): Promise<AbilityConstant.OnContinueResult> {
// ...
// Migrate simple data using wantParam.param
wantParam.wantBasicData = AppStorage.get('wantBasicData');
// ...
// Return AGREE to allow cross-device migration
return AbilityConstant.OnContinueResult.AGREE;
}
// ...
} export default class EntryAbility extends UIAbility {
private distributedObject: distributedDataObject.DataObject | undefined = undefined;
private storage: LocalStorage = new LocalStorage();
private distributedFileUtil: DistributedFileUtil | undefined = undefined;
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
hilog.info(DOMAIN, TAG, FORMAT, `Ability onCreate`);
this.distributedFileUtil = new DistributedFileUtil(this.context);
this.appContinuity(want, launchParam);
}
onNewWant(want: Want, launchParam: AbilityConstant.LaunchParam): void {
hilog.info(DOMAIN, TAG, FORMAT, `Ability onNewWant`);
this.appContinuity(want, launchParam);
}
appContinuity(want: Want, launchParam: AbilityConstant.LaunchParam) {
if (launchParam.launchReason === AbilityConstant.LaunchReason.CONTINUATION) {
if (want.parameters !== undefined) {
// Use want.param to migrate the simple data page data
AppStorage.setOrCreate('wantBasicData', want.parameters.wantBasicData);
}
// ...
try {
// Restore window stage with new LocalStorage instance
this.context.restoreWindowStage(this.storage);
} catch (err) {
hilog.error(DOMAIN, TAG, FORMAT, `RestoreWindowStage failed. Cause : ${err}`);
}
}
}
// ...
} 在源端UIAbility的onContinue()接口中创建分布式数据对象并保存数据,执行流程如下:
export class ContinuationData {
public basicDataStr: string | undefined;
public basicDataNum: number | undefined;
public distributedData: DistributedData | undefined;
// ...
constructor(
basicDataStr: string | undefined,
basicDataNum: number | undefined,
distributedData: DistributedData | undefined,
// ...
) {
this.basicDataStr = basicDataStr;
this.basicDataNum = basicDataNum;
this.distributedData = distributedData;
// ...
}
// ...
} export default class EntryAbility extends UIAbility {
private distributedObject: distributedDataObject.DataObject | undefined = undefined;
private storage: LocalStorage = new LocalStorage();
private distributedFileUtil: DistributedFileUtil | undefined = undefined;
// ...
async onContinue(wantParam: Record<string, Object | undefined>): Promise<AbilityConstant.OnContinueResult> {
if (!this.distributedFileUtil) {
return AbilityConstant.OnContinueResult.REJECT;
}
// ...
let sessionId: string = distributedDataObject.genSessionId();
wantParam.distributedSessionId = sessionId;
// ...
let contentInfo: ContinuationData = new ContinuationData(
AppStorage.get('basicDataStr') ?? '',
AppStorage.get('basicDataNum') ?? undefined,
AppStorage.get('distributedData') ?? undefined,
// ...
(AppStorage.get('pageInfos') as NavPathStack).getAllPathName()[0]
);
let source = await contentInfo.flatAssets();
this.distributedObject = distributedDataObject.create(this.context, source);
this.distributedObject.setSessionId(sessionId).catch((err: BusinessError) => {
hilog.info(DOMAIN, TAG, FORMAT, `SetSessionId failed. Cause code: ${err.code}`);
});
await this.distributedObject.save(wantParam.targetDevice as string).catch((err: BusinessError) => {
hilog.info(DOMAIN, TAG, FORMAT, `Failed to save. Code: ${err.code}`);
});
// Return AGREE to allow cross-device migration
return AbilityConstant.OnContinueResult.AGREE;
}
// ...
} 在对端UIAbility的onCreate()/onNewWant()中,通过加入与源端一致的分布式数据对象组网进行数据恢复。执行流程如下:
export default class EntryAbility extends UIAbility {
private distributedObject: distributedDataObject.DataObject | undefined = undefined;
private storage: LocalStorage = new LocalStorage();
private distributedFileUtil: DistributedFileUtil | undefined = undefined;
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
hilog.info(DOMAIN, TAG, FORMAT, `Ability onCreate`);
this.distributedFileUtil = new DistributedFileUtil(this.context);
this.appContinuity(want, launchParam);
}
onNewWant(want: Want, launchParam: AbilityConstant.LaunchParam): void {
hilog.info(DOMAIN, TAG, FORMAT, `Ability onNewWant`);
this.appContinuity(want, launchParam);
}
appContinuity(want: Want, launchParam: AbilityConstant.LaunchParam) {
if (launchParam.launchReason === AbilityConstant.LaunchReason.CONTINUATION) {
// ...
let mailInfo: ContinuationData = new ContinuationData(undefined, undefined, undefined, undefined, undefined,
undefined, undefined, undefined, undefined, undefined);
this.distributedObject = distributedDataObject.create(this.context, mailInfo);
// Add a data restored listener.
try {
this.distributedObject.on('status',
(_sessionId: string, _networkId: string, status: 'online' | 'offline' | 'restored') => {
if (status === 'restored') {
if (!this.distributedObject || !this.distributedFileUtil) {
return;
}
// Use the distributed object migration to transfer the basic page data
AppStorage.setOrCreate('basicDataStr', this.distributedObject['basicDataStr'] ?? '');
AppStorage.setOrCreate('basicDataNum', this.distributedObject['basicDataNum'] ?? undefined);
AppStorage.setOrCreate('distributedData', this.distributedObject['distributedData'] ?? undefined);
// ...
AppStorage.setOrCreate('curPageInfos', this.distributedObject['curPageInfos'] ?? undefined);
}
});
} catch (err) {
hilog.error(DOMAIN, TAG, FORMAT, `On status failed. Cause code: ${err.code}`);
}
let sessionId: string = want.parameters?.distributedSessionId as string;
this.distributedObject.setSessionId(sessionId).catch((err: BusinessError) => {
hilog.info(DOMAIN, TAG, FORMAT, `SetSessionId failed. Cause code: ${err.code}`);
});
try {
// Restore window stage with new LocalStorage instance
this.context.restoreWindowStage(this.storage);
} catch (err) {
hilog.error(DOMAIN, TAG, FORMAT, `RestoreWindowStage failed. Cause : ${err}`);
}
}
}
// ...
} 对于图片、文档等文件类数据,需要先将其转换为资产commonType.Asset类型,再封装到分布式数据对象中进行迁移。迁移实现方式与普通的分布式数据对象类似,下面仅针对差异部分进行说明。
async writeDistributedFile(buf: ArrayBuffer, displayName: string): Promise<void> {
let distributedDir: string = this.context.distributedFilesDir;
let fileName: string = '/' + displayName;
let filePath: string = distributedDir + fileName;
let file: fileIo.File | undefined = undefined;
try {
file = await fileIo.open(filePath, fileIo.OpenMode.READ_WRITE | fileIo.OpenMode.CREATE);
hilog.info(DOMAIN, TAG, FORMAT, 'Create file success.');
await fileIo.write(file.fd, buf);
hilog.info(DOMAIN, TAG, FORMAT, `File written successfully: ${displayName}`);
} catch (error) {
let err: BusinessError = error as BusinessError;
hilog.error(DOMAIN, TAG, FORMAT, `Failed to open / write. Code: ${err.code}`);
} finally {
if (file) {
try {
await fileIo.close(file);
} catch (err) {
hilog.error(DOMAIN, TAG, FORMAT, `Failed to close. Cause: ${err}`);
}
}
}
} async getAssetInfo(append: ImageInfo): Promise<commonType.Asset | undefined> {
let filePath = this.context.distributedFilesDir + '/' + append.imageName;
let attachment: commonType.Asset;
try {
let uri: string = fileUri.getUriFromPath(filePath);
let stat = await fileIo.stat(filePath);
attachment = {
name: append.imageName,
uri: uri,
path: filePath,
createTime: stat.ctime.toString(),
modifyTime: stat.ctime.toString(),
size: stat.size.toString()
};
hilog.info(DOMAIN, TAG, FORMAT, `[getAssetInfo] attachments name: ${attachment.name}`);
return attachment;
} catch (err) {
hilog.error(DOMAIN, TAG, FORMAT, `Stat failed. Cause code: ${err.code}`);
return undefined;
}
} let imageUri: ImageInfo | undefined = AppStorage.get<ImageInfo>('imageUri');
let asset: commonType.Assets | undefined;
if (imageUri !== undefined) {
await this.distributedFileUtil.pixelMapToBuffer(imageUri);
asset = await this.distributedFileUtil.buildAssetsFromImageInfo(imageUri);
}
// ...
let contentInfo: ContinuationData = new ContinuationData(
// ...
AppStorage.get('monoFileStr') ?? '',
AppStorage.get('monoFileNum') ?? undefined,
asset ?? undefined,
// ...
(AppStorage.get('pageInfos') as NavPathStack).getAllPathName()[0]
);
let source = await contentInfo.flatAssets();
this.distributedObject = distributedDataObject.create(this.context, source); 随后,与普通数据对象迁移的源端实现相同,可以使用该数据对象加入组网,并进行持久化保存。
若应用想要同步多个资产,可采用两种方式实现:
其中方式1的实现可以直接参照添加一个资产的方式添加更多资产。方式2的示例如下所示:
export class ContinuationData {
// ...
public multiFileStr: string | undefined;
public multiFileNum: number | undefined;
public attachments: commonType.Assets | undefined;
public curPageInfos: string | undefined;
constructor(
// ...
multiFileStr: string | undefined,
multiFileNum: number | undefined,
attachments: commonType.Assets | undefined,
curPageInfos: string | undefined
) {
// ...
this.multiFileStr = multiFileStr;
this.multiFileNum = multiFileNum;
this.attachments = attachments;
this.curPageInfos = curPageInfos;
}
async flatAssets(): Promise<object> {
let obj: object = this;
if (this.attachment !== undefined) {
obj[`attachment${0}`] = this.attachment[0];
}
if (this.attachments !== undefined) {
for (let i = 0; i < this.attachments.length; i++) {
obj[`attachments${i}`] = this.attachments[i];
}
}
return obj;
}
} let imageUriArray: Array<ImageInfo> | undefined = AppStorage.get<Array<ImageInfo>>('imageUriArray');
let assets: commonType.Assets | undefined;
if (imageUriArray !== undefined) {
for (const item of imageUriArray) {
await this.distributedFileUtil.pixelMapToBuffer(item);
}
assets =
await this.distributedFileUtil.buildAssetsFromImageArray(AppStorage.get<Array<ImageInfo>>('imageUriArray'));
}
let contentInfo: ContinuationData = new ContinuationData(
// ...
AppStorage.get('multiFileStr') ?? '',
AppStorage.get('multiFileNum') ?? undefined,
assets ?? undefined,
(AppStorage.get('pageInfos') as NavPathStack).getAllPathName()[0]
);
let source = await contentInfo.flatAssets();
this.distributedObject = distributedDataObject.create(this.context, source);