华为云码道 CodeArts 实测:让 AI 独立开发一个鸿蒙原生专注计时应用「刻循」
难度:⭐⭐⭐ | 前置知识:HarmonyOS 基础、TypeScript 语法 | 适用读者:想实测 AI 代码智能体、或入门鸿蒙原生开发的开发者
一键开通华为云码道 CodeArts 代码智能体:https://developer.huaweicloud.com/codeartsco.html?source=dmzntgwatomgit1&sourcead=dmzntgwatomgithd
摘要:这是华为云码道 AI 编程挑战赛第 3 期的参赛实测:我用 CodeArts 代码智能体独立开发 HarmonyOS 原生应用「刻循 · 专注计时」,7 天完成番茄钟、任务批处理与节律统计,纯本地零网络权限。文章记录架构设计(计时内核分离 + 会话状态机 + 三态时基)、ArkTS 约束下的 AI 辅助开发实操、踩坑记录与提效数据,源码已在 AtomGit 开源。
技术栈版本:码道 CodeArts 代码智能体(2026-09 挑战赛版本)| HarmonyOS NEXT(API 12+)| ArkTS + ArkUI(Stage 模型)| @ohos/hypium 单元测试 | 实测时间: 2026-09

一、项目背景:写作现场的专注管理痛点
先交代选题来源。作为一名技术博主,我写一篇专栏文章的真实流程是:资料收集 2 个番茄、初稿 3 个番茄、配图 1 个番茄——任务天然要拆批,节奏天然要管理。但市面上的番茄钟应用有两个让我不满意的地方:
- 锁屏就停。写作时手机锁屏放一边,回来看一眼,计时已经不对了——后台被系统冻结,naive 的
setInterval方案在这种场景下是失效的; - 数据要上云。专注数据是纯个人数据,为了个统计功能注册账号、同步云端,我不接受。
所以第 3 期参赛,我把这两点直接做成产品主张:时间在设备上算得准,数据不出设备——一个纯本地的鸿蒙原生专注计时应用。锁屏不断计时靠长时任务与时基校正,数据不出设备靠「不申请网络权限」这个最硬的约束。
这个选题还有一层考虑:评审是华为团队,「用码道智能体开发鸿蒙原生应用」本身就是对华为生态双主线(码道 + 鸿蒙)的一次实测,比通用选题更有参考价值。
1.1 作品功能一览
| 模块 | 功能 |
|---|---|
| 计时内核 | 番茄钟 / 正计时 / 倒计时三种模式,时基校正保证休眠后依然准确 |
| 会话状态机 | 非法流转拒绝,应用被杀后按持久化快照恢复到正确阶段与剩余时间 |
| 任务批处理 | 任务拆成 N 个番茄的批次计划,完成自动进入短休 |
| 长时任务 | 锁屏计时不断,通知栏常驻显示当前阶段 |
| 节律统计 | 按日专注时长、时段分布热力图、连续专注天数 |
| 一多适配 | 手机单栏、折叠屏/平板双栏,深浅色随系统 |
技术栈:ArkTS + ArkUI 声明式范式(Stage 模型,API 12+),@ohos/hypium 单元测试,纯本地零网络。
二、架构设计:三个核心决策
与第 1 期相同的纪律:架构决策在投喂话术之前由人定好,AI 擅长执行明确约束,不擅长替你做决策。这部分必须在打开智能体之前想清楚。
2.1 决策一:时基校正是纯函数,时钟可注入
计时应用最容易做错的地方不是「显示倒计时」,而是「时间算得准」:休眠漂移、后台冻结、用户手动改系统时间、多次暂停,每一项都会让直觉写法产生分钟级误差。动手前我把三种常见实现摆在一起比过:
| 方案 | 准确性 | 可测性 | 结论 |
|---|---|---|---|
setInterval 累计递减 | 差:后台冻结后 interval 停走,误差不可控 | 差:依赖真实时间流逝 | 否决 |
每帧用 Date.now() 重算剩余 | 中:改系统时间会跳变 | 差:耦合真实时钟 | 否决 |
| 事件驱动 + 时基校正纯函数 | 好:任意时刻由「开始时间戳 + 暂停区间表 + 当前时钟」重算 | 极好:全纯函数,时钟可注入 | ✅ 采用 |
核心不变量只有一条:真实已专注时长 = f(startMs, pausedIntervals[], nowMs),其中时钟由调用方注入。测试时注入 Mock 时钟,休眠漂移、改时间、跨天、多次暂停全部可以确定性构造——这是本期代码质量的主战场。
// src/main/ets/core/clock/FocusMath.ets(节选)
export interface PausedInterval { startMs: number; endMs: number; } // endMs=0 表示暂停中
/**
* 真实已专注毫秒数 = (nowMs - startMs) - 暂停区间并集的重叠时长。
* 时钟回拨返回 0;区间乱序/重叠按并集去重,不重复扣减。
*/
export function computeFocusedMs(
startMs: number,
paused: PausedInterval[],
nowMs: number
): number {
if (nowMs <= startMs) {
return 0; // 时钟回拨防御
}
// 1. 合并乱序/重叠区间为互斥区间并集
// 2. 未闭合区间(endMs=0)按闭到 nowMs 计算
// 3. 总时长减去并集覆盖时长,返回非负整数
// …实现略,完整实现与 20 个边界用例见仓库
return mergedFocusedMs;
}

