写点什么

我把分布式音乐播放器适配了 Stage 模型

  • 2022-11-07
    上海
  • 本文字数:3752 字

    阅读完需:约 12 分钟

我把分布式音乐播放器适配了Stage模型

OpenAtom OpenHarmony(以下简称“OpenHarmony”)应用开发自 API 8 及其更早版本一直使用的是 FA 模型进行开发。FA 模型是 Feature Ability 的缩写,它和 PA(Particle Ability)两种类型是过往长期推广的术语,深入人心。


然而从 API 9 开始,Ability 框架引入了 Stage 模型作为第二种应用框架形态,Stage 模型将 Ability 分为 PageAbility 和 ExtensionAbility 两大类,其中 ExtensionAbility 又被扩展为 ServiceExtensionAbility、FormExtensionAbility、DataShareExtensionAbility 等一系列 ExtensionAbility,以便满足更多的使用场景。新模型接口中有 AbilityStage/WindowStage 的概念,这个 Stage 本身有舞台的意思,寓意是给开发者一个新的展现舞台。Stage 模型的设计,主要是为了开发者更加方便地开发出分布式环境下的复杂应用。下表给出了两种模型在设计上的差异:



可以看得出来,新的模型设计的主要目标是把 UI 与 Ability 分离,即从架构设计层面,规范开发者编写业务逻辑和 UI 交互的开发方式。通过数据把 UI 和业务逻辑解耦,开发者在 Ability 中产生数据,数据传递给 UI 框架后,利用 ArkTS 声明式框架的特点,UI=F(state),通过数据驱动 UI 变化。这样的设计是为了更好地支持 Ability 实现跨端迁移和多端协同,即数据都是存储在 Ability 里,继而通过数据驱动 UI 展示。此外,FA 模型每个 Ability 使用一个 VM 实例,而 Stage 模型整个进程只使用一个 VM 实例,减少进程内存占用,应用内状态在进程内共享。


分布式音乐播放器,是今年上半年我基于 OpenHarmony 3.1,参考 OpenHarmony JS 分布式音乐播放的 Sample 代码,使用 ArkTS 新写的样例,当时的主要目的就是为了学习 ArkTS 开发页面。此次适配 Stage 模型后,在润和大禹系列 HH-SCDAYU200 开发套件上,效果如下图所示:



可以看到,此次更新,不仅使用了 Stage 模型适配,还使用 ArkTS 增加了一个音乐播放器首页列表的界面,以及播放时使用属性动画,实现了一个播放音乐时“唱片旋转”的动画效果。这次使用 Stage 模型适配样例,主要是修改了如下几个地方:


修改点 1:代码目录的调整



可以看到,相对于 FA 的目录结构,首先是在最上层目录里,增加了一个 AppScope 目录,这个目录下也是 resources 下的资源文件,比如 string.json,图片等内容。这个目录里的资源文件,会在编译时拼接到具体的 hap 内编译,因此可以把不同 hap 包里的公用资源提取到这个目录下。


此外是增加了 AbilityStage.ts 这个文件,它是 Hap 及加载入口,开发者可以基于它派生完成 hap 的初始化以及指定多个实例开发。AbilityStage 可以配合 ApplicationContext 监听/管理进程内组件的生命周期,感觉是有点充当了 FA 模型里的 app.ets 的作用。


其它的文件也有小的变化,如配置文件,pages 位置等都有调整。所以建议还是新建一个 stage 模型的工程,然后把之前的代码逐步复制过来,然后修改问题。


修改点 2:获取设备列表,分布式拉起等 API 变化


由于两种模型的应用上下文不同,导致一些跟上下文相关的 API 大都有些变化,在 SDK 及文档中有明确标明哪些 API 是 stage 模型专用的。比如耳熟能详的 startAbility 分布式拉起应用,在 FA 模型中是通过以下代码实现:


