☰
AI辅助开发Zepp OS手表应用:番茄钟与待办清单实战
2026/10/10 14:50:00 网站建设 项目流程

1. 一个旧手表引发的开发冲动

手腕上这块华米Amazfit GTR4,买了快两年,当初看中的是它续航长、屏幕常亮、运动记录够用。但用久了就发现一个问题:它的应用生态实在谈不上丰富,尤其是那种能跟手机深度联动的效率类小工具,几乎找不到趁手的。我平时写代码、写稿子,习惯用番茄工作法来切分时间,手机上的番茄App倒是装了好几个,可每次都要掏手机、解锁、点开App,一套动作下来注意力早就散了。手表就在手腕上,抬腕就能看,为什么不能直接在手表上跑一个番茄钟加待办清单?

这个念头一冒出来就压不住了。但问题也很现实:GTR4用的是Zepp OS,不是Wear OS,也不是watchOS,它的应用开发体系相对小众,官方文档虽然有,但社区案例少得可怜。我一开始心里也没底,不知道这套东西到底能不能撑起一个完整的番茄代办应用。后来转念一想,现在AI coding工具这么成熟,很多样板代码、API调用、UI布局都可以让AI帮我生成初稿,我再基于官方文档去校对和调整,效率应该能提上来。于是就有了这个项目:用AI coding辅助,给这块旧手表写一个能用的番茄代办App。

这篇文章我会把整个开发过程拆开来讲,包括我怎么理解Zepp OS的应用架构、怎么用AI coding工具来加速开发、番茄钟的核心逻辑怎么写、待办清单的数据怎么存、手表和手机之间怎么通信、真机调试踩了哪些坑。如果你手上也有一块Zepp OS的手表,或者你单纯对“用AI辅助开发小众平台应用”这件事感兴趣,这篇内容应该能给你不少可直接参考的东西。整个项目不复杂,但麻雀虽小五脏俱全,从UI到逻辑到数据存储到设备通信,该有的环节一个不少。

2. 先搞清楚Zepp OS到底能做什么

2.1 Zepp OS的应用架构与能力边界

在动手写代码之前,我必须先弄明白Zepp OS的应用到底是怎么跑的。这块如果搞不清楚,后面写出来的代码大概率跑不起来。Zepp OS的应用架构跟Android Wear那套完全不一样,它更接近一种“轻量级小程序”的思路。一个Zepp OS应用主要由两部分组成:一部分是运行在手表端的页面和逻辑,另一部分是运行在手机端Zepp App里的侧服务。手表端负责UI渲染、传感器调用、本地数据读写;手机端侧服务负责跟手表端通信、访问网络、调用手机端更重的计算能力。

这个架构决定了我的番茄代办App该怎么拆分功能。番茄钟的计时、界面展示、按钮交互,这些必须放在手表端,因为用户是直接在手表上操作的。待办清单的增删改查,如果只存在手表本地,那手机端就看不到,换手表数据就丢了。所以我需要把待办数据同步到手机端,甚至进一步同步到云端。但第一版我不想搞太复杂,先把核心功能跑通:手表端能独立完成番茄计时和待办的本地管理,手机端侧服务负责在需要的时候做数据备份和跨设备同步。

Zepp OS的应用包结构也有讲究。一个典型的应用目录里会有app.json配置文件、page目录放页面、app.js作为入口、以及各种资源文件。app.json里要声明应用用到了哪些权限、注册了哪些页面、侧服务怎么配置。这些配置项如果写错了,应用要么装不上,要么装上了打不开。我一开始就是在这个配置文件上卡了很久,后面会细说。

2.2 为什么选AI coding而不是纯手写

你可能会问,既然官方文档都有,为什么不直接照着文档手写?原因很简单:Zepp OS的文档虽然覆盖了主要API,但示例代码比较零散,很多实际开发中会遇到的问题文档里并没有展开讲。比如页面之间的跳转参数怎么传、本地存储的容量上限是多少、定时器在后台会不会被系统杀掉,这些细节文档里要么一笔带过,要么根本没提。

