HarmonyOS 鸿蒙Next应用接续开发分享|逸校园开发实践

发布于 1周前 作者 nodeper 来自 鸿蒙OS

HarmonyOS 鸿蒙Next应用接续开发分享|逸校园开发实践

HarmonyOS NEXT新特性中,应用接续功能可以极大地提升用户在多设备间的使用体验,实现服务不中断。以下是一些关键的开发步骤和实践分享:

开发建议:参考示例代码:HarmonyOS_Samples/ContinuePublish

约束条件:

需同时满足以下条件,才能使用该功能:

  • 双端设备需要登录同一华为账号
  • 双端设备需要打开Wi-Fi和蓝牙开关。

    条件允许时,建议双端设备接入同一个局域网,可提升数据传输的速度。

  • 应用接续只能在同应用(UIAbility)之间触发,双端设备都需要有该应用。

一、开发步骤

1. 启用应用接续能力

在module.json5文件中,为需要支持接续的UIAbility配置continuable属性为true,以启用应用接续能力。

{

  “module”: {

    “abilities”: [

      {

        “name”: “com.example.harmony.MainAbility”,

        “label”: “$string:app_name”,

        “description”: “$string:mainability_description”,

        “icon”: “$media:icon”,

        “visible”: true,

        “launchType”: “standard”,

        “orientation”: “portrait”,

        “continuable”: true

      }

    ]

  }

}

2. 基础数据&文件资产迁移

对于图片、文档等文件类数据,可以将其转换为ArrayBuffer类型,并保存在分布式文件目录下。

writeDistributedFile(buf: ArrayBuffer, displayName: string): void {

  let distributedDir: string = this.context.distributedFilesDir;

  let fileName: string = ‘/’ + displayName;

  let filePath: string = distributedDir + fileName;

  try {

    let file = fs.openSync(filePath, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);

    hilog.info(0x0000, ‘[AddPic]’, ‘Create file success.’);

    fs.writeSync(file.fd, buf);

    fs.closeSync(file.fd);

  } catch (error) {

    let err: BusinessError = error as BusinessError;

    hilog.info(0x0000, ‘[AddPic]’, Failed to openSync / writeSync / closeSync. Code: ${err.code}, message: ${err.message});

  }

}

3. 创建和保存分布式数据对象

在源端UIAbility的onContinue()接口中创建分布式数据对象并保存数据。

async onContinue(wantParam: Record<string, Object | undefined>): Promise<AbilityConstant.OnContinueResult> {

  wantParam.imageUriArray = JSON.stringify(AppStorage.get<Array<PixelMap>>(‘imageUriArray’));

  try {

    let sessionId: string = distributedDataObject.genSessionId();

    wantParam.distributedSessionId = sessionId;

    let imageUriArray = AppStorage.get<Array<ImageInfo>>(‘imageUriArray’);

    let assets: commonType.Assets = [];

    if (imageUriArray) {

      for (let i = 0; i < imageUriArray.length; i++) {

        let append = imageUriArray[i];

        let attachment: commonType.Asset = this.getAssetInfo(append);

        assets.push(attachment);

      }

    }

    let contentInfo: ContentInfo = new ContentInfo(

      AppStorage.get(‘mainTitle’),

      AppStorage.get(‘textContent’),

      AppStorage.get(‘imageUriArray’),

      AppStorage.get(‘isShowLocalInfo’),

      AppStorage.get(‘isAddLocalInfo’),

      AppStorage.get(‘selectLocalInfo’),

      assets

    );

    let source = contentInfo.flatAssets();

    this.distributedObject = distributedDataObject.create(this.context, source);

    this.distributedObject.setSessionId(sessionId);

    await this.distributedObject.save(wantParam.targetDevice as string).catch((err: BusinessError) => {

      hilog.info(0x0000, ‘[EntryAbility]’, Failed to save. Code: ${err.code}, message: ${err.message});

    });

  } catch (error) {

    hilog.error(0x0000, ‘[EntryAbility]’, ‘distributedDataObject failed’, code ${(error as BusinessError).code});

  }

  return AbilityConstant.OnContinueResult.AGREE;

}