import featureAbility from '@ohos.ability.featureAbility';
featureAbility.startAbility({ want: wantValue }).then((data) => { CommonLog.info('startAbilityContinuation finished, ' + JSON.stringify(data))
//拉起后,自我关闭 featureAbility.terminateSelf((error) => { CommonLog.info('startAbilityContinuation terminateSelf finished, error=' + JSON.stringify(error)) }) }).catch((error) => { CommonLog.info('startAbilityContinuation error ' + JSON.stringify(error)) })

复制代码


而在 stage 模型里,由于不再有 featureAbility,因此无法 import featureAbility,进而无法使用 featureAbility.startAbility 拉起应用,进而使用 getContext 获取上下文后,调用 startAbility 拉起应用。


    getContext(this).startAbility(want).then((data) => {      CommonLog.info('startAbilityContinuation finished, ' + JSON.stringify(data))
//自我关闭 getContext(this).terminateSelf((error) => { CommonLog.info('startAbilityContinuation terminateSelf finished, error=' + JSON.stringify(error)) }) }).catch((error) => { CommonLog.info('startAbilityContinuation error ' + JSON.stringify(error)) })
复制代码


除了 startAbility 外,样例里使用到的获取包含 bundleName,设备发现 deviceManager 的相关 API 都需要按照上述方法进行修改。


修改点 3:数据从组件分离,提取到 Ability 中在


分布式拉起时,需要传递当前播放的音乐和音乐的播放进度。在两种模型里,这些参数都是被设置在 wantValue 的 parameters 里,通过 startAbility 传出去。


  let params = {      index: this.playerManager.getCurrentMusicIndex(),      seekTo: this.playerManager.getCurrentTimeMs(),      isPlaying: this.isPlaying    }    let wantValue = {      bundleName: this.bundleName,      abilityName: 'com.madixin.music.MainAbility',      deviceId: remoteDevice.deviceId,      parameters: params    }
复制代码


但在接收参数时,FA 模型里,是在当前组件的代码里,通过 featureAbility.getWant 来获取参数,如下代码。

  featureAbility.getWant((error, want) => {      CommonLog.info('restoreFromWant featureAbility.getWant=' + JSON.stringify(want))      let status = want.parameters      if (status != null && status.index != null) {        this.playerManager.playSpecifyMusic(status.seekTo, status.index)        this.isPlaying = true        this.playAnimation()      }    })
复制代码


而使用 Stage 模型后,虽然参数传递的方式是一致的,但是无法直接在组件 UI 中获取参数,而需要先在 MainAbility.ts 获取参数 want。此时如果要传递给组件,有多种方式,这里我是使用的如下方式,即在 MainAbility.ts 的 onCreate 和 onNewWant 里,把 want 赋值到 globalThis 里,然后在 UI 组件里,通过 globalThis 获取参数。


 // MainAbility.ts    onNewWant(want, launchParams) {        globalThis.newWant = want        hilog.info(0x0000, 'MyOpenHarmonyPlayer', '%{public}s', 'onNewWant launchParam:' + JSON.stringify(launchParams) ?? '');    }
onCreate(want, launchParam) { globalThis.newWant = want hilog.info(0x0000, 'MyOpenHarmonyPlayer', '%{public}s', 'want param:' + JSON.stringify(want) ?? ''); hilog.info(0x0000, 'MyOpenHarmonyPlayer', '%{public}s', 'launchParam:' + JSON.stringify(launchParam) ?? ''); } // index.ets let newWant = globalThis.newWant CommonLog.info("aboutToAppear newWant:" + JSON.stringify(newWant)) if (newWant !== null && newWant.parameters.hasOwnProperty("seekTo")) { this.playerManager.playSpecifyMusic(newWant.parameters.seekTo, newWant.parameters.index) }
复制代码


另外,了解到还有一种方式传递数据是使用 AppStorage 来关联,比如在 MainAbility.ts 里使用 AppStorage.SetOrCreate<string>传入数据,在 UI 组件里,使用 @StorageLink 标签修饰变量来获取数据。


除以上三点修改外,还有两点值得说明下


首先是因 OpenHarmony 3.2 后分布式能力限制智能系统应用使用,需要提升 apl 等级:找到所使用 API 版本对应 toolchains>版本号>lib>UnsgnedReleasedProfileTemplate.json,更改 "apl": "normal"为 "apl": "system_core"。


其次是 API 9 以后区分了 public-SDK 和 Full SDK。DevEco Studio 默认下载的是 public-SDK,它不包含系统应用所需要的高权限 API。当我们 import deviceManager from '@ohos.distributedHardware.deviceManager'时,会发现里面只有一个空的接口,没有任何方法。虽然这不影响功能,但代码中必须使用 @ts-ignore 忽略 typescript 的告警,而且没有语法提示。此时,需要使用 full-SDK 替换。


相关文档请参考https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/full-sdk-switch-guide.md


新增首页页面,和播放列表页的动画,不是本文的重点,大家可以参考代码自行学习。


总结

OpenHarmony 的 FA 模型能力已经停止演进,后续将会增强 Stage 模型。此次将现有的样例代码适配 Stage 模型,虽然整体代码修改量不大,但因为惯性思维以及 API 的变化,期间还是踩了不少坑。我已在 OpenHarmony 知识体系仓中更新了样例代码,欢迎开发者来参考和指正问题,建议新上手 OpenHarmony 的开发者可以直接学习使用新的 Stage 模型来开发应用。前面提到在 Stage 模型里,ExtensionAbility 又被扩展为 ServiceExtensionAbility、FormExtensionAbility、DataShareExtensionAbility 等一系列 ExtensionAbility,这个样例目前还没有涉及到,待后续进一步学习,通过 ExtensionAbility 把音乐播放实现成一个后台服务,从而实现应用在后台时也能继续播放音乐,届时将持续更新这个应用,也欢迎大家一起共建。


分布式音乐播放器样例地址https://growing.openharmony.cn/mainPlay/detail?sampleId=3742

用户头像

OpenHarmony开发者官方账号 2021-12-15 加入

OpenHarmony是由开放原子开源基金会(OpenAtom Foundation)孵化及运营的开源项目,目标是面向全场景、全连接、全智能时代,基于开源的方式,搭建一个智能终端设备操作系统的框架和平台,促进万物互联产业的繁荣发展

评论

发布
暂无评论
我把分布式音乐播放器适配了Stage模型_OpenHarmony_OpenHarmony开发者社区_InfoQ写作社区