AI coding工具在这里的价值就体现出来了。我可以把官方文档里的API说明贴给AI,让它帮我生成一个符合Zepp OS规范的页面骨架,包括生命周期函数、UI组件声明、事件绑定。AI生成的代码不一定完全正确,但它能帮我省掉大量查文档、拼样板代码的时间。我拿到初稿之后,再对照官方文档逐行检查,把不对的地方改掉。这个过程比我从零开始写要快得多,尤其是UI布局这种重复性高、逻辑性弱的部分。

但这里有个前提:你不能完全信任AI生成的代码。Zepp OS的API跟Web开发、跟React Native都不一样,AI如果没见过足够的Zepp OS代码,它生成的很多东西会是“看起来像那么回事,但实际跑不起来”。我的做法是,先把官方文档里最核心的几个API(比如hmUI.createWidget、hmFS、hmBle)的用法喂给AI,让它基于这些真实API来生成代码,而不是让它自由发挥。这样出来的代码可用率会高很多。

2.3 功能范围的取舍:第一版做什么,不做什么

一个番茄代办App听起来简单,但真要展开,功能可以无限多。我在动手之前先给自己划了一条线:第一版只做最核心的三件事。第一,番茄钟计时,支持25分钟工作、5分钟休息的经典模式,可以开始、暂停、重置。第二,待办清单,支持添加、勾选完成、删除,数据存在手表本地。第三,手表端和手机端侧服务之间的基础通信,能把待办数据同步到手机端。

不做的事情也很明确:不做账号系统、不做云端同步、不做复杂的统计报表、不做多主题换肤。这些不是不重要,而是第一版没必要。先把核心链路跑通,验证Zepp OS能不能撑起这个应用场景,再考虑扩展。这个取舍很关键,因为Zepp OS的资源有限,手表端的内存和存储都比手机小得多,功能堆太多容易导致应用卡顿甚至崩溃。

3. 开发环境搭建与AI coding工作流

3.1 工具链准备:从零到能跑Hello World

Zepp OS的开发工具链不算复杂,但有几个必须装的東西。首先是Node.js环境,官方提供的CLI工具是基于Node的。然后是Zepp OS的开发者工具,它提供了一个模拟器,可以在电脑上预览手表端的界面效果。最后是Zepp App的开发者模式,用来把编译好的应用包推送到真机上调试。

我装完这些之后,第一件事是跑通官方的Hello World示例。这一步看着简单,但其实是整个项目里最关键的一步。因为只有Hello World跑通了,你才能确认你的开发环境、模拟器、真机连接、应用签名这一整套链路是通的。我见过不少人一上来就写复杂功能,结果卡在环境问题上好几天,最后发现是某个配置项没填对。

Hello World跑通之后,我做的第二件事是把官方文档里关于app.json的配置说明完整看了一遍。这个文件相当于应用的“身份证”,里面要声明应用名称、版本号、图标、页面路径、权限列表、侧服务配置。我建议你把这个文件里每一个字段的含义都搞清楚,因为后面遇到的大部分“应用装不上”“页面打不开”的问题,根源都在这里。

3.2 用AI生成第一版页面骨架的实操记录

环境准备好之后,我开始用AI coding工具生成第一版页面骨架。我的做法是这样的:先把官方文档里关于页面生命周期的说明复制出来,包括onInit、onReady、onShow、onHide、onDestroy这几个函数的调用时机和用途。然后我把这些内容作为上下文喂给AI,让它帮我生成一个番茄钟页面的骨架,要求包含一个显示时间的文本组件、三个按钮(开始、暂停、重置),以及对应的点击事件处理函数。

AI第一次生成的代码里,UI组件的创建方式用的是类似HTML的写法,这明显不对,因为Zepp OS用的是hmUI.createWidget这种命令式的API。我把官方文档里hmUI.createWidget的示例贴给它,让它重新生成。第二次生成的代码就靠谱多了,基本结构是对的,但有几个细节问题:按钮的点击事件绑定方式不对,文本组件的更新方式也不对。我手动改了这两处,页面就能在模拟器里正常显示了。

这个过程让我总结出一个经验:用AI coding开发小众平台,你不能指望它一次生成完全正确的代码,但你可以把它当成一个“高级代码补全工具”。你给它越多的真实API示例,它生成的代码就越接近可用。反过来,如果你只给它一个模糊的需求描述,它生成的东西大概率是没法用的。