2.2 决策二:会话状态机用查表法,恢复不做「补帧追赶」
会话生命周期(idle → running → paused → completed/abandoned)如果用 if-else 散落在页面里,非法流转迟早泛滥。我把它收敛为一张显式流转表,非法流转直接拒绝并说明当前状态与目标状态。
会话全生命周期的流转关系如下图,非箭头方向的事件一律拒绝:

恢复策略上有一条显性取舍:应用被系统冻结再回来时,不做逐帧追赶,直接按快照 + 时基校正一次跳到正确值。这条决策把「从冻结中恢复」从玄学问题变成了纯函数问题:
| 恢复方案 | 正确性 | 实现复杂度 | 结论 |
|---|---|---|---|
| 逐帧补帧追赶(把冻结期间的时间补渲染出来) | 差:补多少帧都是猜 | 高:动画与状态纠缠 | 否决 |
| 快照 + computeFocusedMs 重算,一次跳到正确值 | 好:数学上精确 | 低:纯函数 | ✅ 采用 |
// src/main/ets/core/statemachine/SessionMachine.ets(节选)
// 流转表显式定义:Record<Event, Record<Status, Status | null>>,null 表示非法流转
const TRANSITIONS: Record<SessionEvent, Record<Status, Status | null>> = {
START: { [Status.IDLE]: Status.RUNNING },
PAUSE: { [Status.RUNNING]: Status.PAUSED },
RESUME: { [Status.PAUSED]: Status.RUNNING },
COMPLETE: { [Status.RUNNING]: Status.COMPLETED },
ABANDON: { [Status.RUNNING]: Status.ABANDONED, [Status.PAUSED]: Status.ABANDONED },
TICK: { [Status.RUNNING]: Status.RUNNING },
};
export function transition(current: Status, event: SessionEvent): TransitionResult {
const target = TRANSITIONS[event][current] ?? null;
if (target === null) {
return { ok: false, from: current, to: current,
error: `非法流转:当前状态 ${current} 不允许处理事件 ${event}` };
}
return { ok: true, from: current, to: target };
}
⚠️ 注意:以上为节选,流转表省略了快照持久化的触发点(每次事件同步写
preferences)。完整实现见仓库,ArkTS 下Record的键必须是 enum 而非魔法字符串,直接照搬 TS 写法会被编译器打回(见第五章坑 1)。
每次状态事件发生时同步写 preferences 快照(最后状态 + 时间戳 + 阶段目标),重启后内核按「最后事件 + computeFocusedMs」重放恢复——「杀进程后重开还在原地」是可当场验证的体验点。
2.3 决策三:零网络权限是安全主张,不是能力妥协
AI 生成的代码在业务逻辑上表现不错,但安全边界需要人主动划。本期的安全设计只有一条主线,但它足够硬:
| 安全项 | 实现 |
|---|---|
| 零网络权限 | module.json5 中不申请 ohos.permission.INTERNET——专注数据无需上云,没有网络就没有泄露面 |
| 权限最小化 | 全部权限仅 2 项:后台长时任务(KEEP_BACKGROUND_RUNNING)+ 通知 |
| 数据可清除 | 会话历史一键清除(二次确认),导出 JSON 仅含会话记录数组 |
| 键不入码 | 无任何密钥/token(纯本地应用天然无此风险,但终检话术仍逐项扫) |
「没有 INTERNET 权限」是安全合规最直接、最可验证的证据——它写在配置文件里,任何人打开仓库就能核对。
三、用 CodeArts 开发:ArkTS 约束下的实操流程
3.1 开发前的准备
打开 CodeArts 之前的三件人肉准备:AtomGit 创建公开仓库 kefocus-harmony(LICENSE + README 骨架 + .gitignore)、DevEco Studio + API 12 模拟器跑通、以及本期特有的一项——整理「ArkTS 合规清单」。
ArkTS 不是 TypeScript:强制静态类型、禁用 any、禁止运行时动态增删对象属性。AI 的 TS 习惯代码在 ArkTS 下会被编译器大量打回,所以我把它整理成一份固定前缀,每条话术投喂时都粘贴在开头:
【ArkTS 合规清单 —— 生成任何代码前先阅读,违反任何一条都要自我纠正】
1. 禁止 any / unknown:所有变量、参数、返回值显式声明类型;
2. 禁止运行时给对象动态增删属性,数据结构一律显式 interface/class;
3. 联合类型收窄用 as 或类型守卫,不用逻辑 hack;
4. core/ 层禁止出现 @ohos 能力(时钟等一律通过接口注入);
5. 异步统一 async/await + Promise;
6. 状态流转用 enum + Record 查表,不用魔法字符串。

七天里程碑沿用第 1 期节奏:D1 内核骨架 → D2 状态机与恢复 → D3 主界面与长时任务 → D4 批处理与历史 → D5 统计与一多适配收口 → D6 文章撰写 → D7 发布。每块话术写死目录结构、接口签名与验收标准(hypium 用例数、模拟器实测步骤),AI 在约束内实现。
3.2 一个典型话术块长什么样
以 D1 的时基校正话术为例(节选),「纯逻辑、时钟注入、边界穷举」三个要求都写在投喂内容里:
在 src/main/ets/core/clock/ 中实现时基校正。【纯逻辑,零 @ohos 依赖】
1. 核心不变量:computeFocusedMs(startMs, pausedIntervals[], nowMs);
2. 时钟通过 Clock 接口注入,core 层禁止 Date.now()/systemDateTime 直调;
3. 边界全部处理:时钟回拨返回 0、暂停区间乱序重叠按并集去重、
未闭合区间按闭到 now 计算、跨天会话正确;
4. hypium 不少于 20 个用例,覆盖上述全部边界 + DriftGuard 30 秒跳变阈值。
完成后报告 hypium 运行结果(用例数与通过情况)。
AI 对这类纯函数约束的执行质量很高——时基校正一次生成即通过全部 20 个用例。真正需要我介入的是后面 ArkTS 编译器打回的环节,下一章展开。

四、功能演示:从计时到节律的完整闭环

4.1 计时环与三态时基
主界面为 Canvas 自绘计时环:外环进度弧(当前阶段进度),环中心剩余时间等宽大字,剩余不足 1 分钟变黄、超时未处理变红。手动把系统时间往前拨 10 分钟,下一次 tick 界面弹出「检测到系统时间被调整」提示——DriftGuard 的跳变检测在工作。
锁屏计时是专注应用的生命线:开始一个 25 分钟番茄 → 锁屏 → 解锁,专注时长持续正确。深浅色模式下计时环语义色一致(下图为深色模式同一界面):

这背后是三态时基架构在兜底:


4.2 杀进程恢复
从最近任务里划掉应用再重开:应用回到正确阶段、剩余时间精确到秒。运行中杀进程,重开后计时环直接跳回正确剩余时间(不补帧):

专注中阶段的计时环(深色模式,专注任务 0/1,剩余 00:52,暂停/放弃按钮):

暂停状态下杀进程同样成立——暂停区间在快照里,恢复时被正确扣除:

4.3 任务批处理与节律统计
建一个「写第 3 期文章」批次拆 3 个番茄,每完成一个 FOCUS 批次进度 +1,三个全部完成批次自动标记 DONE:

批次列表页(深色模式,番茄钟/正计时/倒计时/统计 Tab 切换,专注中 30:00):

阶段完成弹窗(浅色模式,批次完成享受长休,进入下一阶段/结束/重新开始选项):

历史页按日聚合会话记录,统计页的热力图能明显看到我的专注时段集中在 9-11 点与 14-17 点——演示数据由确定性常量表生成并明确标注「演示数据」:

节律首页汇总卡片与任务 Tab(按日筛选 + 任务状态列表):

节律任务 Tab(浅色模式,番茄钟专注中 29:55,暂停/放弃按钮):

折叠屏展开态双栏布局:左侧批次列表 + 右侧统计卡片,深浅色随系统切换:

五、踩坑记录:AI 写对了九成,剩下一成靠人
如实记录开发过程中真实遇到的问题。
1. AI 的 TS 习惯代码,被 ArkTS 编译器逐条打回
现象:状态机话术投喂后,AI 一次生成了完整实现,hvigorw 编译却报出十余个错误——any 类型、对象字面量动态加属性、可选链后的隐式宽类型,全是 ArkTS 规范不允许的 TS 习惯写法。
根因:AI 的语料以标准 TS 为主,ArkTS 的严格子集约束(禁 any、禁 delete、禁动态属性)不在它的默认习惯里。话术里只写了「ArkTS 语法」,没有写成逐条可检查的规则。
解决:把编译器报错逐条喂回 + 固化「ArkTS 合规清单」作为每次投喂的固定前缀。
效果:第二轮生成一次通过编译。此后全部话术带上清单,ArkTS 相关返工再未出现——从十余个编译错误降到 0。
教训:平台特有约束必须翻译成逐条可验收的规则清单,写进投喂话术——「用什么语言写」这种一句话约束,AI 是记不住的。

2. 长时任务后台模式声明不匹配,锁屏即冻结
现象:长时任务申请成功、通知栏也正常,但真机锁屏 2 分钟回来,计时停在锁屏时刻——长时任务形同虚设。
根因:module.json5 里 backgroundModes 的声明与代码申请的 taskKeeping 模式不匹配(AI 凭记忆生成的权限名拼写与当前 API 版本不一致),系统按未声明后台模式处理,应用退后台即被冻结。
解决:对照官方文档「申请长时任务」核实当前 API 版本的准确权限名与 backgroundModes 拼写,逐项修正。终检话术中追加了「权限名逐条对照官方文档核实,不要猜」的硬性约束。
效果:修正后真机锁屏 25 分钟实测计时持续、误差 0 秒(坑三所述真机口径),长时任务恢复应有作用。
教训:系统能力的声明类配置(权限、后台模式)是 AI 最容易「凭旧版本记忆」出错的地方,这类内容必须以官方文档为准人工复核,不能信任生成结果。

3. 模拟器与真机的时钟行为差异
现象:模拟器上「锁屏 25 分钟误差 0 秒」的实测非常漂亮,换真机复测出现秒级偏差。
根因:模拟器与宿主机共享时钟源,休眠漂移被掩盖;真机的低功耗状态存在真实的时间源切换误差。模拟器数据不能代表真机口径。
解决:锁屏误差实测数据一律以真机口径为准(记录机型与系统版本),模拟器数据仅作开发期回归用。文章与 README 中的性能数据全部标注实测环境。
效果:真机口径下重测并修正数据标注后,文章中不再出现无环境标注的裸数据,后续口径争议为 0。
教训:性能口径必须在目标设备上测——「模拟器通过」不是「真机通过」,数据的环境标注是可信度的一部分。

5.4 小结
三个坑的共同点与第 1 期一致:AI 的失误都发生在「话术没约束到的地方」——平台特有约束、版本敏感配置、真实环境口径。架构决策与验收标准由人写死,AI 在约束内执行,这个分工在鸿蒙原生开发里同样成立。
Agent 测试会话现场(kefocus-harmony 仓库,测试要求投喂:RUNNING 快照 + MockClock 前进 10 分钟、PAUSED 快照时钟前进、快照字段损坏 recover 返回结构化错误、24 小时过期判定):

