今天第一天正式开始学习鸿蒙应用开发。
本来想着,作为一个拥有 10 来年工作经验的资深开发,对 React/Vue,React Native,Android 开发都有丰富的实践经验,对 Swift UI 也有所涉猎,在大前端这一块可以说是信心满满,学习 ArkUI 应该信手拈来才对,谁知道学习的第一天,我就发现我太天真了。
HarmonyOS 与 ArkUI 给我了沉痛一击
学习第一天一点都不顺利,上午还算有所收获,下午直接毫无建树,踩在一个坑里出不来,人直接裂开,差点以为自己要创业未半而中道崩殂了。不过好在晚饭后,侥幸解决了下午遇到的坑
最终今天学习的成果如下
scroll.gif
导航栏的4个图标都是用了 lottie 的动画,因为使用了 gif 录制,可能有点感觉不太明显,真机上的感受非常舒适,用户体验极佳
今天已经学习过的内容包括
- 基础项目结构
- 基础布局组件
- 容器布局组件
- 滚动组件
- 导航组件
- ohpm 安装
- 引入 lottie 动画
- 属性动画
- 配置 hot reload
- 组件状态管理 @state @props @link
- 组件逻辑表达式
- 沉浸式状态栏
- 真机调试
我的开发设备具体情况如下
MacOS M1 HarmonyOS API 9 华为 P40 pro+,已安装 HarmonyOS 4
作为一个把主要精力放在前端的开发者,做个记录分享一下学习体会
01组件概念
在前端开发中,不管你是用 React 还是使用 Vue,我们只需要掌握一个概念:组件。复杂的组件是由小的组件组成,页面是由组件组成,项目是由组件组成,超大项目也是由组件组成。组件可以组成一切。因此 React/Vue 的学习会相对更简单一些
和 Android 一样,由于 HarmonyOS 有更复杂的应用场景、多端、分屏等,因此在这一块的概念也更多一些,目前我接触到的几个概念包括
Window 一个项目好像可以有多个窗口,由于接触的时间太短了暂时不是很确定,可以创建子窗口,可以管理窗口的相关属性,创建,销毁等
Ability 用户与应用交互的入口点,一个 app 可以有一个或者对个 Ability
page 页面,一个应用可以由多个 page 组成
Component 组件,可以组合成页面
由于目前接触的内容不够全面,因此对这几个概念的理解还不够笃定,只是根据自己以往的开发经验推测大概可能是什么情况,因此介绍得比较简单,但是可以肯定的是理解这些概念是必备的
02基础布局
虽然 HarmonyOS 目前也支持 web 那一套逻辑开发,不过官方文档已经明确表示未来将会主推 arkUI,因此我个人觉得还是应该把主要学习重心放在 arkUI 上来
arkUI 的布局思路跟 html + css 有很大不同。
html + css 采用的是结构样式分离的方式,再通过 class/id 关联起来。因此,html + css 的布局写起来会简单很多,我们只需要先写结构,然后慢慢补充样式即可
arkUI 并未采用分离思路,而是把样式和结构紧密结合在一起,这样做的好处就是性能更强了,因为底层渲染引擎不用专门写一套逻辑去匹配结构和样式然后重新计算 render-tree,坏处就是...
代码看着有点糟心
比如下面这行代码,表示两段文字
Column() { Text('一行文字') .textAlign(TextAlign.Center) .fontSize(30) .width('100%') .backgroundColor('#aabbcc') Text('二行文字') .textAlign(TextAlign.Center) .fontSize(30) .width('100%') .backgroundColor('#aabbcc') }.width('100%') .height('100%') .backgroundColor('red')
如果用 html 来表示的话....
<div> <p>一行文字</p> <p>一行文字</p> </div>
当然我期望能找到一种方式去支持属性的继承和复用。目前简单找了一下没找到,希望有吧 ~
由于 html 中 div 足以应付一切,因此许多前端开发者会在思考过程中忽视或者弱化容器组件的存在,反而 arkUI 的学习偏偏要从容器组件开始理解
我觉得这种思路会对解耦思路有更明确的训练。许多前端开发在布局时不去思考解耦问题,我认为这是一个坏处。
arkUI 的布局思路是:先考虑容器,再考虑子元素,并且要把样式特性结合起来一起思考。而不是只先思考结构,再考虑样式应该怎么写。
例如,上面的 GIF 图中, nav 导航区域是由 4 按钮组成。先考虑容器得是一个横向的布局
然后每一个按钮,包括一个图标和一个文字,他们是纵向的布局,于是结构就应该这样写
Row: 横向布局 Column: 竖向布局 Row() { Column() { Lottie() Text() } Column() { Lottie() Text() } Column() { Lottie() Text() } Column() { Lottie() Text() } }
按照这个思路去学习,几个容器组件 Row/Column/FLex/Stack/GridContainer/SideBarContainer ... 很快就能掌握
03引入 lottie
在引入 lottie 的时候遇到了几个坑。
一个是有一篇最容易找到的文章介绍如何在 arkUI 中引入 lottie,结果这篇文章是错误的。 ~ ~,这篇文章是在官方博客里首发,让我走了不少弯路。
image.png
这里面有两个坑,一个坑是 @ohos/lottie-ohos-ets 的好像库不见了。另外一个坑就是文章里指引我用 npm 下载这个库。但是当我用 npm 下载之后,文件会跑到项目中的 node_modules 目录下,不过如何在 arkUI 的项目中引入 node_modules 中的库,我还没找到方法,应该是要在哪里配置一下
最后在 gitee 的三方仓库里,找到了如下三方库
import lottie from '@ohos/lottie';
这里遇到的一个坑就是我的电脑上的环境变量不知道咋回事被改了,导致 ohpm 没了,找了半天才找到原因,又重新安装 ohpm,然后把环境变量改回来
- 到官方文档下载对应的工具包
- 把工具包放到你想要放的安装目录,然后解压,进去 ohpm/bin 目录,在该目录下执行 init 脚本开始安装
> init
- 然后使用如下指令查看当前文件路径
> pwd
然后执行如下指令
// OHPM_HOME 指的是你自己的安装路径 > export OHPM_HOME=/home/xx/Downloads/ohpm > export PATH=${OHPM_HOME}/bin:${PATH}
- 执行如下指令检查是否安装成功
> ohpm -v
@ohos/lottie
使用如下指令下载 lottie
ohpm install @ohos/lottie
然后在 page 中引入
import lottie from '@ohos/lottie'
在类中通过定义私有变量的方式构建上下文
private mrs: RenderingContextSettings = new RenderingContextSettings(true) private ctx: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.mrs)
并且用私有变量保存 lottie 数据路径或者内容
private path: string = 'common/lottie/home.json'
然后在 build 中,结合 Canvas 组件绘制
Canvas(this.ctx).onReady(() => { lottie.loadAnimation({ container: this.ctx, renderer: 'canvas', loop: false, autoplay: true, path: this.path }) })
参考文章:@ohos/lottie
04hot reload
使用 commond + , 调出配置页面,然后通过如下路径找到配置选中 Perform hot reload
Tools -> Actions on Save -> Perform hot reload
image.png
然后在项目运行的入口处,选择 entry -> edit configrations,弹出如下界面,选中 Hot Reload 的 entry,做好与下图中一致的勾选,点击 apply 按钮之后启动项目即可实现 hot reload
image.png
不过呢,hot reload 在调试样式的时候还能勉强用一用,涉及到代码逻辑的更改,往往没什么用,属实是食之无味,弃之可惜
除此之外,也许 Previewer 更适合开发时使用
image.png
05沉浸式状态栏
沉浸式状态栏是一款体验良好的 app 必备能力。因此我学会了基础知识之后,第一时间就想要研究一下再 HarmonyOS 中如何达到这个目的。
沉浸式状态栏指的就是下图中位置能够做到与页面标题栏,或者页面背景一致的样式。或者简单来说,可以由我们开发者来控制这一块样式。布局进入全屏模式。
image.png
在我们创建入口 Ability 时,可以在生命周期 onWindowStageCreate 中设置全屏模式
onWindowStageCreate(windowStage: window.WindowStage) { windowStage.getMainWindow(err, mainWindow: window.Window) { if (err.code) { return } mainWindow.setWindowLayoutFullScreen(true) } }
setWindowLayoutFullScreen 是一个异步函数,因此如果你想要修改状态栏样式的话,可以在它的回调里,通过 setWindowSystemBarProperties 去设置
mainWindow.setWindowLayoutFullScreen(true, (err) => { if (err) { return } mainWindow.setWindowSystemBarProperties({ statusBarColor: '#FFF' }) })
具体的参数配置,可以在代码中,查看类型声明获悉。
这里有一个巨大的坑,就是在我的开发环境启动的模拟器中 API 9,当你设置了全屏模式之后,布局会发生混乱。真机调试又是正常的。
我刚开始以为是我的代码哪里没搞对,为了解决这个问题花了一个多小时的时间,结果最后才确定是模拟器的布局 bug...
真机调试
真机调试的设置方式主要跟其他 app 开发都一样,把手机设置为开发者模式即可。不过你需要通过如下方式,配置好一个应用签名才可以。因此你首先需要注册成为华为开发者
File -> Project Structure -> Signing Configs -> Sign in
跟着指引在后台创建项目,然后再回到开发者工具这个页面自动生成签名即可
image.png
真机调试有一个巨大无比的坑,那就是 API 9 创建的项目,在老版本的麒麟芯片上巨卡无比。连基本的点击都无法响应。
这就要了命了。如果连真机调试都做不到,那还拥抱个啥啊?
研究了很久,找到了几个解决这个问题的方法
1、换新机,只要你的手机不是华为被制裁之前的麒麟芯片,都不会存在这个问题
2、创建项目时,选择 API 8
3、在开发者选项的配置中,选择 显示面(surface)更新,虽然不卡了,不过闪瞎了我的狗眼
4、等明年 HarmonyOS next 出来之后再来学,官方说,API 10 将会解决这个问题
上面的解决办法或多或少都有一些坑点。我选择了一种方式可以很好的解决这个问题
那就是:投屏
如果你有一台华为电脑,这个投屏会非常简单。不过由于我是 mac M1,因此我选择的投屏方案是 scrcpy
使用 brew 安装
> brew install scrcpy
然后继续安装
> brew install android-platform-tools
启动
> scrcpy
启动之前确保只有一台手机已经通过 USB 连接到电脑,并允许电脑调试手机就可以成功投屏。在投屏中操作手机,就变得非常流畅了
不过目前我通过这种方式投屏之后,运行起来的项目经常闪退,具体是什么原因我还没找到,只能先忍了
总之就是坑是一个接一个 ~ ~
06总结
一整天的学习,整体感受下就如标题说的那样:拥抱华为,困难重重。 还好我电脑性能强悍,要是内存少一点,又是虚拟机,又是投屏的,搞不好内存都不够用,可以预想,其他开发者还会遇到比我更多的坑 ~
image.png
个人感觉华为相关的官方文档写得不是很友好,比较混乱,找资料很困难。反而在官方上把一堆莫名其妙的教学视频放在了最重要的位置,我不是很明白,到底是官方文档,还是视频教程网站 ~ ~
官方文档里还涉及了 FA mode 到 Stage mode 的更新,因此通过搜索引擎经常找到 FA mode 的相关内容,可是 FA mode 又是被弃用的,因为这个问题也给我的学习带来了不少的麻烦。由于遇到的坑太多了,以致于我到现在尝试点什么新东西都紧张兮兮的,生怕又是坑
总的来说,自学困难重重,扛得住坑的,才能成为最后的赢家,红利不是那么好吃的