3.3 模拟器调试与真机部署的差异

模拟器里跑通之后,我迫不及待地想把应用推到真机上试试。结果第一次真机部署就失败了,应用装上了但打开就闪退。我一开始以为是代码问题,排查了半天才发现是权限声明的问题。模拟器对权限的检查比较宽松,但真机上的Zepp OS对权限管得很严,你在app.json里没声明的权限,代码里调用了就会直接崩溃。

具体来说,我的应用用到了本地存储和震动反馈,这两个都需要在app.json的权限列表里显式声明。我补上之后重新打包,真机上就能正常打开了。这件事给我的教训是:模拟器只能验证UI和基本逻辑,真机才是最终的试金石。任何涉及硬件能力(震动、传感器、蓝牙通信)的功能,都必须在真机上验证。

另外还有一个差异是性能。模拟器跑在电脑上,性能比手表强得多,有些在模拟器里看起来很流畅的动画,到了真机上就会卡顿。所以我在真机测试的时候,会特别关注页面切换的流畅度和定时器更新的及时性。如果发现卡顿,就要考虑是不是UI组件创建得太频繁,或者定时器的间隔设得太短。

4. 番茄钟核心逻辑的实现细节

4.1 计时器方案选型:setInterval还是setTimeout

番茄钟的核心就是一个计时器。在Zepp OS里,可用的计时方案主要有两种:setInterval和setTimeout。setInterval是每隔固定时间执行一次回调,setTimeout是延迟一段时间后执行一次回调。对于番茄钟来说,我需要每秒更新一次界面上的倒计时显示,所以直觉上应该用setInterval,间隔设为1000毫秒。

但实际用下来发现,setInterval在Zepp OS上有个问题:如果页面被切到后台,或者手表进入息屏状态,setInterval的回调可能会被系统暂停或延迟。这会导致计时不准确。比如你设了25分钟,实际可能过了27分钟才提醒你。对于番茄钟来说,这个误差是可以接受的,但如果你想要更精确的计时,就需要换一种方案。

我最后的做法是:用setTimeout来驱动计时,每次回调里重新计算剩余时间,而不是简单地累加。具体来说,我在开始计时的时候记录一个起始时间戳,然后每次setTimeout触发时,用当前时间戳减去起始时间戳,算出已经过去了多少秒,再更新界面。这样即使回调被延迟了,下一次回调也能自动纠正回来,不会累积误差。这个方案比单纯用setInterval累加要可靠得多。

4.2 状态管理:工作、休息、暂停、重置的切换逻辑

番茄钟有四个状态:工作中、休息中、暂停、空闲。这四个状态之间的切换逻辑必须理清楚,否则会出现“暂停之后点开始,结果从休息状态开始了”这种bug。我用一个状态变量来记录当前状态,然后在每个按钮的点击事件里根据当前状态来决定下一步动作。

具体来说,状态机是这样的:空闲状态下,点开始进入工作状态,计时25分钟;工作状态下,点暂停进入暂停状态,计时停止;暂停状态下,点开始回到之前的状态继续计时;工作状态计时结束后,自动进入休息状态,计时5分钟;休息状态计时结束后,自动回到空闲状态。重置按钮在任何状态下都可以点,点了之后回到空闲状态,计时归零。

这个状态机看着简单,但实际写的时候很容易漏掉一些边界情况。比如在工作状态下点重置,然后再点开始,应该从工作状态重新开始,而不是从休息状态开始。再比如在暂停状态下点重置,暂停状态应该被清除。这些边界情况我在测试的时候一个个试过,确保每个状态转换都符合预期。

4.3 界面刷新与性能平衡

番茄钟的界面需要每秒刷新一次倒计时显示。在Zepp OS里,刷新界面上的文本组件用的是widget.setProperty方法。这个方法本身不慢,但如果每秒调用一次,而且同时刷新多个组件,在手表上还是能感觉到一点卡顿。我一开始的写法是每秒刷新倒计时文本、状态文本、进度条三个组件,结果手表上看起来有点掉帧。

