当Vibe Coding遇上鸿蒙穿戴应用开发
TLDR(省流版)
鸿蒙穿戴应用(即华为智能手表/手环)应用开发的技术栈太小众了,再加上华为这块的开发文档过于混乱和黑箱(一点都不 open),所以 Vibe 不了一点,全是坑,只能各种手动调试代码来保证功能的可行性。
当然,即便如此,通过把鸿蒙穿戴应用开发的技术栈文档作为项目级别的知识库,Cursor 也能相对准确的辅助代码补全,提高这门小众技术栈开发的效率。
Vibe Coding 是什么?
Vibe Coding 这个概念最近很火,我个人对此有一个简单粗暴的理解——别管技术栈和编程语言是什么,我们就是甲方,而 AI IDE/Agent 就是乙方,就当做自己不懂代码就好了,我们只管输出想法和进行产品验收,而 AI 负责去进行代码的开发。
社区里也有人总结出 Vibe Coding 相关的原则,比如:
需求背景
最近忙着给自己规划各种事项的 SOP,想要随时查看 SOP 方便去执行和迭代;而目前对我本人来说,智能手表才是最贴身的,也是最方便随时查看简单信息的载体。
而我用的手表是华为的 watch fit3,有应用市场,所以我觉得官方应该提供了开发应用的 SDK 吧,正好最近 vibe coding 很火,因此想试试能不能用 Cursor 搭配 vibe coding速通鸿蒙系统的穿戴应用开发,毕竟 vibe coding 的最大优势就是无视技术栈的壁垒(然而我高估了鸿蒙开发生态的完整性😂)。
其实前不久为了同步 obsidian 笔记中的日程到手环中,想尝试开发一个手环应用来着,可惜鸿蒙穿戴应用从底层设计上没有提供网络请求能力(因为我这款手表没有独立连接网络和独立 sim 卡的功能),所以如果要实现从网络上同步日程就得在手机端开发一个 App 提供数据传送的功能,这个代码量就稍微有点大了,因此就放弃了这个方案。
其实拆分需求特别简单:
- SOP 列表:显示有哪些事项的 SOP
- SOP 详情:点击事项查看 SOP 内容
如果这些需求放在网页端的技术栈,我相信是真的可以用 Cursor + vibe coding 用不了几分钟就能给实现;可惜的是鸿蒙穿戴应用的运行时环境和开发技术栈跟网页开发有挺大差异。
华为 Lite Wearable 应用开发的现状
Lite Wearable 和 Wearable
华为目前把旗下的智能穿戴设备分为了两种:
- 智能穿戴(Wearable)
- 轻量级智能穿戴(Lite Wearable)
从名字不难看出,Lite Wearable 应用的功能与 Wearable 相比肯定有所阉割(后面才深刻地体会到其实是超大的阉割😅),不幸的是我用的是 watch fit3 就是 Lite Wearable 设备。根据穿戴设备类型的不同,所用的开发语言就不同:
- 智能穿戴(Wearable):可以使用 JS 和 JAVA 两种语言进行开发
- 轻量级智能穿戴(Lite Wearable):只能用 JS 语言进行开发
JS 开发框架——超迷你版 MVVM 框架
如果各位开发过微信小程序,就会对华为设计的这套 JS 开发框架很熟了,一套极其初始版本的 MVVM 框架,毫无开发体验,写起来很累:
- HML:跟 WXML 类似,就是 View 模块;可以使用内置的一些组件(千万不要下意识的当成 html 元素来用,尽管里面有跟 html 标签同名的,但实际上完全不同!),有简单的数据绑定、事件绑定和自定义组件功能,也提供 for、if、ref 和 show 等指令;详情参考——HML语法参考
- CSS:究极阉割版的 CSS 样式,只能用 flex 布局和一些特别核心的样式属性、尺寸属性等;官方文档还说支持 scss 和 less 呢,详情参考——CSS语法参考
- JS:提供页面层级和应用层级的一些生命周期以及状态管理等功能;详情参考——JS语法参考
- ohpm:仿照 pnpm 设计的用于 Open Harmony 的模块管理工具,一些跟系统能力相关的模块也通过它进行使用,我觉得目前应该没人给穿戴应用环境适配 ohpm 包吧……
噢,值得一提的是,它居然提供了简单的 Canvas API[1],难以置信🙃:
JS 开发框架能力亦有不同
不得不说,华为为开发者准备的文档真是有种完全不管你死活的美;作为一个鸿蒙生态开发的新手,我想要开发穿戴应用,最先找到的文档就是这个 [2]:
结果点进去发现是一点入门的信息都没有,好像默认你就会使用它们的语法一样;只有一些关于集成 Wear Engine SDK 的功能示例,而这个 SDK 就是用于跟手机端 APP 进行各种通信相关的功能。我也不知道找了多久,终于找到 JS 开发框架相关的文档 [3]:
我当时还很高兴呢,觉得终于找到 JS 框架相关的文档,这下就可以把这些文档导入到项目知识库然后等着 Cursor 发力就行了,后面我才发现我太 naive 了;因为我发现这里面说的很多组件以及组件属性在使用后都没法正常编译,后面我终于知道了原来 JS 框架的还分为 Full 和 Lite 两种 [4],而且文档上也完全不说 Full 和 Lite 适用的范围,虽然不难猜到 Lite 适用于 Lite Wearable 设备,但是文档的作用不就是让开发过程变得清晰吗,结果全要靠开发者去猜……
尽管一步步了解到 Lite Wearable 应用能力的边界在不断缩小这一点令我对该应用的产出预期越来越低,但更令人不爽的是华为这糟糕的文档管理方式,完全分散在各个角落,明明可以顺手在一开始的地方对这些文档做一下引用和适用范围说明。
系统能力很不 Open
目前对于 SDK 在 4.0.0(10) 及以上的穿戴应用开发,完全不知道如何调用系统能力,因为内置的 @system
模块所提供的大多数模块和方法都已经弃用了:
没错,上面模块中的方法就没几个能用;而看起来用来替代 @system
模块的 @ohos
模块也没几个方法可以使用:
除此之外,无论是 @system
模块还是 @ohos
模块的 router 方法都没法正常使用,这就导致路由跳转相关的功能形同虚设😅。
不仅如此,从 watch fit3 来看,这个手环侧面有两个按钮——上面是旋钮,下面是长按钮;这两个按钮都应该有交互事件可以来监听才对,尤其是旋钮包含旋转交互,这些能力在系统应用和一些第三方应用中都有调用;从系统应用和第三方应用不难发现应该有一些更丰富的系统组件可以使用,不然很难想象用这么简陋的系统能力和组件怎么写出一些很优雅的渲染和交互的。所以要么就是文档没来得及写,要么就是这些系统能力只对华为内部和合作伙伴开放,不对外开放,无论怎样都是💩。
除了坑还是坑
很难想象现在在鸿蒙系统开发应用的开发者有多痛苦🤣,仅从穿戴应用开发来看,除了上面提到的开发文档特别混乱和系统能力不透明不开放以外,我从【华为开发者联盟】社区里面各种开发者求助的帖子就不能看出,华为官方就没有投入足够的人员和尊重来回应社区里各种问题和关切,经常就是很久没人回答或者就一个客服回应就没了下文:
类似的帖子我看过太多了,甚至有的帖子过了几年还有人反馈有同样的问题😅。因此,目前开发鸿蒙穿戴应用除了坑还是坑……不知道 Apple Watch 的应用开发有这么痛苦吗😀。
踩坑实录
说多了都是泪,感觉我不是在写代码,而是在反编译一个黑箱产物。
开发信息
- 穿戴设备:Watch Fit3 + HarmonyOS 5.0.0
- DevEco Studio:5.0.3 Beta2(Mac + intel)
- SDK:4.0.0(10)
组件内容尺寸自适应
不好意思,目前提供的系统组件不存在高度自适应(即 height 为 auto),需要手动设置一个固定高度或相对高度,不然默认高度就是 0,所以当你看到某个元素没有显示时大概率就是没有设置 height 样式。
同样的,宽度也一样。所以当你明白这一点的时候你就知道,写 Lite Wearable 应用有多痛苦了,几乎要全部手动设置宽高,相当于没有布局引擎,就跟你在不使用第三方工具库的情况下基于 Canvas 渲染图形一样,图形的位置和大小全都要自己计算。
当然,有一个组件是例外的,那就是 text 组件,毕竟如果文本的宽高还要自行计算的话,那这个渲染框架简直设计了个寂寞,干脆让开发者自行写一套渲染引擎得了😅。不过实际上使用 text 组件时需要手动设置一个宽度,不然文本过长时它会直接超出容器而不会自动换行(这也太 auto 了……):
滚动容器
令人不敢相信的是,内置的容器组件大多都没有提供滚动的功能,即不能像 HTML 那样设置 overflow 属性;但是经过尝试(是的,官方文档没有明确写出来哪个容器内可以进行上下滚动),list 组件内部的 list-item 高度超出容器高度时就可以触摸进行上下滑动:
然而由于前面提到的,组件内容并不会高度自适应,所以要让 list-item 组件内的内容完整显示,你要么自行写一个布局引擎根据样式来计算渲染高度(我试过让 Cursor 写一个文本渲染高度计算,但布局引擎的各种边界条件很多,要想完全实现精准计算代码的复杂度就很高了),要么跟我一样写一个很大的高度值😅。
奇怪的是,watch fit3 里面的系统应用和一些第三方应用有着很明显的带滚动条的视图(是的,list 虽然可以当滚动容器,但不会出现滚动条的 UI 提示):
而且这种带滚动条的视图,还可以基于 watch fit3 右侧的旋钮转动来完成上下滚动的交互,这怎么看都是一种标准的组件和系统交互,可惜完全看不到相关的文档。
HAP 包
HAP(Harmony Ability Package)是应用安装和运行的基本单元。HAP 包是由代码、资源、第三方库、配置文件等打包生成的模块包,其主要分为两种类型:entry 和 feature。
- entry:应用的主模块,作为应用的入口,提供了应用的基础功能。
- feature:应用的动态特性模块,作为应用能力的扩展,可以根据用户的需求和设备类型进行选择性安装。
应用程序包可以只包含一个基础的 entry 包,也可以包含一个基础的 entry 包和多个功能性的 feature 包。[5]
简言之,HAP 包就是项目编译后打包得到的一种压缩包。
签名
相比普通的前端项目开发,Lite Wearable 应用最大的不同就是打包时需要进行签名,如果没有签名那么就无法到真机上进行调试;虽然 DevEco Studio 提供了自动签名的功能,但不幸的是目前 Lite Wearable 应用只能使用手动签名,而手动签名的步骤有亿点点繁琐:
- 在 DevEco Studio 生成项目的密钥和证书文件,会得到
.p12
和.csr
这两个文件;详细步骤可以参考官方文档——生成密钥和证书请求文件 - 然后需要在华为的 AppGallery Connect 申请 APP ID、调试证书、注册调试证书和调试 Profile,会得到
.cer
和.p7b
这两个文件;详细步骤可以参考官方文档——调试HarmonyOS应用/元服务 - 最后在 DevEco Studio 配置项目的签名信息;详细步骤可以参考官方文档——手动配置签名信息
配置签名的步骤特别多,需要严格按照官方文档进行设置,因为只要错了其中的一个步骤就会导致签名失败或者签名不正确,然后安装失败😅。其中特别需要注意的是,在申请 APP ID 时,要确保应用包名与项目配置中的包名是一致的:
真机安装调试
在华为应用市场安装【应用调测助手】这个 APP(不确定其它手机应用市场有没有这个):
该 APP 就是用来在华为穿戴设备上安装 HAP 包的,还可以查看穿戴设备的 debug 日志:
顺便一提,这里的 UDID 在签名时注册调试设备时需要用到。其中的应用管理就是可以从当前手机的 haps 目录中读取可安装的 HAP 包:
那么如何获取到 HAP 包呢?在 DevEco Studio 菜单栏下面找到 Product 图标,Build Mode 选择 debug 模式,然后 apply:
如果发现 apply 按钮置灰,可以把 Build Mode 改成其它模式编译一遍,然后再切回 debug 模式就能 apply 了(我也不知道这是 bug 还是 feature……)。最后就能在 build 目录中找到编译好的 HAP 包:
其中名字带 signed 的就是签名了的 HAP 包,我们要安装到真机的就是这个包。把这个包复制到手机的 haps 目录后,就可以到【应用调测助手】中的应用管理安装上述的 HAP 包了:
HAP 包常见安装报错
然而实际上 HAP 包的安装不是一帆风顺的,总会遇到各种报错导致无法安装,以下就是我遇到的一些安装报错:
解压<包名.hap>失败
这个错误我也不记得我是怎么解决的了🤣,因为在网上找相关的错误只有一篇文章提及,而且只说了有这个错误,但没人给出解决方案 [6]。我应该是重新编译之后就没有这个报错,猜测应该是 build mode 选错了。
40.配置文件格式错误
出现这个报错时,一种可能就是字面意思,config.json
中的某些字段设置错了 [7];而我碰到的则是另一种——SDK 版本不兼容,讲真的,我不知道鸿蒙里面的 SDK 版本和系统版本之间的关系是啥,因为只看 SDK 版本号你会直觉地认为这就是跟系统版本一一对应的:
而我的手环系统版本就是 5.0.0,所以我一开始选择的 SDK 就是 5.0.0(12);后面也是发现一篇文章提到他是通过降低 SDK 版本 [8] 解决了这个 40 报错,我就把 SDK 版本降到了 4.0.0(12),果然就解决了这个报错😀:
10.内部错误
这个错误大概率就是因为签名配置不正确导致的,比如:
应用图标配置
关于穿戴应用图标的尺寸和相关配置的规范,我完全没有找到相关文档😅。所以一开始就是按照新建项目后默认提供的图标尺寸——114x114,结果发现安装到真机后,完全不匹配:
后面我通过类似二分查找的方法,最终测试感觉图标大小应该是 102:
由于应用需要的是一个圆形的图标,所以需要用工具把图标进行一个剪裁,如:在图像中剪切圆圈 - 免费工具
不过后面我仔细对比了一下其它应用的图标,发现 102 的尺寸有些许的偏小,所以推测实际上图标尺寸应该是 104 左右?
关于图标,还有一个坑——目前 watch fit3 有两种桌面形态,即棋盘和列表;不知道为啥我这应用在棋盘模式下不会出现,但在列表模式下会出现,且在选择 APP 的列表也能发现这个应用,难道要让应用出现在棋盘桌面下还另有配置?我反正完全找不到相关文档和说明😅。
项目层级 node_modules 冲突
我本来想在该项目使用 Bun 来执行 TS 脚本,于是就在项目层级进行了初始化,但貌似如果项目根目录出现 node_modules 目录,就无法正常进行编译了,大概是跟以前的鸿蒙应用使用了普通的 npm 包来进行模块管理,现在换成了 ohpm 但没有完全去除之前的那套逻辑?解决办法就是不要在项目层级初始化 node_modules,移到某个子目录下即可:
Cursor Rules 的用法
整个应用的开发过程,除了踩了很多坑之外,令人欣慰的是还无意中解锁了一些 Cursor 的有意思的用法。
指令缩写“函数”
在使用 Agent 将华为的开发文档转为本地 markdown 文档的过程中,我突然意识到每次重复一条条相似的指令有点“蠢”,指令应该也能复用吧?于是正好想到了 Cursor 有个 Rules 功能来着,然后试了一下,果然通过 Rules 可以把复杂的指令进行缩写,保留关键信息即可,就如同编程中复用逻辑时创建函数一样:
上面的就是原始的提示词,不难发现这个提示词有两个参数——网址和文件名,那么可以编写如下的 Rules:
通过指定上面的 Rules,Agent 就可以通过缩写后的指令来补全还原成原始的提示词:
这样在进行重复操作时,要写的提示词就大大变少了;不过都抽象成“函数”了,要是 Cursor 能够提供一种自定义提示词模板的 UI 交互就更方便,比如只填参数内容,然后把参数填到模板中,再把完整的提示词发送给 Agent😏。
特定文件的专属知识库
通过上面的方法,我收集了一些跟穿戴应用 JS 开发框架相关的核心文档:
而这些文档就可以作为开发应用页面时的专属知识库,以便让 Cursor 可以写出符合文档的代码(不然它可能会把相关的代码开发当成普通的 html 或者小程序的语法),这样就不用每次都在提示词中指定知识库上下文了:
当然,同一个项目可以为不同范围的文件指定不同的规则,比如: