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