资讯动态

Zepp OS手表开发实战:AI辅助打造番茄待办应用

发布时间:2026/10/21 20:55:40 来源:尧图企业网站定制
1. 项目缘起与整体设计思路1.1 为什么要在旧手表上折腾一个番茄钟手上这块华米Amazfit GTR4已经戴了快两年屏幕没划痕、电池还能撑一周多唯一的问题就是——它自带的番茄钟功能太素了。系统只给了一个最基础的倒计时没有任务清单、没有专注统计、没有和待办事项的联动每次想记录一下今天完成了几个番茄、每个番茄对应什么任务都得掏出手机手动记体验割裂得不行。后来我琢磨了一下这块表跑的是Zepp OS官方开放了JS层面的应用开发框架支持侧载自定义应用。也就是说我完全可以自己写一个小应用把番茄钟和待办清单揉在一起直接跑在手表上。正好那段时间在深度使用AI coding工具辅助开发就想着拿这个项目练练手——目标很明确做一个能在GTR4上流畅运行的番茄待办App功能不用多但每个功能都得真正用得上。这个项目适合几类人参考一是手里有Zepp OS设备、想自己折腾点实用小工具的开发者二是对AI辅助编程感兴趣、想看看实际落地效果的人三是单纯想了解智能手表轻量应用开发流程的技术爱好者。不需要你有多深的嵌入式经验只要会基本的JavaScript剩下的边做边学完全来得及。1.2 功能边界的取舍逻辑做任何小工具第一件事不是想能加什么而是想必须砍什么。手表的屏幕就那么大交互方式只有触摸和侧键处理器性能和内存也远不如手机。我一开始列了一堆想法任务分类、优先级、标签、云同步、数据导出……后来全砍了只保留三个核心模块番茄计时器25分钟专注5分钟休息的经典循环支持暂停、跳过、重置待办清单每个番茄可以绑定一个任务名完成后自动记录专注统计当天完成的番茄数量、累计专注时长一屏展示砍掉的那些功能不是不好而是放在手表这个场景下性价比太低。比如云同步手表端做网络请求本身就麻烦而且我每天看统计也就是扫一眼根本不需要跨设备同步。再比如任务分类手机上做分类都嫌烦手表上更不可能去维护。这里有个经验手表应用的黄金法则是三秒原则——用户抬腕到完成操作不应该超过三秒。任何需要超过三次点击才能完成的功能都值得重新考虑是否要做。1.3 技术选型与AI coding的介入方式Zepp OS的应用开发用的是JavaScript配合官方的Zepp OS SDK界面用类似JSX的语法描述整体上手门槛不高。开发工具链方面官方提供了模拟器和真机调试通道可以在电脑上先跑通逻辑再推到手表上验证。AI coding在这个项目里的角色不是帮我写全部代码而是帮我快速跨过不熟悉的领域。我对JS本身很熟但Zepp OS的API文档结构、页面生命周期、传感器调用方式这些是全新的AI在这部分帮我省了大量翻文档的时间。具体来说我的工作流是这样的先自己理清功能逻辑和页面结构画出简单的状态流转图把每个页面的需求用自然语言描述给AI让它生成初版代码骨架自己审查代码重点看API调用是否符合Zepp OS规范在模拟器上跑遇到报错把错误信息贴给AI让它给排查方向真机测试根据实际表现调整UI尺寸和交互细节这个流程里AI承担的是快速产出可运行草稿的角色而判断、调试、优化这些核心环节还是得自己来。下面我把整个开发过程拆开把每个环节的关键细节都讲清楚。2. 开发环境搭建与核心细节解析2.1 Zepp OS开发环境的一次性配置Zepp OS的开发环境搭建不算复杂但有几个坑我踩过提前说清楚能省不少时间。首先你需要安装Node.js版本建议在16以上然后通过npm安装官方的CLI工具。安装命令大概是这样npm install -g zeppos/zeus-cli装完之后用zeus create命令创建一个新项目CLI会引导你选择项目模板。这里建议选Empty App模板不要选带示例代码的模板因为示例代码里有很多你用不上的东西反而干扰理解。创建完项目后目录结构大致是这样的app.json是全局配置app.js是应用入口page目录下放各个页面。每个页面由三个文件组成.js负责逻辑.ux负责界面描述.json负责页面配置。这个结构和很多前端框架类似有前端经验的人看起来会很亲切。注意CLI工具在Windows上的路径处理偶尔会有问题如果你在Windows上遇到命令找不到的情况试试用管理员权限重新打开终端或者检查一下npm的全局路径是否加到了系统环境变量里。2.2 页面结构设计与状态管理这个App我一共设计了三个页面主页番茄计时器、任务页待办清单、统计页专注数据。三个页面之间用官方的路由API跳转状态数据统一放在一个全局的store对象里管理。为什么不用每个页面各自管理状态因为番茄计时器的状态需要在页面切换时保持——比如你正在专注切到任务页看一下待办再切回来计时不能断。如果状态放在页面内部页面销毁时数据就丢了。用一个全局store所有页面读写同一份数据逻辑清晰也不容易出bug。store的结构大概是这样const store { timer: { status: idle, // idle / running / paused / break remaining: 1500, // 剩余秒数 currentTask: , // 当前绑定的任务 completedCount: 0 // 今日完成数 }, tasks: [], // 待办列表 stats: { date: , totalFocus: 0, sessions: [] } }这个结构看着简单但每个字段的存在都有理由。status用字符串而不是数字是为了代码可读性调试的时候一眼就能看出当前是什么状态。remaining用秒而不是毫秒是因为手表端做毫秒级计时没有意义反而增加计算负担。2.3 计时器精度的处理方案计时器是这个App的核心精度问题必须处理好。最朴素的做法是用setInterval每秒减一但这种方式在手表上有两个问题一是setInterval在后台可能被系统挂起导致计时不准二是长时间运行后累积误差会越来越大。我的方案是记录一个开始时间戳每次刷新时用当前时间减去开始时间算出实际经过的秒数再更新剩余时间。这样即使定时器被挂起几次恢复后也能立刻校正到正确的时间。具体逻辑// 开始计时时记录 store.timer.startTimestamp Date.now() store.timer.startRemaining store.timer.remaining // 每次刷新时计算 const elapsed Math.floor((Date.now() - store.timer.startTimestamp) / 1000) store.timer.remaining store.timer.startRemaining - elapsed这个方案的好处是计时精度只取决于系统时间不依赖定时器的准确性。实测下来连续跑25分钟误差在1秒以内完全够用。实操心得Zepp OS的定时器最小间隔建议不要低于500毫秒太频繁的刷新会明显增加耗电。我用的是1秒刷新一次配合时间戳校正既省电又准确。3. 核心功能实现与实操过程3.1 番茄计时器的完整实现计时器的界面很简单中间一个大号的时间数字下面两个按钮开始/暂停、重置顶部显示当前绑定的任务名。但简单界面背后的逻辑分支不少我把状态机画清楚之后才动手写代码。状态流转是这样的idle状态下点击开始进入runningrunning状态下点击暂停进入pausedpaused状态下点击继续回到running计时归零后如果是专注阶段就进入break如果是休息阶段就回到idle并完成计数。界面刷新用Zepp OS提供的setInterval配合页面生命周期。这里有个细节页面onShow的时候启动定时器onHide的时候要清掉否则页面切走后定时器还在跑白白耗电。但清掉定时器不代表计时停止因为我们的计时是基于时间戳的重新onShow时再启动定时器时间会自动校正。Page({ onShow() { this.timerId setInterval(() { this.updateTimer() }, 1000) }, onHide() { clearInterval(this.timerId) }, updateTimer() { if (store.timer.status ! running) return const elapsed Math.floor((Date.now() - store.timer.startTimestamp) / 1000) const remaining store.timer.startRemaining - elapsed if (remaining 0) { this.handleComplete() } else { store.timer.remaining remaining this.refreshUI() } } })handleComplete里处理计时结束的逻辑播放震动提醒、更新完成计数、切换阶段。震动用zeppos/sensor里的振动接口给一个短促的震动就行不用太强。3.2 待办清单的数据结构与交互待办清单我设计得很轻量一个数组每个元素是一个对象包含任务名、创建时间、是否完成、绑定的番茄数。界面上就是一个可滚动的列表点击某一项就把它设为当前任务计时器会自动绑定这个任务。数据结构{ id: task_001, name: 写项目文档, created: 1699000000000, done: false, pomodoros: 0 }添加任务的交互我纠结了很久。手表上打字太痛苦了所以最终方案是手表端只支持从预设的常用任务里选或者快速添加任务1、任务2这种占位名真正的任务编辑放在手机端的配套设置里。这样虽然牺牲了一点灵活性但换来了手表端操作的流畅性。踩过的坑一开始我想在手表上做全键盘输入结果发现屏幕太小按键根本点不准而且输入法切换很麻烦。后来改成预设列表语音输入调用系统语音转文字体验好了很多。如果你的设备支持语音输入强烈建议用这个方案。列表的滚动用官方的scroll组件注意设置好scroll-top和scroll-height否则在真机上可能出现滚动不流畅或者内容被截断的问题。每一项的高度我设的是80像素这个尺寸在GTR4的1.43英寸屏幕上刚好手指点起来不费劲。3.3 专注统计的数据记录与展示统计页展示三个数据今日完成番茄数、今日累计专注时长、最近七天的完成趋势。前两个数据实时从store里读第三个需要持久化存储。Zepp OS提供了本地存储API可以存一些简单的键值对。我每天结束时把当天的统计数据存进去键名用日期这样查历史数据的时候直接按日期读就行。// 保存当日统计 const today formatDate(new Date()) localStorage.setItem(stats_${today}, JSON.stringify(store.stats)) // 读取最近七天 const recent [] for (let i 0; i 7; i) { const d formatDate(new Date(Date.now() - i * 86400000)) const data localStorage.getItem(stats_${d}) recent.push(data ? JSON.parse(data) : { totalFocus: 0, sessions: [] }) }趋势展示我用的是简单的柱状图用矩形组件堆出来的没有引入图表库——手表端引入第三方库的代价太大而且这么简单的图表自己画反而更可控。每根柱子的高度按当天专注时长占七天最大值的比例来算最低给一个10像素的保底高度避免时长为零时柱子完全看不见。3.4 真机调试与性能优化实录模拟器上跑通不代表真机没问题。我第一次把应用推到手表上发现了三个问题一是启动速度慢从点击图标到界面出现大概要两秒多二是计时页面滑动切换时偶尔卡顿三是连续运行半小时后手表明显发热。针对启动慢我做了代码分割把统计页的代码改成按需加载不在一开始就全部初始化。这个改动让启动时间缩短到了1秒以内。针对卡顿我把页面切换动画从默认的滑动改成了淡入淡出减少了渲染压力。针对发热我检查了定时器的刷新频率把UI刷新从每秒一次改成了每两秒一次时间戳校正保证了计时精度不受影响同时把不必要的传感器监听全部关掉。优化前后的对比指标优化前优化后启动时间2.3秒0.8秒页面切换帧率约24fps约45fps半小时耗电约8%约3%经验之谈手表端开发性能优化的优先级是减少渲染 减少计算 减少IO。任何能合并的UI刷新都合并任何能缓存的中间结果都缓存本地存储的读写频率要严格控制。4. 常见问题排查与避坑指南4.1 开发过程中遇到的典型报错问题一页面白屏控制台无报错。这种情况大概率是.ux文件里的组件引用路径写错了。Zepp OS对路径大小写敏感./components/Timer和./components/timer会被当成两个不同的路径。排查方法是逐个检查import语句确保路径和实际文件名完全一致。问题二定时器在后台不执行。这是预期行为Zepp OS为了省电应用切到后台后定时器会被挂起。解决办法就是前面说的用时间戳校正不要依赖定时器的连续性。如果你的功能确实需要后台运行可以研究一下官方的后台任务API但要注意后台任务的执行频率有限制。问题三本地存储写入失败。检查一下存储的键名是否包含特殊字符以及存储的值是否超过了大小限制。Zepp OS的本地存储单个键值对建议不要超过1KB总容量也有限。如果数据量大考虑分片存储或者只存必要的摘要数据。问题四真机上字体显示不全。手表屏幕的像素密度和模拟器不一样模拟器上看着刚好的字号真机上可能被裁切。解决办法是字号用相对单位而不是绝对像素或者针对不同设备做适配。GTR4的分辨率是466x466我最终用的字号是32px大数字和20px正文实测显示效果最好。4.2 AI coding辅助开发的正确姿势用AI辅助写代码最大的陷阱是盲目信任。AI生成的代码在语法上通常没问题但在API的具体用法上经常出错——它可能会用一些看起来合理但实际不存在的API或者参数顺序搞反。我的做法是AI生成的每一段涉及平台API的代码都要对照官方文档验证一遍。另一个心得是给AI的描述越具体产出质量越高。比如不要说帮我写一个计时器页面而要说帮我写一个Zepp OS的计时器页面使用setInterval每秒刷新页面onShow时启动定时器onHide时清除计时基于时间戳校正。后者生成的代码基本可以直接用前者生成的代码需要大量修改。还有一个技巧把报错信息完整地贴给AI包括堆栈信息。AI对错误信息的理解能力很强往往能直接定位到问题所在。但要注意贴报错信息之前先把里面可能包含的敏感路径或者个人信息删掉。4.3 常见问题速查表问题现象可能原因排查方向解决方案应用启动崩溃入口文件语法错误检查app.js和app.json用模拟器逐步调试定位到具体行界面元素错位布局用了绝对定位检查.ux文件的样式改用flex布局用百分比而非固定像素计时不准依赖setInterval累加检查计时逻辑改用时间戳校正方案数据丢失未做持久化检查存储读写时机在onHide和计时完成时写入存储耗电过快定时器频率过高检查setInterval间隔降低刷新频率关闭无用传感器真机与模拟器表现不一致设备差异对比分辨率和性能真机实测针对性适配4.4 几个让我少走弯路的小技巧第一个技巧开发阶段把日志打全一点。Zepp OS的日志可以在CLI终端里看到用console.log输出关键状态排查问题时能省很多时间。但记得发布前把日志清理掉过多的日志输出会影响性能。第二个技巧善用模拟器的慢速模式。模拟器可以模拟低性能设备在这个模式下跑通了真机上基本不会卡。我习惯在慢速模式下做功能测试在正常模式下做体验测试。第三个技巧版本管理要趁早。哪怕是一个人开发的小项目也建议用Git管理起来。每次改完一个功能就提交一次出问题的时候可以快速回滚。AI生成的代码尤其要这样因为有时候AI的修改会引入一些隐蔽的bug有版本记录才能快速定位。第四个技巧真机测试要覆盖完整的使用场景。不要只测打开应用-开始计时-结束计时这个主流程还要测计时中途切到其他应用再切回来、计时中途息屏再亮屏、连续使用一小时后这些边界情况。很多bug只有在这些场景下才会暴露。5. 项目复盘与后续扩展思路5.1 这个项目教会我的几件事做完这个项目我最大的感受是AI coding确实能大幅提升开发效率但它改变的是写代码这个环节的速度而不是想清楚要做什么和验证做得对不对这两个环节。整个项目里我花在理清需求和调试上的时间其实比写代码的时间还多。AI帮我省下的是查文档、写样板代码的时间这部分大概占了总工作量的四成左右。另一个感受是手表端开发和手机端、网页端开发的思维差异很大。手机端可以容忍一定的性能浪费手表端不行手机端可以堆功能手表端必须做减法。这种约束反而让设计变得更清晰——当你只有三个功能可以做的时候你会认真思考哪三个才是真正重要的。5.2 后续可以怎么扩展这个App目前只实现了最核心的功能后续有几个方向可以继续做。一是增加白噪音功能在专注时播放一些环境音帮助进入状态这个需要用到音频播放API。二是增加任务模板把常用的任务组合保存下来一键开始一整组番茄。三是做手机端的配套应用把手表上的数据同步到手机在手机上做更详细的分析和回顾。不过这些扩展都要遵循一个原则不能影响核心体验。手表应用最怕的就是功能越加越多最后变得又慢又难用。每加一个功能都要问自己这个功能值得用户多花三秒钟吗如果答案是否定的那就不加。5.3 给想尝试类似项目的人的建议如果你也想给自己的手表写一个应用我的建议是从最小的功能开始。不要一上来就想做一个全能助手先做一个能用的计时器跑通了再慢慢加东西。开发过程中遇到问题先查官方文档文档解决不了的再问AIAI给的方案一定要自己验证。还有一点很重要不要追求完美。我的这个App界面很朴素没有动画、没有花哨的配色但它稳定、省电、该有的功能都有。对于手表应用来说稳定和省电比好看重要得多。先把核心功能做扎实美化的事情可以后面再说。最后享受这个过程。给自己的设备写一个真正用得上的工具那种这东西是我做的的满足感是直接用现成应用体会不到的。而且做完之后你会发现你对这块手表的理解比之前深了不止一个层次。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