后来我做了两个优化。第一,把进度条的刷新频率降低,改成每5秒刷新一次,因为进度条的变化本来就不需要那么精细。第二,把状态文本的刷新跟倒计时文本合并,只在状态真正变化的时候才更新状态文本,而不是每秒都更新。这两个优化做完之后,界面流畅度明显提升。

还有一个细节是,当页面不可见的时候(比如用户按了手表的主页键),应该暂停计时器的刷新,等页面重新可见时再恢复。这个可以用页面的onHide和onShow生命周期函数来实现。如果不做这个处理,页面在后台还在不停刷新,会白白消耗电量。

5. 待办清单的数据存储与同步

5.1 本地存储方案:hmFS的使用要点

待办清单的数据需要持久化存储,否则一关应用数据就没了。Zepp OS提供了hmFS这个文件系统API,可以用来读写本地文件。我用它来存一个JSON格式的待办列表,每条待办包含id、内容、是否完成、创建时间这几个字段。

hmFS的用法跟Node.js的fs模块有点像,但有几个坑要注意。第一,文件路径必须是以/开头的绝对路径,而且只能写在应用自己的沙箱目录里,不能写到系统目录。第二,写入操作是异步的,需要传回调函数,如果你在写入完成之前就去读,可能会读到旧数据。第三,存储空间有限,官方文档里说单个应用能用的存储空间大概是几MB,对于待办清单来说完全够用,但如果你要存大量数据,就要考虑分文件存储或者定期清理。

我一开始犯的错误是每次添加待办都重新写整个文件。这个做法在待办数量少的时候没问题,但待办一多,每次写入的数据量就上去了,手表上能感觉到明显的延迟。后来我改成只在数据真正变化的时候才写入,而且写入之前先把数据序列化成JSON字符串,减少写入的数据量。

5.2 待办数据的增删改查实现

待办的增删改查逻辑本身不复杂,但有几个细节需要处理好。添加待办的时候,需要生成一个唯一的id,我用的方案是时间戳加上一个随机数,这样基本不会重复。勾选完成的时候,只需要把对应id的待办的完成状态翻转一下,然后重新渲染列表。删除待办的时候,需要从数组里移除对应的项,然后重新渲染。

列表渲染这块,Zepp OS没有提供类似React的虚拟DOM机制,所以每次数据变化都需要手动重建列表。如果待办数量多,每次都全部重建会比较慢。我的优化方案是,只重建发生变化的那一项,而不是整个列表。具体来说,我给每个待办项创建一个独立的widget,数据变化时只更新对应的widget,而不是销毁重建。这个优化在待办数量超过10条的时候效果很明显。

还有一个细节是空状态的显示。当待办列表为空的时候,应该显示一个提示文案,而不是一片空白。这个提示文案的widget在列表有数据的时候要隐藏,列表为空的时候要显示。我用的是widget.setVisibility方法来控制显示和隐藏。

5.3 手表与手机端侧服务的通信机制

手表端和手机端侧服务的通信,Zepp OS提供了hmBle这个API。它的用法是,手表端和手机端各自注册一个消息监听器,然后通过hmBle.send来发送消息。消息的内容可以是字符串或者二进制数据,我用的方案是把待办数据序列化成JSON字符串再发送。

这里有个坑要注意:hmBle的通信不是实时的,它依赖于蓝牙连接的状态。如果手表和手机的蓝牙断了,消息就发不出去。所以我在发送消息之前会先检查蓝牙连接状态,如果没连接就先把数据存在本地,等连接恢复了再同步。这个逻辑我用了一个简单的队列来实现,未发送的消息先入队,连接恢复后依次发送。

手机端侧服务的代码是跑在Zepp App里的,它可以用更丰富的API,比如访问网络、读写手机本地存储。我第一版只做了最基础的接收和存储,把手表端发来的待办数据存到手机本地,没有做云端同步。后面如果要扩展,可以在侧服务里加一个网络请求,把数据同步到云端。

6. 真机调试踩坑实录与排查技巧

6.1 应用闪退的常见原因与排查路径

真机调试阶段我遇到最多的就是闪退。应用闪退的原因有很多种,排查起来需要一点耐心。我总结了一个排查路径:先看日志,再看权限,再看API调用,最后看内存。