4. 基础数据&文件资产恢复

在对端设备UIAbility的onCreate()/onNewWant()中调用restoreDistributedObject()方法,通过加入与源端一致的分布式数据对象组网进行数据恢复。

onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {

  hilog.info(0x0000, ‘[EntryAbility]’, ‘Ability onCreate’);

  this.restoreDistributedObject(want, launchParam);

}

onNewWant(want: Want, launchParam: AbilityConstant.LaunchParam): void {

  hilog.info(0x0000, ‘[EntryAbility]’, ‘Ability onNewWant’);

  this.restoreDistributedObject(want, launchParam);

}

async restoreDistributedObject(want: Want, launchParam: AbilityConstant.LaunchParam): Promise<void> {

  if (launchParam.launchReason !== AbilityConstant.LaunchReason.CONTINUATION) {

    return;

  }

  let mailInfo: ContentInfo = new ContentInfo(undefined, undefined, [], undefined, undefined, undefined, undefined);

  this.distributedObject = distributedDataObject.create(this.context, mailInfo);

  this.distributedObject.on(‘status’, (sessionId: string, networkId: string, status: ‘online’ | ‘offline’ | ‘restored’) => {

    hilog.info(0x0000, ‘[EntryAbility]’, status changed, sessionId: ${sessionId});

    hilog.info(0x0000, ‘[EntryAbility]’, status changed, status: ${status});

    hilog.info(0x0000, ‘[EntryAbility]’, status changed, networkId: ${networkId});

    if (status === ‘restored’) {

      if (!this.distributedObject) {

        return;

      }

      AppStorage.setOrCreate(‘mainTitle’, this.distributedObject[‘mainTitle’]);

      AppStorage.setOrCreate(‘textContent’, this.distributedObject[‘textContent’]);

      AppStorage.setOrCreate(‘isShowLocalInfo’, this.distributedObject[‘isShowLocalInfo’]);

      AppStorage.setOrCreate(‘isAddLocalInfo’, this.distributedObject[‘isAddLocalInfo’]);

      AppStorage.setOrCreate(‘selectLocalInfo’, this.distributedObject[‘selectLocalInfo’]);

      AppStorage.setOrCreate(‘attachments’, this.distributedObject[‘attachments’]);

      let attachments = this.distributedObject[‘attachments’] as commonType.Assets;

      hilog.info(0x0000, ‘[EntryAbility]’, attachments: ${JSON.stringify(this.distributedObject['attachments'])});

      for (const attachment of attachments) {

        this.fileCopy(attachment);

      }

      AppStorage.setOrCreate<Array<ImageInfo>>(‘imageUriArray’, this.imageUriArray);

    }

  });

  let sessionId: string = want.parameters?.distributedSessionId as string;

  this.distributedObject.setSessionId(sessionId);

  this.context.restoreWindowStage(new LocalStorage());

}

5. 从分布式文件目录路径下读取文件

接续过来的图片,需要从分布式文件目录路径下读取所需的文件,经处理后,转化成需要的数据类型。

private fileCopy(attachment: commonType.Asset): void {

  let filePath: string = this.context.distributedFilesDir + ‘/’ + attachment.name;

  let savePath: string = this.context.filesDir + ‘/’ + attachment.name;

  try {

    if (fs.accessSync(filePath)) {

      let saveFile = fs.openSync(savePath, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);

      let file = fs.openSync(filePath, fs.OpenMode.READ_WRITE);

      let buf: ArrayBuffer = new ArrayBuffer(Number(attachment.size) * 1024);

      let readSize = 0;

      let readLen = fs.readSync(file.fd, buf, { offset: readSize });

      let sourceOptions: image.SourceOptions = { sourceDensity: 120 };

      let imageSourceApi: image.ImageSource = image.createImageSource(buf, sourceOptions);

      this.imageUriArray.push({

        imagePixelMap: imageSourceApi.createPixelMapSync(),

        imageName: attachment.name

      });

      while (readLen > 0) {

        readSize += readLen;

        fs.writeSync(saveFile.fd, buf);

        readLen = fs.readSync(file.fd, buf, { offset: readSize });

      }

      fs.closeSync(file);

      fs.closeSync(saveFile);

      hilog.info(0x0000, ‘[EntryAbility]’, attachment.name + ‘synchronized successfully.’);

    }

  } catch (error) {

    let err: BusinessError = error as BusinessError;

    hilog.error(0x0000, ‘[EntryAbility]’, DocumentViewPicker failed with err: ${JSON.stringify(err)});

  }

}

