这块GTR4在我抽屉里充电放了近半年,开屏还是熟悉的表盘,电量也还能撑好几天。闲着刷到AI coding的讨论,我冒出一个念头:与其让这块旧手表继续吃灰,不如给它写个真正用得上的应用。于是我用AI coding给它做了一个番茄钟加待办事项的小应用,从工程初始化到真机安装,前后折腾了一周。这篇就是完整的过程复盘,包含Zepp OS开发里最容易踩的坑、番茄钟状态机的设计思路、手表端持久化方案,以及AI coding在穿戴设备开发中真实能顶多少用。想给闲置智能表写点东西、或者对AI辅助硬件开发感兴趣的朋友,应该能从中拿到不少可复用的经验。
1. 闲置手表与AI编码的适配判断:GTR4还能怎么用
1.1 硬件底子与系统开放度评估
先给不太了解这块表的读者补个背景。Amazfit GTR4用的是1.43英寸圆形AMOLED屏,分辨率466x466,运行Zepp OS系统,官方开放了面向普通应用的JavaScript开发链路。对折腾过智能手表开发的人来说,这意味着它不像某些完全封闭的穿戴系统,你确实能往里面塞自己的小应用,而且是正经跑在手表上的那种,不是手机端模拟一个假面板。
评估硬件能不能做番茄钟,其实我主要看三点:
| 评估项 | GTR4上的情况 | 对番茄钟应用的意义 |
|---|---|---|
| 屏幕 | 1.43英寸圆形AMOLED,466x466 | 显示足够清楚,能一屏放下计时器、待办标题和操作按钮 |
| 震动马达 | 系统提供振动模块 | 专注结束提醒靠的就是它,不打搅别人 |
| 处理器和内存 | 能跑JS应用,但远不如手机 | 适合轻量交互,不适合重型列表和动画 |
| 电池续航 | 正常使用能撑几天到一周 | 一个计时器应用耗电可控,不需要一天一充 |
系统层面还有一个现实:Zepp OS对单个安装包体积有比较严的限制,小应用被压在几MB的尺度内。番茄钟加待办这种纯文本交互应用,完全在这个预算里。反过来说,如果你打算做一个带大量资源文件的应用,就得提前考虑打包体积和运行时内存了。
1.2 番茄代办这个需求为什么适合手表
我在手机上用过很多款番茄钟,问题都一样:锁屏、倒计时、弹窗提醒,看起来啥都有,但效率工具的宿命就是被其他App的消息淹没。手表不一样,它是长在手腕上的设备,交互天然短促。专注开始前,我只需要抬腕、点一下、放下手臂;专注结束时,手表震动就能把我拉回现实。
这就是我判断需求成立的逻辑:番茄钟的核心场景是短交互加物理反馈,恰好是手表的强项。如果是文档编辑、图片查看这种长时间耗在屏幕上的需求,放在手表上纯属受罪。待办事项在手表上也不会做得太重——它更适合做“看一眼今天做什么”的速查清单,而不是项目管理工具。把需求压缩到这个尺度后,GTR4的屏幕、内存、输入方式都够用,项目复杂度也控制得住。
1.3 项目中AI coding的边界定位
老实说,如果完全手写,这个项目也能做,但效率会低不少。我选AI coding的原因很直接:我想让AI帮我快速生成页面骨架、状态机样板和JSON读写这类胶水代码,把时间花在真机调试和交互打磨上。
但我对AI coding的定位从一开始就不是“让它全权代劳”。我在心里给它划了条边界:架构决策、设备能力判断、真机验证这些事必须掌握在自己手里,AI负责的是代码块生成和反复迭代中的快速试错。后来证明这个定位非常关键。Zepp OS的开发资料不像前端、后端生态那么密集,AI预训练里可能只见过一些相似代码,直接让它“自由发挥”会生成一堆根本不存在的API。我把自己的需求描述得越清晰,AI的输出就越接近能跑。项目做到后半程,我几乎形成了一套固定的提问模板,这个后面专门开一节讲。
2. 工程从零到能跑:Zepp OS的开发链路与工程结构
2.1 环境准备:CLI、模拟器和空工程的第一个构建
Zepp OS的官方开发链路基本围绕一套命令行工具和配套IDE展开。我先把环境搭起来,成功跑通一个空工程后,再让AI介入。
当时我的操作步骤大概是这样:
- 安装Node环境,用npm装好Zepp OS CLI工具。
- 用CLI初始化一个空应用工程,模板选基础JS应用。
- 在官方模拟器里打开编译产物,确认空应用能正常启动。
- 真机准备工作:手表开启开发者模式,和手机App扫码配对后,通过安装入口把应用包推到手表上。
过程中最容易被忽略的是版本匹配问题。CLI版本、项目模板版本、手表系统版本三者如果不一致,经常出现编译报错或者安装后打不开。我第一次构建的时候,项目跑在模拟器上没问题,推到真机却闪退,排查半天发现是模板默认依赖的版本号和一个常量字段跟当前系统不兼容。吃一堑长一智,现在我每次新建工程,第一步就是确认版本组合,而不是急着写业务代码。
2.2 app.json与页面配置里的常见坑
空工程跑通之后,第二步是弄明白配置文件的含义。项目根目录的app.json是应用的门脸,通常包含应用类型、应用ID、名称、版本号、入口页面声明、图标路径等字段。
这套配置非常容易被忽略,但它决定了应用能不能被系统正确识别和启动。我遇到的典型问题有两个。
第一个是应用ID不合法。不同系统对应用ID格式要求严格,得用反域名格式。我一开始随手写了个myapp,在模拟器上倒还能跑,但真机安装时直接拒绝。
第二个坑在页面路径声明。应用必须明确告诉系统“我的页面文件在哪”,这部分容易因为大小写不一致或者扩展名不对导致启动白屏。Zepp OS项目的页面目录结构长这样:
app.json app.js pages/ index/ index.page.js index.page.ui.js assets/ icon.png build/看起来标准的SPA应用结构其实别有洞天:页面逻辑和页面UI是拆开的,逻辑文件负责数据和交互,UI文件负责画界面。这就涉及到一个关键认知:这块手表上没有浏览器,没有DOM,UI层是系统自己的组件体系。跟Web开发里随便写div完全不同。AI第一次帮我生成UI代码时完全没意识到这点,直接给我整了花架子。
2.3 页面代码的基本生命周期与一次加载流程
理解了目录结构,接下来要说的是应用运行起来后的加载流程。Zepp OS应用的运行机制比手机App简单不少,生命周期也更短平快:启动一个应用后,系统会先加载应用入口,然后创建页面对象,再执行页面初始化、准备UI、页面显示这几个步骤,退出时执行清理。
番茄钟应用启动后需要做的事情必须附着在这些生命周期事件上。我的做法是:
- 应用入口层初始化全局变量;
- 页面初始化阶段读取本地待办文件;
- UI就绪后渲染列表和状态;
- 用户点击开始后启动计时刷新循环;
- 页面销毁时把计时状态持久化,避免丢数据。
这里有个特别容易踩的坑:很多新手会把耗时操作直接写在初始化阶段,导致进入应用时出现短暂卡顿。手表性能不比手机,像文件读取这种操作应该尽量精简,数据量大时还要考虑异步处理。我的做法是启动时只读取最近使用的一小批数据,把全量待办列表的构建懒加载推迟到用户滚动到底部时。
3. 番茄计时器的可靠性设计:不是setInterval那么简单
3.1 从时间戳出发的状态机设计
番茄钟的核心是状态切换。刚开始我天真地以为,只要在代码里用定时器每秒减一秒,到点震动就行。真机测试后我意识到一个问题:手表会因为熄屏、切换应用、系统调度等一系列原因让JS执行暂停。如果我只是简单累减一个计数变量,那么暂停的时间就会被“吃掉”,倒计时就失真了。
解决方案不复杂,核心思路是:不依赖计时次数,只记录目标时间戳。也就是说,专注开始时我记录下“预计结束时间”,刷新UI时用当前时间减去开始时间算出剩余值。就算中途暂停了多久,重新唤起时计算出来的剩余时间依然正确。
状态机的设计我整理成了这么一张表:
| 状态 | 进入方式 | 持续时间 | 退出行为 |
|---|---|---|---|
| 空闲 | 打开应用 | 不限 | 点击“开始专注”进入专注态 |
| 专注中 | 从空闲进入 | 25分钟 | 倒计时归零后进入休息态 |
| 短休息 | 专注结束 | 5分钟 | 进入空闲,或继续进入下一轮专注 |
| 长休息 | 完成4轮专注 | 15分钟 | 回到空闲并重置轮次 |
这个表在最初靠AI生成时,AI差点把长休息的轮次判断写成“休息结束后再手点一次长休息”。我后来在提示里反复强调“轮次计数独立存储”,AI才给出正确方案。这段经历让我加深了印象:AI能把表格逻辑写得清晰,但业务规则还是得人来定义。
3.2 刷新循环如何兼顾节电与观感
手表上做倒计时UI,最直接的方案是每秒刷新一次剩余时间显示。屏幕开启情况下,这个刷新频率完全没问题,画面流畅不卡顿。但如果我依赖一个每100毫秒触发一次的定时器去做秒表动画,就属于浪费电量。
我的实际体验是:每秒刷新一次足够,但刷新动作要轻。也就是每秒只更新文本内容,而不是重新渲染整个页面。另外,在秒级显示的时候,倒计时数字变化是逐秒跳动的;我为了让视觉反馈更明显,把剩余时间每分钟的前30秒显示成“分钟+秒”,后30秒显示成“分钟”,既给了变化感知,又不会让人觉得屏幕一直在闪。
更重要的是,刷新循环必须跟着页面生命周期走。页面不可见时应该立即停止定时器,等页面回到前台再重新启动,而不是让定时器在后台空跑。这点上我最初没处理好,导致手表待机时间明显变短。后来在页面销毁事件里强制清理定时器,这个问题才消失。
3.3 震动反馈的调用细节与体验优化
番茄钟能不能形成闭环,震动提醒是关键一环。Zepp OS系统提供了震动模块调用接口,传入震动参数即可。开发文档通常给的是开关震动、连续震动、按模式数组震动这类功能。
我的使用场景有三个:开始专注时轻轻震一下,专注结束时连续震动三次,手动跳过休息时轻震一下。调试中发现的细节是:
- 震动参数用毫秒级的开关列表描述时,不同系统版本对列表的支持度有差异;
- 震动时间太长或太频繁会明显增加耗电,长震10秒以上的场景要避免;
- 页面在后台时震动能力可能受到限制,所以提醒要尽量在一个应用生命周期内完成。
我实际测试下来,短促的振动反馈比长震动更符合交互习惯。试想一下,你戴着表开会,突然整只手表开始狂震,那画面太尴尬。所以最终方案很短:开始震动80毫秒,结束震动三轮各200毫秒,中间间隔200毫秒,整体控制在1秒以内。
4. 待办事项的持久化:手表上的文件存储实战
4.1 数据结构与容量规划
待办功能看起来简单,但落在手表上必须控制数据规模。手机上的待办列表动辄几百条,手表端要真塞几百条,光是滚动就够累的。我一开始规划的数据结构是一个数组,每个待办对象包含这样几个字段:
{ id: 'task_001', text: '整理周报数据', done: false, createdAt: '2025-01-10T09:00:00Z', completedAt: null }开发时加了个硬性限制:列表最多保留50条。如果用户想要新增待办但列表已满,我会在界面提示“先清理完成项再添加新的”。这不是偷懒——文件存储、内存占用、滚动渲染性能都和条目数直接相关,50条在这个应用里是最佳平衡点。单个JSON文件也就几十KB,完全不会触碰到表端存储包体积的红线。
4.2 fs读写与防丢策略
手表端的存储读写能力和PC是完全两个量级,但好在系统提供了简易文件接口,能让我们以文本方式保存结构化数据。我的方案是把待办列表序列化成JSON字符串,写入应用自有目录的一个文件里。
写入时机是另一个需要琢磨的点。如果每次编辑都立刻写盘,频繁写入会影响性能和手表的存储寿命;如果只在退出应用时写一次,又怕中途异常退出丢数据。我的折中方案是:
- 用户每次操作完成时立即写盘,比如勾选完成、新增待办;
- 倒计时状态只在进入和退出专注时写盘;
- 文件内容结构里带一个增量标记,后续可以考虑合并减少写盘频率。
防丢方面,我做了恢复兜底:写文件时先写临时文件,成功后再覆盖正式文件。如果读取正式文件失败,回退读取临时文件。这套策略虽然简单,但足够应付日常使用中90%以上的异常场景。
4.3 首版不做手机同步的取舍说明
我知道很多人看到待办功能,第一反应是:“能不能和手机上的日历/待办应用同步?”我也考虑过,但后来决定首版先不做,原因很实际:
- 手表和手机之间通信需要做配套的数据通道配置,调试成本翻倍;
- 同步机制涉及数据冲突、离线策略等问题,复杂度会膨胀;
- 番茄钟的核心场景本来就是“拿起手表就用”,同步反而引入额外的连接依赖。
所以我做了范围控制:首版待办数据完全本地存储,卸载应用会自动清空数据,这算是我希望用户知道的边界。后续如果要做同步,方向也很明确:通过系统提供的设备间通信能力,把手表端的待办变更推给手机端,再做双向合入。但那是二期的事,这一期尝鲜用足够了。
5. 在1.43英寸圆屏上做UI:改到第五版才敢说能用的交互
5.1 安全区域与信息层级
圆形屏幕比方形屏幕更尴尬的是四个角的显示内容会被裁掉。GTR4的屏占比虽然高,但任何文本如果贴着屏幕边缘走,总会有一段被表盘的弧形边框遮挡。所以布局第一课不是我写了多少界面,而是先搞明白系统安全区域有多大。
我的做法是:所有关键内容全部放在离屏幕边缘有一定余量的圆形内切矩形范围内,把实际可用区框成一个粗略的正方形来排布。比如底部区域不要摆放需要精确点击的控件,表盘下方边缘位置很容易被手误触。
信息层级我做了三档:主显区放番茄钟剩余时间,用大号字体;中段放当前选中的待办标题,最多显示一行,长标题通过省略号截断;底部是操作按钮区。主显区高度占比约四成,操作按钮至少占三成,剩下的给待办信息。因为用户抬腕看表的黄金时间是2秒左右,主信息必须一眼可见。
5.2 列表、按钮与滚动的手腕交互细节
手表上做列表比手机上麻烦得多,主要痛点就在点击精度和滚动方向控制。屏幕本身小,手指又粗,在手机上毫无压力的40像素高按钮,在手表上要放大到至少48像素才算好点。圆形屏幕还要额外照顾边缘区域的触控灵敏度,我发现靠近表冠位置的点击尤其容易误触,因此把所有核心操作都上移。
待办列表的滚动我做成了整列表区域可滑动,底部的“开始专注”按钮固定在列表下方,这样手指滑动列表时不会碰到按钮。还有一个细节是按钮间要保持足够间距,我最初把所有操作挤在同一行里,结果经常点错。后来改成上下排列,确认概率高多了。
这里要特别强调一个真机测试才能发现的问题:模拟器里鼠标点击的精准度和真机手指触摸完全是两回事。我在模拟器里觉得“这个按钮大小刚好”,真机一试才知道至少得再大一倍,所以UI验证一定以真机为准。
5.3 主题配色与实机可读性
GTR4是AMOLED屏,黑色背景天生省电又好看。我选用深灰底加高对比度纯白的配色方案,番茄钟在专注中时用橙色作为主题色,休息状态用青绿色,状态区分非常明显。
字体不是越大越好,而是选择关键信息足够醒目的组合。剩余时间我用了最大的数字字号,配合中等字重的单位标签,保证时间数字清晰可读;待办标题则是中号字体,不需要特别醒目,能辨认就行。户外光线比较强的时候,纯白文字配深色背景也是最耐看的组合,比浅色背景更不容易糊成一片。
做这轮UI时AI确实帮了大忙:配色、圆角、间距这些具体数值,AI能一次给出多组建议,我再拿到真机上试效果。但最终决策还是来自肉眼和手腕的实感——比如某些颜色在模拟器里挺好看,真机OLED上一看偏紫,只能改回纯色。
6. AI coding过程复盘:哪些环节真省力,哪些环节必须人工把关
6.1 一次生成成功率与翻车实例
先说结论:AI coding在这个项目里大概帮我把编码环节的耗时压缩了六成,但它不是不需要把关的。我整理了每个环节对AI的依赖度和人工介入情况:
| 任务 | AI生成质量 | 人工介入程度 | 备注 |
|---|---|---|---|
| 页面骨架和基础布局 | 高 | 低 | 生成后改改就能用 |
| 状态机逻辑 | 中 | 中 | 逻辑规则需要人工确认 |
| 文件持久化代码 | 低 | 高 | AI很容易猜错API |
| 真机调试 | 基本没有 | 极高 | 只能人来跑 |
| UI配色和尺寸微调 | 高 | 中 | 拿真机验证后很快 |
AI翻车的典型例子是文件持久化。AI给我生成了一段非常漂亮的代码,调用了一个叫“saveJSON”的接口,我翻遍文档都没找到这个接口——AI兴冲冲按照手机开发经验“脑补”出来的。遇到这种情况,最有效的做法不是跟AI反复说“你怎么错了”,而是把官方文档里的API示例直接贴给它,让它照着改。
6.2 长对话中的上下文漂移应对
AI编程对话有个常见的毛病:聊了十几轮之后,它开始忘记一开始约定的规则,或者在某个小改动里悄悄改变了前面的设计。我遇到过它在生成待办列表时突然把本地文件方案改成了云同步逻辑,也遇到过它在某个页面里用了另一套文字颜色体系。这些都是上下文漂移的表现。
我的应对办法是强制维持一份“项目约束块”,每次跟AI对话时都把以下内容贴在开头:
- 平台是Zepp OS 3.x,采用JavaScript开发;
- UI使用系统自带UI组件,不使用网页标签;
- 数据存储用本地文件,不能依赖外部网络;
- 番茄钟状态机见第3节规则,不允许修改;
- 单次对话只处理一个功能模块,不要跨模块重构。
这套约束块虽然啰嗦,但直接治好了AI的失忆症。我相当于把“项目上下文”从AI的隐性记忆里搬到了显性的提示里,每次都能拉回正轨。
6.3 能沉淀下来的AI协作工作流
经过这个项目,我总结出一套适合“AI coding + 穿戴设备开发”的协作流,分享出来也许能帮到想复刻类似项目的朋友:
- 先手写一个最小可运行的空壳工程,确保构建链和真机安装都通;
- 按照模块切片,一次只让AI生成一个模块的完整代码;
- 每轮对话都粘贴“项目约束块”,防止上下文漂移;
- AI生成的代码能跑不算完,必须逐段看一遍,对不认识的API一律抱着怀疑态度去查文档;
- 真机测试环节完全交给人工,AI的模拟能力还不足以替代穿戴设备的物理反馈和屏幕表现。
这套流程跑完,项目本身算是稳定交付了,我也算给这块旧表找到了最值当的新身份。最后一算,实际写代码的时间一半都不到,大部分时间花在“喂上下文”和“真机试错”上。如果本篇文章能让你避开我在Zepp OS开发里踩过的坑,少走一些弯路,那它就算达成使命了。