日志是最直接的线索。Zepp OS的开发者工具可以查看真机上的运行日志,应用崩溃的时候通常会打印出错误堆栈。我遇到过一次闪退,日志里显示是hmUI.createWidget调用失败,原因是我在一个页面销毁之后又去创建widget,这时候页面上下文已经不存在了。解决办法是在页面销毁的时候把所有的定时器和异步操作都清理掉,避免在页面销毁后还有代码在跑。

权限问题也很常见。前面提到过,真机上没声明的权限调用会直接崩溃。我建议你在开发过程中,每用到一个新的系统能力,就先去app.json里把对应的权限加上,不要等到最后再补。

API调用错误是另一个高频原因。Zepp OS的API对参数类型和取值范围有严格要求,传错了就会抛异常。比如hmFS的文件路径如果不符合规范,就会直接报错。这类问题最好的解决办法是仔细看官方文档里的参数说明,不要凭直觉传参。

6.2 定时器在后台被暂停的应对方案

前面提到过,setInterval和setTimeout在手表息屏或者页面切到后台的时候可能会被系统暂停。这个问题在番茄钟场景下特别明显:用户设了25分钟,然后把手表放下去做别的事,结果手表息屏之后计时器就不走了,25分钟到了也不会提醒。

我试过几种方案。第一种是用hmSensor里的定时器API,但那个主要是给传感器采样用的,不适合做长时间计时。第二种是用系统闹钟API,但那个需要用户手动确认,体验不好。最后我采用的方案是,在页面onHide的时候记录当前剩余时间,然后在onShow的时候重新计算已经过去了多少时间,如果超过了预设的时长,就直接触发提醒。这个方案不能保证精确到秒的提醒,但能保证用户回来的时候看到的是正确的剩余时间,不会出现“明明过了25分钟但手表上还显示剩10分钟”的情况。

6.3 常见问题速查表

问题现象可能原因排查方法解决方案
应用装不上app.json配置错误检查app.json的字段格式对照官方文档逐字段核对
应用打开闪退权限未声明查看真机日志在app.json里补上对应权限
页面显示空白页面路径配置错误检查app.json里的页面注册确保页面路径与实际文件一致
计时不准确定时器被系统暂停观察息屏后的计时变化用时间戳差值计算剩余时间
数据丢失写入未完成就读取检查写入回调确保在回调里再执行后续操作
列表卡顿全量重建widget观察待办数量多时的表现只更新变化的widget
蓝牙通信失败蓝牙未连接检查连接状态未连接时先存本地,恢复后同步

这张表里的问题都是我实际遇到过的,解决方案也是验证过可行的。如果你在开发过程中遇到类似的问题,可以先对照这张表排查一下。

7. 一些关于AI coding的真心话

用AI coding辅助开发这个项目,我的整体感受是:它确实能提效,但前提是你自己得懂。AI生成的代码,你得有能力判断它对不对、好不好、能不能用。如果你完全不懂Zepp OS的开发,AI给你一段代码你也不知道它是不是符合规范,出了问题你也不知道怎么排查。所以AI coding不是替代学习,而是加速学习之后的产出。

另外一个感受是,AI在小众平台上的表现明显不如在主流平台上。你让AI写一个React组件,它大概率写得不错;但你让AI写一个Zepp OS的页面,它经常会用错API。这时候就需要你把官方文档里的真实示例喂给它,让它基于真实API来生成。这个“喂文档”的过程,其实也是你自己重新学习一遍的过程,一举两得。

最后说一个实际的小技巧:我在用AI生成代码的时候,会要求它把每一段代码的用途用注释写清楚。这样我拿到代码之后,即使有些地方需要改,我也能快速理解它的意图,改起来更有方向。这个习惯帮我省了不少时间,推荐你也试试。

这个项目我还会继续迭代,下一步打算把待办数据同步到手机端侧服务之后,再加一个简单的统计功能,看看每周完成了多少个番茄钟。如果你也在折腾Zepp OS的应用开发,或者你用AI coding做过类似的小项目,欢迎一起交流。手表虽然旧,但能跑自己写的应用,这种感觉还是挺不一样的。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询