二、开发TIPS:

可以在需要开启接续的页面启用接续功能,离开该页面即关闭

onPageShow() {
// 进入该页面时,将应用设置为可迁移状态
this.context.setMissionContinueState(AbilityConstant.ContinueState.ACTIVE, (result) => {
console.info('setMissionContinueState ACTIVE result: ', JSON.stringify(result));
});

this.isBasicMode = true;
}

onPageHide(): void {
this.context.setMissionContinueState(AbilityConstant.ContinueState.INACTIVE, (result) => {
console.info('setMissionContinueState ACTIVE result: ', JSON.stringify(result));
});
}

接续功能可以开启应用版本检测,避免升级带来的接续不兼容闪退等问题:

onContinue(wantParam: Record<string, Object>) {
let versionDst = wantParam.version; // 获取迁移对端应用的版本号
let versionSrc: number = bundleManager.getBundleInfoForSelfSync(bundleManager.BundleFlag.GET_BUNDLE_INFO_DEFAULT).versionCode; // 获取迁移源端即本端应用的版本号
if (versionDst > versionSrc) { // 兼容性校验
// 兼容性校验不满足
return AbilityConstant.OnContinueResult.MISMATCH;
}
console.info(onContinue version = ${wantParam.version}, targetDevice: ${wantParam.targetDevice})
// 迁移数据保存
let continueInput = AppStorage.get<string>(“ContinueProperty”);
if (continueInput) {
// 将要迁移的数据保存在wantParam的自定义字段(如:data)中;
wantParam[“data”] = continueInput;
}

三、效果:

cke_3168.gifcke_10188.gif


更多关于HarmonyOS 鸿蒙Next应用接续开发分享|逸校园开发实践的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html

1 回复

更多关于HarmonyOS 鸿蒙Next应用接续开发分享|逸校园开发实践的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


在HarmonyOS鸿蒙Next应用接续开发中,针对逸校园的开发实践,核心在于充分利用鸿蒙系统的分布式特性和系统能力。

首先,鸿蒙系统支持多设备协同工作,这意味着开发者可以在逸校园应用中实现跨设备的无缝接续。例如,学生在手机上查看课程信息后,可以无缝切换到平板或电脑上继续深入学习,而无需重新加载或登录。

其次,鸿蒙系统提供了丰富的系统能力接口,如位置服务、通知服务、多模输入等,这些都可以被集成到逸校园应用中,以提升用户体验。例如,通过位置服务,应用可以自动推荐附近的图书馆或自习室;通过通知服务,可以及时提醒学生上课或考试等重要事件。

在开发实践中,需要重点关注鸿蒙系统的应用框架、分布式数据库、分布式文件系统等技术点,这些是实现跨设备接续和数据同步的关键。

此外,鸿蒙系统还支持丰富的UI组件和动画效果,开发者可以利用这些组件和效果,打造更加美观和流畅的用户界面。

总之,在HarmonyOS鸿蒙Next应用接续开发中,通过充分利用鸿蒙系统的分布式特性和系统能力,可以为逸校园应用带来更加出色的跨设备接续体验和更丰富的功能。

如果问题依旧没法解决请联系官网客服,官网地址是:https://www.itying.com/category-93-b0.html

回到顶部