难度:⭐⭐⭐ | 前置知识: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

码道 Agent 会话现场:kefocus-harmony 仓库代码索引(5 个文件 4 个文件夹已加载)与生成计时内核代码,右上角含 51 行者 AtomGit 账号

一、项目背景:写作现场的专注管理痛点

先交代选题来源。作为一名技术博主,我写一篇专栏文章的真实流程是:资料收集 2 个番茄、初稿 3 个番茄、配图 1 个番茄——任务天然要拆批,节奏天然要管理。但市面上的番茄钟应用有两个让我不满意的地方:

  1. 锁屏就停。写作时手机锁屏放一边,回来看一眼,计时已经不对了——后台被系统冻结,naive 的 setInterval 方案在这种场景下是失效的;
  2. 数据要上云。专注数据是纯个人数据,为了个统计功能注册账号、同步云端,我不接受。

所以第 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 查表,不用魔法字符串。

ArkTS 合规清单投喂后的会话现场:Agent 按清单生成 3 个文件(TimerEngine、TimerStateMachine、TimerPhase 状态枚举),右上角含 51 行者 AtomGit 账号

七天里程碑沿用第 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 编译器打回的环节,下一章展开。

hypium 测试全绿现场:D2 状态机与恢复,4 个文件生成,编译检查通过,12 个用例全部通过

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

全屏计时环主界面:番茄钟倒计时(25:00 专注中,自由专注,专注任务 +4,开始按钮),浅色模式

4.1 计时环与三态时基

主界面为 Canvas 自绘计时环:外环进度弧(当前阶段进度),环中心剩余时间等宽大字,剩余不足 1 分钟变黄、超时未处理变红。手动把系统时间往前拨 10 分钟,下一次 tick 界面弹出「检测到系统时间被调整」提示——DriftGuard 的跳变检测在工作。

锁屏计时是专注应用的生命线:开始一个 25 分钟番茄 → 锁屏 → 解锁,专注时长持续正确。深浅色模式下计时环语义色一致(下图为深色模式同一界面):

深色模式计时环:语义色变量切换后的同一界面(专注中,专注任务 0/1,剩余时间大字 + 暂停/放弃按钮)

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

短休阶段:番茄钟短休倒计时(04:56 短休,专注任务 1/4,跳过休息按钮),深色模式
在这里插入图片描述

4.2 杀进程恢复

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

杀进程恢复演示:运行中杀进程 → 重开 → 计时仍在正确位置(深色模式,专注任务 0/4,剩余 20:27)

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

专注中阶段:番茄钟专注倒计时(00:52,专注任务 0/1,暂停/放弃按钮),深色模式

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

暂停状态下杀进程:阶段完成弹窗(专注中已完成,休完短休继续/进入下一阶段/重新开始选项)

4.3 任务批处理与节律统计

建一个「写第 3 期文章」批次拆 3 个番茄,每完成一个 FOCUS 批次进度 +1,三个全部完成批次自动标记 DONE:

批次推进四连拍:00:00 开始(浅色)→ 24:52 专注中·专注任务 0/1(深色)→ 25:00 自由专注·专注任务 4(浅色)→ 00:07 专注中·暂停/完成(深色),深浅色模式交替

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

批次列表页:番茄钟主界面批次列表视图(30:00 专注中,深色模式)

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

阶段完成弹窗:番茄钟阶段完成提示(浅色模式,专注中已完成,批次完成享受长休)

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

节律统计页:最近 7 天每日专注(09-23 138m、09-24 256m),完成率 50%(已完成 6 / 已放弃 6),本月总时长 6 小时 34 分钟、会话数 6、活跃天 2,时段热力图(最近 7 天 × 24 小时)标注演示数据

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

节律统计页:连续专注 0 天、本周总时长 6 小时 34 分钟、完成率 50%,最近 7 天专注趋势 + 每日专注柱状图(09-23 138m、09-24 256m)+ 完成率详情 + 阶段分布

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

节律任务 Tab:番茄钟主界面任务视图(29:55 专注中,浅色模式)

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

折叠屏展开态双栏布局:节律统计页(连续专注 0 天、本周总时长 6 小时 34 分钟、完成率 50%)+ 最近 7 天每日专注柱状图 + 完成率详情 + 阶段分布

五、踩坑记录:AI 写对了九成,剩下一成靠人

如实记录开发过程中真实遇到的问题。

1. AI 的 TS 习惯代码,被 ArkTS 编译器逐条打回

现象:状态机话术投喂后,AI 一次生成了完整实现,hvigorw 编译却报出十余个错误——any 类型、对象字面量动态加属性、可选链后的隐式宽类型,全是 ArkTS 规范不允许的 TS 习惯写法。

根因:AI 的语料以标准 TS 为主,ArkTS 的严格子集约束(禁 any、禁 delete、禁动态属性)不在它的默认习惯里。话术里只写了「ArkTS 语法」,没有写成逐条可检查的规则。

解决:把编译器报错逐条喂回 + 固化「ArkTS 合规清单」作为每次投喂的固定前缀。

效果:第二轮生成一次通过编译。此后全部话术带上清单,ArkTS 相关返工再未出现——从十余个编译错误降到 0。

教训:平台特有约束必须翻译成逐条可验收的规则清单,写进投喂话术——「用什么语言写」这种一句话约束,AI 是记不住的。

坑一现场:D4 批处理生成 4 个文件(TaskBatchRepository、HistoryRepository、BatchService、HistoryService),编译检查通过,16 个用例全部通过