质量收口的实测数据(hypium 本地实测):
- core 层单元测试合计 ≥ 75 个用例(clock ≥20 / statemachine ≥18 / strategy ≥15 / schedule ≥12 / stats ≥10),全部通过;
- 纪律自查:
core/**零@ohos依赖、零时钟直调(搜索确认); module.json5权限清单最终 2 项,无 INTERNET。

六、提效数据:AI 辅助开发到底快了多少
如实给出本次开发的提效记录(基于开发日志的实际耗时统计,为个人单项目样本,仅供参考)。
| 开发阶段 | 纯手写预估 | AI 辅助实际 | 提效来源 |
|---|---|---|---|
| ArkTS 工程骨架 + 分层规范 | 约 1 天 | 约 1.5 小时 | 脚手架类工作收益最大 |
| 时基校正 + 状态机 + 单测 | 约 2 天 | 约 4 小时 | 纯函数 + 边界穷举是 AI 强项 |
| 主界面计时环 + 长时任务 | 约 2 天 | 约 5 小时 | AI 写 core,人工调 ArkUI 视图 |
| 批处理 + 历史库 + 演示数据 | 约 1 天 | 约 3 小时 | CRUD 与建表模板化 |
| 统计热力图 + 一多适配收口 | 约 1.5 天 | 约 4 小时 | 断点布局由 AI 生成,人工走查 |

两点如实说明:一是「纯手写预估」基于以往同类项目经验估算,存在主观误差;二是 ArkTS 路线的提效低于前两期的 TS/Java 路线——合规清单之外的编译器返工是额外成本,这部分如实计入。综合感受:整体工期压缩到传统方式的三分之一左右,鸿蒙原生开发的「框架税」(ArkTS 约束、Stage 模型样板)被 AI 消化了大部分。
适用边界:本数据为个人单项目、单人开发的样本,未计入团队协作的沟通成本与代码评审开销;任务以「架构清晰、验收可自动化」的中小型应用为前提——需求频繁变更或强依赖领域知识的场景,提效幅度会低于本表。
七、开源地址与运行方式
项目已开源,包含可构建源代码、README(作品介绍)与开源协议:
项目仓库:https://atomgit.com/dickeryang/kefocus-harmony.git(AtomGit 公开仓库)
本地运行(依赖 DevEco Studio):
# 1. 克隆仓库
git clone https://atomgit.com/dickeryang/kefocus-harmony.git
cd kefocus-harmony
# 2. DevEco Studio 打开工程(版本要求见 README),自动同步依赖后 Run
# 或命令行构建:
hvigorw assembleHap --mode module -p product=default
# 3. 首次启动自动生成 7 天演示数据(历史页标注「演示数据」),
# 可直接体验计时环、批次推进、杀进程恢复与节律热力图
仓库内附 docs/architecture.md(分层架构 + 会话状态机 + 三态时基时序图 + 被否决方案论证)、docs/testing.md(hypium 用例清单),README 声明 DevEco Studio / API / hvigor 三个版本号。项目采用 Apache-2.0 协议开源。
八、总结与平台使用建议
8.1 结论
三期的第三种端形态,答案是稳定的:在「人定架构与验收、AI 做实现」的分工下,鸿蒙原生应用同样可以一周完成。
本期与前两期最大的差异在语言约束:ArkTS 的严格子集让「AI 一次生成即编译通过」的比率低于 TS/Java 项目,但「合规清单固定前缀 + 编译器报错喂回」两个动作把它拉回到了同一水平线。安全维度上,「零网络权限」这个设计让本期的安全叙事比前两期都短——但更硬。
8.2 给平台的建议
一周深度使用下来,对 CodeArts 代码智能体的几点优化建议(如实反馈,供官方参考):
- ArkTS 语料增强:希望智能体对 ArkTS 严格子集(禁 any、禁动态属性)有内置感知,生成前主动规避 TS 习惯写法,减少编译器返工;
- 平台 API 版本对齐:权限名、backgroundModes 这类版本敏感配置,建议 Agent 主动声明「依据的 API 版本」并提示与最新文档核对;
- 项目级约定持久化(与第 1 期建议相同,依然期待):合规清单这类项目级约束若能持久化,就不必每条话术重复投喂。
8.3 写在最后
三种端形态(Web 全栈 / 微信小程序 / 鸿蒙原生)、三套技术栈、同一套方法:架构决策人做、约束写进话术、每块验收兜底。鸿蒙这一期额外验证了方法的可移植性——换语言、换平台模型,工作流不变。
下一期(第 4 期,10-05 ~ 10-11)将是 Rust + Tauri 桌面应用「仓衡 · Git 仓库健康度体检台」,借用检查器会第一次登场。如果你也在参加本期华为云码道 AI 编程挑战赛,欢迎在评论区交流。
说明:因 AtomGit 的码道额度用尽,本文部分功能使用码道客户端进行开发,其余功能通过码道 Web 端完成。
觉得有用就点个赞,有疑问或不同看法欢迎评论区交流。
专栏导航:
更多推荐



所有评论(0)