2. 长时任务后台模式声明不匹配,锁屏即冻结

现象:长时任务申请成功、通知栏也正常,但真机锁屏 2 分钟回来,计时停在锁屏时刻——长时任务形同虚设。

根因:module.json5 里 backgroundModes 的声明与代码申请的 taskKeeping 模式不匹配(AI 凭记忆生成的权限名拼写与当前 API 版本不一致),系统按未声明后台模式处理,应用退后台即被冻结。

解决:对照官方文档「申请长时任务」核实当前 API 版本的准确权限名与 backgroundModes 拼写,逐项修正。终检话术中追加了「权限名逐条对照官方文档核实,不要猜」的硬性约束。

效果:修正后真机锁屏 25 分钟实测计时持续、误差 0 秒(坑三所述真机口径),长时任务恢复应有作用。

教训:系统能力的声明类配置(权限、后台模式)是 AI 最容易「凭旧版本记忆」出错的地方,这类内容必须以官方文档为准人工复核,不能信任生成结果。

坑二现场:D4 批处理与历史 4 文件生成,编译检查通过,16 个用例全部通过(module.json5 权限声明修正后)

3. 模拟器与真机的时钟行为差异

现象:模拟器上「锁屏 25 分钟误差 0 秒」的实测非常漂亮,换真机复测出现秒级偏差。

根因:模拟器与宿主机共享时钟源,休眠漂移被掩盖;真机的低功耗状态存在真实的时间源切换误差。模拟器数据不能代表真机口径。

解决:锁屏误差实测数据一律以真机口径为准(记录机型与系统版本),模拟器数据仅作开发期回归用。文章与 README 中的性能数据全部标注实测环境。

效果:真机口径下重测并修正数据标注后,文章中不再出现无环境标注的裸数据,后续口径争议为 0。

教训:性能口径必须在目标设备上测——「模拟器通过」不是「真机通过」,数据的环境标注是可信度的一部分。

坑三现场:D5 统计与一多适配,4 个文件生成(StatsEngine、StatsService、StatsViewModel、BreakpointUtils),20 个用例全部通过

5.4 小结

三个坑的共同点与第 1 期一致:AI 的失误都发生在「话术没约束到的地方」——平台特有约束、版本敏感配置、真实环境口径。架构决策与验收标准由人写死,AI 在约束内执行,这个分工在鸿蒙原生开发里同样成立。

Agent 测试会话现场(kefocus-harmony 仓库,测试要求投喂:RUNNING 快照 + MockClock 前进 10 分钟、PAUSED 快照时钟前进、快照字段损坏 recover 返回结构化错误、24 小时过期判定):

Agent 测试会话现场:kefocus-harmony 仓库测试要求投喂(RUNNING/PAUSED 快照 + MockClock 验证、快照损坏 recover 错误处理、24 小时过期判定)

质量收口的实测数据(hypium 本地实测):

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

hypium 覆盖率与用例总数汇总:D5 统计与一多适配收口完成,20 个用例全部通过,编译检查通过

六、提效数据:AI 辅助开发到底快了多少

如实给出本次开发的提效记录(基于开发日志的实际耗时统计,为个人单项目样本,仅供参考)。

开发阶段纯手写预估AI 辅助实际提效来源
ArkTS 工程骨架 + 分层规范约 1 天约 1.5 小时脚手架类工作收益最大
时基校正 + 状态机 + 单测约 2 天约 4 小时纯函数 + 边界穷举是 AI 强项
主界面计时环 + 长时任务约 2 天约 5 小时AI 写 core,人工调 ArkUI 视图
批处理 + 历史库 + 演示数据约 1 天约 3 小时CRUD 与建表模板化
统计热力图 + 一多适配收口约 1.5 天约 4 小时断点布局由 AI 生成,人工走查

AtomGit 工作台:kefocus-harmony 项目会话记录列表(51 行者 AtomGit 账号)

两点如实说明:一是「纯手写预估」基于以往同类项目经验估算,存在主观误差;二是 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 代码智能体的几点优化建议(如实反馈,供官方参考):

  1. ArkTS 语料增强:希望智能体对 ArkTS 严格子集(禁 any、禁动态属性)有内置感知,生成前主动规避 TS 习惯写法,减少编译器返工;
  2. 平台 API 版本对齐:权限名、backgroundModes 这类版本敏感配置,建议 Agent 主动声明「依据的 API 版本」并提示与最新文档核对;
  3. 项目级约定持久化(与第 1 期建议相同,依然期待):合规清单这类项目级约束若能持久化,就不必每条话术重复投喂。

8.3 写在最后

三种端形态(Web 全栈 / 微信小程序 / 鸿蒙原生)、三套技术栈、同一套方法:架构决策人做、约束写进话术、每块验收兜底。鸿蒙这一期额外验证了方法的可移植性——换语言、换平台模型,工作流不变。

下一期(第 4 期,10-05 ~ 10-11)将是 Rust + Tauri 桌面应用「仓衡 · Git 仓库健康度体检台」,借用检查器会第一次登场。如果你也在参加本期华为云码道 AI 编程挑战赛,欢迎在评论区交流。


说明:因 AtomGit 的码道额度用尽,本文部分功能使用码道客户端进行开发,其余功能通过码道 Web 端完成。

觉得有用就点个赞,有疑问或不同看法欢迎评论区交流。

专栏导航:

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