鸿蒙ArkTS零基础新手与华为云码道CodeArts的碰撞:从一句“帮我生成登录页“到完整工程落地的实操对比
一键开通华为云码道 CodeArts 代码智能体:https://developer.huaweicloud.com/codeartsco.html?source=dmzntgwatomgit1&sourcead=dmzntgwatomgithd
一、背景:为什么想起搞鸿蒙
没学过 ArkTS,也没装过 DevEco Studio,能不能直接搞出一个能跑的鸿蒙工程?本文记录了一次用华为云码道 CodeArts 从零生成鸿蒙登录 Demo 的完整实操,并与传统新手手搓流程做了逐步对比。
事情的起因很简单。最近鸿蒙 NEXT 炒得火热,纯血鸿蒙、去安卓化、ArkTS 声明式 UI……各种概念满天飞。作为一个常年写 Flutter/前端的开发者,我对鸿蒙生态一直有种"想碰但没空学"的状态——知道 ArkTS 是 TypeScript 超集,知道 Stage 模型是新架构,但从来没有真的坐下来写过一行 .ets 代码。
刚好刷到一个华为云码道(CodeArts)的演示,里面用一句话生成了完整的鸿蒙工程。我当时的第一反应是:真的假的?连 ArkTS 语法都不懂的人,也能直接生成能用的工程?
于是就有了这篇文章。我用一个最经典的需求——登录页面,分别从"新手手搓"和"AI 生成"两条路径走了一遍,记录下两种方式在每一步上的差异。
不过在正式开始之前,有必要先把鸿蒙开发中几个容易混淆的概念理一理,不然后面看到 CodeArts生成的代码会觉得莫名其妙。

二、前置知识:鸿蒙开发那些绕不开的概念
2.1 ArkTS 和 ArkUI 的关系
很多人一开始搞不清楚 ArkTS 和 ArkUI 到底是什么关系。简单说:
- ArkTS 是语言——TypeScript 的扩展版,加了
@Component、@State、@Builder等装饰器语法,以及一些运行时限制(比如不能用any,强制类型检查)。 - ArkUI 是框架——提供声明式 UI 的组件和 API,类似 Flutter 的 Widget 体系或 SwiftUI 的 View 体系。你在
.ets文件里写的Column()、Text()、Button()这些都来自 ArkUI。
打个比方,ArkTS 之于 ArkUI,就像 TypeScript 之于 React——一个是语言,一个是框架。你在 ArkTS 里用 ArkUI 的组件来构建界面。
不过 ArkTS 并不是简单地给 TypeScript 加了几个装饰器那么简单。华为对 ArkTS 做了相当严格的运行时约束,最明显的就是禁止使用 any 类型。在标准 TypeScript 里,any 是逃逸类型检查的后门,开发者在不确定类型时可以随手写个 any 先跑起来再说。但 ArkTS 把这个后门堵死了——所有变量必须有明确类型,函数签名的参数和返回值也不能省略类型标注。这意味着 ArkTS 代码在编译期就能捕获大部分类型错误,代价是写起来比 TypeScript 更"啰嗦"。此外,ArkTS 还限制了一些动态特性,比如不允许通过 Object.keys() 动态遍历对象属性,不支持 any[] 类型的数组操作,对象字面量必须显式声明接口类型。这些限制看起来是"倒退",但华为的考量是:鸿蒙应用需要运行在资源受限的嵌入式设备上,编译期的严格类型检查能在运行前排除大量潜在错误,同时让 AOT 编译器有更多优化空间。从工程角度看,这其实是在用"开发时的便利性"换取"运行时的安全性和性能"。

另一个值得注意的语言特性是 ArkTS 的装饰器系统。@Component 不只是个语法糖——编译器在遇到这个装饰器时,会把 struct 转换成一个带响应式状态管理的组件类。当你修改 @State 变量的值时,ArkUI 框架内部会触发一轮"状态变更 → 虚拟 DOM diff → 实际 DOM 更新"的渲染流水线,整个过程是自动的,开发者不需要像 React 那样手动调用 setState 通知框架。但这也意味着 ArkTS 组件的更新粒度比 React 更细——React 的 setState 是批量处理的,而 ArkTS 的 @State 赋值是即时的,每次赋值都可能触发一次 UI 更新。如果在一个方法里连续修改多个 @State 变量,ArkUI 会在方法执行完后做一次合并渲染,这种"微任务级别的批量更新"和 Flutter 的 markNeedsBuild 机制非常相似。
2.2 Stage 模型 vs FA 模型
这是鸿蒙开发的另一个高频概念。鸿蒙应用有两种架构模型:
表 1:Stage 模型与 FA 模型对比
| 维度 | FA 模型(旧) | Stage 模型(新) |
|---|---|---|
| 全称 | Feature Ability 模型 | Stage 模型 |
| 推出时间 | 鸿蒙早期(API 6-8) | 鸿蒙 3.0+(API 9+) |
| 核心单元 | Ability(页面+逻辑耦合) | Ability(逻辑)+ UI 页面分离 |
| 配置文件 | config.json | module.json5 |
| UI 描述 | 部分 JS UI(兼容 Web 组件) | 纯 ArkUI 声明式 |
| 推荐状态 | 已废弃,不建议新项目使用 | 官方推荐,API 9+ 必选 |

简单理解:FA 模型把页面和逻辑混在一个 Ability 里,Stage 模型把它们拆开——Ability 管生命周期,页面管 UI 渲染。这和 Android 从 MVP 到 MVVM 的演进逻辑类似,都是往解耦的方向走。
新手如果跟着老教程走 FA 模型,后面迁移到 Stage 模型会发现文件名、配置格式、路由方式全都不一样,等于白学一遍。
从技术层面深入来看,Stage 模型的核心改动在于 AbilityContext 的引入。在 FA 模型中,Ability 既是 UI 承载者也是逻辑处理者,页面间的数据传递依赖 Intent 机制,和早期 Android 非常类似。Stage 模型把 Ability 拆成了两层:UIAbility 管生命周期(onCreate/onWindowStageCreate/onForeground/onBackground/onWindowStageDestroy/onDestroy),ArkUI 组件管 UI 渲染。两者之间通过 windowStage 桥接——UIAbility 在 onWindowStageCreate 回调中调用 windowStage.loadContent('pages/LoginPage') 加载 ArkUI 页面。这种分离带来的好处是:你可以在同一个 Ability 里动态切换多个页面,而不需要销毁重建整个 Ability 实例。比如登录成功后从 LoginPage 切到 Index 页面,Ability 生命周期不变,只是 windowStage 加载的内容变了。这种设计在多页面应用中能显著减少状态重建的开销。

另一个 Stage 模型的重要概念是 ExtensionAbility。不同于普通 UIAbility 面向用户交互,ExtensionAbility 是面向特定场景的后台能力组件,比如 FormExtensionAbility(服务卡片)、InputMethodExtensionAbility(输入法)、AccessibilityExtAbility(无障碍服务)等。它们没有 UI 界面,但能以独立组件的形式被系统调度。这种"按需加载、即插即用"的设计让鸿蒙应用的模块化粒度比 Android 更细——Android 的 Service 是全局的,而鸿蒙的 ExtensionAbility 是按场景拆分的,系统可以在不需要某项能力时直接卸载对应的 ExtensionAbility 进程,释放内存。
2.3 DevEco Studio 与构建工具链
DevEco Studio 是华为官方的鸿蒙 IDE,基于 IntelliJ IDEA 社区版魔改。它的角色类似 Android Studio 之于 Android 开发。
围绕 DevEco Studio 有一套构建工具链:
| 工具 | 作用 | 类比 |
|---|---|---|
| hvigor | 构建系统,负责编译打包 | Gradle(Android)/ Xcode build |
| hvigorw | hvigor 的命令行启动器 | gradlew |
| ohpm | 包管理器,管理三方库依赖 | npm / pip / cargo |
| hdc | 设备调试连接工具 | adb(Android) |
如果你做过 Android 开发,这套工具链的概念基本可以平移理解。区别在于 hvigor 用 TypeScript 写配置(hvigorfile.ts),不像 Gradle 用 Groovy/Kotlin。
不过 hvigor 和 Gradle 的底层实现差异不小。Gradle 基于 JVM,构建脚本在 Groovy/Kotlin 虚拟机上执行,拥有完整的 DSL 能力和插件生态。hvigor 则是华为基于 Node.js 自研的构建框架,配置文件用 TypeScript 写,执行在 V8 引擎上。这意味着 hvigor 的启动速度比 Gradle 快很多——Gradle 冷启动动辄十几秒,hvigor 通常两三秒就能开始编译。但代价是 hvigor 的插件生态远不如 Gradle 成熟,很多自定义构建逻辑需要开发者手写 TypeScript 脚本,而不是像 Gradle 那样有大量社区插件可以直接 apply。另外 hvigor 的依赖解析机制和 ohpm 配合时偶尔会出现缓存不一致的问题——比如 ohpm install 装了新版本但 hvigor 的缓存还指向旧版本,需要手动清 oh_modules 和 .hvigor 缓藏目录才能解决。这类问题在社区论坛里不算少见,但官方文档里很少提及。
2.4 工程结构概览
一个标准的 Stage 模型工程长这样:
MyApplication/
├── AppScope/ # 应用级配置(跨模块共享)
│ ├── app.json5 # 应用名称、图标、版本等全局配置
│ └── resources/ # 应用级资源(图标等)
│ └── base/
│ └── element/
│ └── string.json # 应用名称字符串
├── entry/ # 主模块(入口模块)
│ ├── build-profile.json5 # 模块级构建配置
│ ├── hvigorfile.ts # 模块构建脚本
│ ├── oh-package.json5 # 模块依赖配置
│ └── src/main/
│ ├── module.json5 # 模块配置(声明 Ability、权限等)
│ ├── ets/ # ArkTS 源码目录
│ │ ├── entryability/
│ │ │ └── EntryAbility.ets # 入口 Ability(生命周期管理)
│ │ └── pages/
│ │ ├── LoginPage.ets # 登录页
│ │ └── Index.ets # 首页
│ └── resources/ # 模块级资源
│ ├── base/
│ │ ├── element/
│ │ │ └── string.json # 字符串资源
│ │ ├── media/ # 图片资源
│ │ └── profile/
│ │ └── main_pages.json # 路由注册文件
│ ├── en_US/ # 英文资源
│ └── zh_CN/ # 中文资源
├── build-profile.json5 # 根级构建配置
├── hvigorfile.ts # 根级构建脚本
└── oh-package.json5 # 根级依赖配置
这个结构看起来层级很深,但核心逻辑就是:AppScope 放全局的东西,entry 放具体模块的东西,resources 按语言/设备分流。如果做过 Android 开发,会发现跟 AndroidManifest.xml + res/ 的思路非常像。

这里有个细节值得展开说说——为什么配置文件用 .json5 而不是 .json?JSON5 是 JSON 的超集,支持注释、单引号字符串、尾随逗号等语法扩展。华为选择 JSON5 而不是纯 JSON,主要是为了解决配置文件可读性的问题。纯 JSON 不允许写注释,开发者在一个几百行的 module.json5 里看到 compatibleSdkVersion: "5.0.0(12)" 时,完全不知道这个版本号代表什么、有哪些兼容性变化。而 JSON5 允许在配置里写 // API 12 引入了 kit 风格的 import 路径 这样的注释,大幅降低了配置维护的认知成本。这也说明华为在工具链设计上确实借鉴了 Android Gradle 配置的痛点教训——Android 的 build.gradle 虽然支持注释,但 Groovy 语法本身对非 JVM 开发者不友好,JSON5 是一个在"可读性"和"结构化"之间的合理折中。

另一个容易忽略的是 resources 目录的分流机制。鸿蒙的资源系统按"限定词目录"做资源匹配,base 是默认资源,zh_CN 是中文环境资源,en_US 是英文环境资源。系统在运行时会根据当前设备语言、屏幕方向、设备类型等条件,按优先级匹配对应的资源目录。比如设备语言是中文时,系统先在 zh_CN 目录下找 string.json,找到就用,找不到就回退到 base 目录。这种机制和 Android 的 values-zh-rCN 目录是同一套思路,但鸿蒙的命名规则更简洁。CodeArts 在生成工程时自动创建了 base、zh_CN、en_US 三套资源目录,说明它对鸿蒙的国际化规范是有认知的——这一点很多新手自己手搓工程时根本不会考虑。

理解了这些前置概念,下面看传统路径和 AI 路径的对比就不会觉得陌生了。
三、需求定义
需求很简单,一句话:
生成一个鸿蒙工程,里面有一个登录页面,用户名 + 密码,点登录后跳到首页。
就这么点东西。下面先看看传统方式要干什么。
四、传统新手路径:从头搞一个鸿蒙工程
作为一个没碰过 ArkTS 的人,如果不用 AI,我大概得走这么几步:
4.1 环境准备
| 步骤 | 操作 | 预估耗时 |
|---|---|---|
| 下载 DevEco Studio | 从华为开发者官网下载安装包,约 2GB+ | 15-20 分钟 |
| 安装并配置 SDK | 首次启动会拉取 HarmonyOS SDK,选 API 12 | 10-15 分钟 |
| 配置 hvigor / ohpm | 构建工具链和包管理器,一般随 IDE 自动装好 | 5 分钟 |
| 创建模拟器或连接真机 | 模拟器需要下载系统镜像,真机需要开启开发者模式 | 10-30 分钟 |
光环境搭好,快的话 40 分钟,慢的话一个上午就没了。这还没开始写一行代码。
这里有个坑特别值得提:SDK 版本选择。鸿蒙 SDK 有多个 API Level(9、10、11、12),不同版本对应的组件 API 有差异。比如 TextInput 组件的 type 参数,在 API 9 之前叫 InputType.Password,API 10+ 可能改了名字或者增加了新选项。新手不知道选哪个版本,通常默认选最新的 API 12,但如果跟着老教程学,教程里用的 API 9 的写法可能在新 SDK 上有兼容性警告。

4.2 新建工程
DevEco Studio 里走向导:File → New → Create Project → Empty Ability → Stage Model。选完之后 IDE 会生成一个标准 Stage 模型工程骨架,包含 AppScope/、entry/、build-profile.json5 等文件。
这一步本身不复杂,但如果你不知道"Stage 模型"和"FA 模型"的区别,就会在选项面前愣住。DevEco Studio 的项目模板列表里有时候还混着 FA 模型的模板,不小心选错了后面全是坑。
4.3 写登录页
核心步骤大概是:
- 在
entry/src/main/ets/pages/下新建LoginPage.ets - 用 ArkTS 声明式语法写 UI:
@Entry @Component struct LoginPage { ... } - 加
@State变量绑定用户名和密码 - 用
TextInput组件做输入框,Button做登录按钮 - 在
.onClick里写校验逻辑 - 用
router.replaceUrl跳转到Index.ets首页 - 修改
main_pages.json注册路由
问题在于,对于一个完全没学过 ArkTS 的人,第 2 步就开始卡壳了——@Entry 和 @Component 是什么?struct 和 class 有什么区别?build() 方法里怎么嵌套组件?链式调用的顺序搞错了会不会报错?

这些概念单独看文档都能搞明白,但组合起来,新手通常会在"代码能编译但 UI 不对"和"编译直接报错"之间反复横跳,光是调布局和样式就能耗掉一两个小时。
4.3.1 ArkTS 声明式 UI 的心智模型
如果你有声明式 UI 经验(Flutter、SwiftUI、Jetpack Compose),ArkTS 的写法会让你觉得很熟悉。核心范式是:
// 装饰器声明组件
@Entry // 标记为页面入口
@Component // 标记为自定义组件
struct LoginPage {
// 响应式状态,改了 UI 自动刷新
@State username: string = ''
// UI 描述,类似 Flutter 的 build() 或 SwiftUI 的 body
build() {
Column() { // 垂直布局容器
Text('欢迎登录') // 文本组件
.fontSize(24) // 链式调属性
TextInput({ placeholder: '请输入用户名' }) // 输入框
.onChange((value: string) => {
this.username = value // 绑定状态
})
}
}
}
表 2:ArkTS 与其他声明式框架对照
| 概念 | ArkTS | Flutter | SwiftUI | React |
|---|---|---|---|---|
| 组件声明 | @Component struct | class extends Widget | struct: View | function Component |
| UI 入口 | build() | build() | body | return JSX |
| 响应式状态 | @State | StatefulWidget + setState | @State | useState |
| 布局容器 | Column() / Row() | Column / Row | VStack / HStack | flex-direction |
| 属性设置 | 链式调用 .width() | 嵌套传参 | 修饰符 .frame() | props/className |
| 事件绑定 | .onClick(() => {}) | onPressed: () {} | .onTapGesture | onClick |
如果你从 Flutter 迁移过来,最大的区别是 ArkTS 用 struct 而不是 class,以及状态更新是自动的(改 @State 变量就行),不需要显式调 setState。
这里需要特别聊一下 ArkTS 中 struct 的设计取舍。在标准 TypeScript 里,struct 关键字并不存在,它不是 JS/TS 的原生概念。华为在 ArkTS 中引入 struct 而不是 class,是有明确的工程意图的。class 在 JavaScript 里是引用类型,对象之间通过引用传递,这意味着如果两个组件持有同一个 class 实例的引用,一个组件修改实例属性会影响另一个组件——这在声明式 UI 框架中是危险的,因为你很难追踪到底谁修改了状态。struct 在 ArkTS 的编译处理中表现为值语义:组件的状态是局部的、隔离的,传递时默认是值拷贝而非引用共享。虽然底层运行时仍然是 JavaScript 引擎,struct 最终也会被编译成 JS 对象,但编译器会在类型检查层面强制实施值语义约束——比如禁止你把 @State 变量直接暴露给外部修改。这种"语法层面的约束 + 编译器强制的隔离"是 ArkTS 区别于普通 TypeScript 框架的核心差异之一,也是它能在资源受限设备上保证状态可预测性的基础。

再来说说 ArkUI 的渲染管线。和 React 的虚拟 DOM diff 不同,ArkUI 采用了基于 Element 树 的增量渲染机制。每个 ArkUI 组件在编译后会被转换成 C++ 层的 Element 节点,这些节点组成一棵 Element 树。当 @State 变量变化时,框架不会像 React 那样重建整个虚拟 DOM 树再做 diff,而是沿着组件树从变更点开始做局部更新——只有受影响的 Element 节点会被重新渲染。这种"精准更新"比 React 的"全树 diff + 最小化 DOM 操作"要高效得多,尤其是在列表渲染和频繁状态变更的场景下。代价是 ArkUI 的组件写法比 React 更"静态"——你不能在 build() 里写条件分支返回不同组件(或者说有严格限制),因为框架需要在编译期就确定组件树结构,运行时的动态变化只能通过数据绑定实现,不能通过结构变化实现。这也解释了为什么 ArkTS 的 if/else 在 build() 里的行为和普通代码不同——它是框架级别的条件渲染指令,不是简单的 JavaScript 条件判断。
4.3.2 布局调试的坑
新手写 ArkTS 布局最容易踩的两个坑:
嵌套层级不对。 ArkTS 的 build() 方法里只能有一个根容器。如果你写了两个并列的 Column(),编译器会报错。解决方法是把所有内容包在一个外层 Column() 或 Stack() 里。

链式调用顺序。 ArkTS 的属性设置是链式的,比如 .width('100%').height(48).fontSize(16).margin({ top: 10 })。顺序一般无所谓,但如果你在 .onClick() 之后再加 .width(),某些旧版本编译器会有 bug。新手不确定顺序就会反复试。
4.4 路由配置
写完登录页代码还不够,你还得在 main_pages.json 里注册页面路由:
{
"src": [
"pages/LoginPage",
"pages/Index"
]
}
忘了注册的后果是:router.replaceUrl({ url: 'pages/Index' }) 运行时直接报错,页面跳不过去,但不给明确的编译期提示。这个坑几乎每个新手都会踩一次。
表 3:鸿蒙路由 API 对比
| API | 行为 | 适用场景 |
|---|---|---|
router.pushUrl() | 压栈跳转,可返回 | 列表 → 详情 |
router.replaceUrl() | 替换当前页,不可返回 | 登录 → 首页(不想返回登录页) |
router.back() | 返回上一页 | 返回操作 |
Navigation 组件 | 容器级路由,支持栈管理 | 复杂导航场景(API 10+ 推荐) |
登录场景用 replaceUrl 是对的——登录成功后你不希望用户按返回键回到登录页。
深入聊聊鸿蒙的路由系统设计。鸿蒙目前同时存在两套路由方案:基于 @ohos.router 的传统路由和基于 Navigation 组件的容器级路由。router API 是鸿蒙早期的路由方案,它的工作方式类似 Flutter 的 Navigator——维护一个全局页面栈,pushUrl 压栈、replaceUrl 替换栈顶、back 弹栈。这种方式简单直观,但有个限制:页面是全局共享的,不能在同一个页面里嵌套多个独立导航区域(比如底 Tab Bar 下每个 Tab 维护自己的导航栈)。Navigation 组件就是为解决这个场景而引入的——它本身是一个 UI 组件,内部维护自己的路由栈,你可以在一个页面的不同区域放置不同的 Navigation 组件,每个都有独立的导航状态。

这在实现"底部 Tab + 每个 Tab 内部多级页面"这种常见 App 结构时非常实用。但 Navigation 组件的 API 比 router 复杂不少,需要手动管理 NavPathStack,对于简单 Demo 来说用 router 足够了。CodeArts 在生成代码时选择了 router.replaceUrl 而非 Navigation,这个决策是合理的——对于一个只有登录→首页两个页面的 Demo,引入 Navigation 组件反而增加了不必要的复杂度。
4.5 调试和运行
| 环节 | 常见问题 | 排查思路 |
|---|---|---|
| Previewer 预览 | 组件不显示? | 检查 build() 里 Column/Row 是否闭合,组件是否有 width/height |
| 模拟器运行 | 模拟器起不来? | 检查 SDK 版本和镜像是否匹配,内存是否够(建议 4GB+) |
| 真机调试 | 真机连不上? | hdc 命令行工具没装或驱动不对,检查 USB 调试是否开启 |
| 路由跳转 | router.replaceUrl 报错? | main_pages.json 没注册目标页面 |
| 白屏 | 页面空白不渲染? | @State 变量初始值不对,或者 build() 里有条件渲染返回了空 |
| 中文乱码 | 文字显示为方框? | resources 目录下缺少 zh_CN 的 string.json |
4.6 小结:传统路径的总成本
| 维度 | 估计 |
|---|---|
| 环境搭建 | 40-60 分钟 |
| 学习语法概念 | 1-2 小时(看文档、查 API) |
| 编写代码 | 1-2 小时(含调试) |
| 调试运行 | 30-60 分钟 |
| 总计 | 约 3-5 小时,前提是你有耐心 |
对于一个有前端/Flutter 经验的开发者来说,这个成本不算特别高,但也不是"随手就搞"的程度。关键瓶颈不在于代码多难写,而在于对生态不熟悉导致的试错成本——不知道哪个 API 是新的、哪个是废弃的、配置文件写错了不报错但就是跑不起来。
五、CodeArts AI路径:一句话生成工程
接下来看看用华为云码道CodeArts走同样的需求,会是什么体验。
5.1 发起请求
打开码道 CodeArts 的对话界面,输入:
我没有学过鸿蒙ArkTS语法,可以帮我生成一个简单的鸿蒙工程吗?要求有一个登陆的页面
就这么一句话,甚至"登陆"写成了错别字(应该是"登录"),但CodeArts依然准确理解了意图。
这其实涉及到 CodeArts的第一个能力:意图识别。它没有纠结于"登陆"vs"登录"的错别字,而是从整体语义判断——用户要一个鸿蒙工程,里面要有登录页面,用户是新手。这三个要素够了,后面就是怎么实现的问题。

从自然语言处理的角度来看,CodeArts 的意图识别并不是简单的关键词匹配。如果只是做关键词匹配,“登陆"会被匹配到"登陆"这个词本身,而不是被理解为"登录"这个动作。CodeArts 之所以能正确处理这个错别字,是因为它内部的大语言模型对中文语义有足够的理解力——“登陆"在中文语境中和"登录"是高度相关的,特别是在"页面"这个上下文里,几乎不可能是指军事上的"登陆”。模型能做出这种语义消歧,靠的是预训练阶段积累的语言知识,而不是某个硬编码的同义词表。这种基于语义理解的意图识别,比传统聊天机器人的关键词匹配方案要灵活得多。当然,它也不是万能的——如果你说"帮我做个登录”,但上下文是在讨论服务器管理,CodeArts 可能会误以为是 SSH 登录。不过在这个场景下,“鸿蒙工程”+"登录页面"的组合已经足够消歧了。

5.2 CodeArts 的执行过程
CodeArts 收到请求后,并不是直接吐出一坨代码,而是走了一套完整的"思考-决策-执行"流程。以下是从截图观察到的实际执行步骤:
表 4:CodeArts 执行流程
| 步骤 | 动作 | 说明 |
|---|---|---|
| 1 | 意图分析 | 识别为鸿蒙开发任务,检查可用技能(game-maker 不适用,harmonyos 相关技能可用) |
| 2 | 环境检查 | 执行 which hvigor hvigorw ohpm node,发现环境里没有鸿蒙构建工具链 |
| 3 | 技能搜索 | 调用 ToolSearch harmonyos,找到 harmonyos-developer 子代理 |
| 4 | 方案决策 | 模板工具 createHmTemplate 报错(templates 目录找不到),决定手动创建工程 |
| 5 | 规划结构 | 列出标准 Stage 模型工程结构:AppScope、entry、build-profile、oh-package、hvigorfile 等 |
| 6 | 生成配置 | 写入 oh-package.json5(modelVersion 5.0.0)、build-profile.json5(compatibleSdkVersion 5.0.0(12)) |
| 7 | 生成入口 | 写 EntryAbility.ets,生命周期管理 + 窗口创建 |
| 8 | 生成登录页 | 写 LoginPage.ets:@State 绑定用户名密码、TextInput 输入框、Button 登录按钮、router.replaceUrl 跳转 |
| 9 | 生成首页 | 写 Index.ets:登录后的欢迎页 |
| 10 | 生成图标 | 检查 ImageMagick 不可用后,用 Python PIL 生成蓝色圆角应用图标 |
| 11 | 校验 | 执行 find . -type f 列出文件 + JSON 语法校验,确认结构完整 |
| 12 | 输出 | 给出工程路径 /workspace/HelloLogin,附使用说明和语法清单 |
整个过程中有几个细节值得一提:
模板工具失败后的自适应。 CodeArts 先尝试用 createHmTemplate 工具直接创建模板,但报错了——templates 目录找不到。这种情况下很多自动化脚本会直接报错退出,但 CodeArts 切换了策略:先查标准鸿蒙工程结构长什么样,然后手动一个文件一个文件地创建。这个"先试快路,不行再走稳路"的决策模式,比纯模板驱动或纯手写的方式都更务实。

配置文件的版本兼容处理。 CodeArts 在写 build-profile.json5 时,选择了 compatibleSdkVersion: "5.0.0(12)",对应 API 12 + DevEco Studio 5.0。它还特别处理了一个 API 12 的 import 语法变化问题:
表 5:API 12 的 import 语法迁移
| 旧写法(API 9-11) | 新写法(API 12+) | 说明 |
|---|---|---|
import router from '@ohos.router' | import { router } from '@kit.ArkUI' | 按功能聚合到 kit 包 |
import UIAbility from '@ohos.app.ability.UIAbility' | import { UIAbility } from '@kit.AbilityKit' | 同上 |
import http from '@ohos.net.http' | import { http } from '@kit.NetworkKit' | 同上 |
华为在 API 12 推动了 import 路径从 @ohos.* 迁移到 @kit.* 风格,目的是把相关模块聚合到一起,减少 import 行数。但这个变化对新手来说是个隐藏的地雷——如果跟着 API 9 的教程写 @ohos.router,在 API 12 的工程里虽然能跑,但会有废弃警告,某些严格模式下直接编译失败。CodeArts 主动选择了新的 kit 风格,避免了这个问题。

图标也能搞。 CodeArts 发现环境里没有 ImageMagick,但 Python3 + PIL 可用,于是用 PIL 画了一个蓝色圆角矩形当应用图标,生成了 1024x1024 和 124x124 两种尺寸。虽然图标很简陋,但至少工程结构是完整的,不会因为缺图标而编译失败。
这种"有 A 用 A,没 A 用 B"的工具降级策略在 CodeArts 中体现得很明显。它不是只会调用某个固定工具,而是会检查环境中有什么可用,然后选择可行的方案。
这一点其实触及了 CodeArts 架构设计的一个核心问题:工具调用的鲁棒性。传统的自动化脚本通常假设环境是确定性的——所有需要的工具都已安装、所有依赖都已就绪、所有目录都有写权限。但现实中的开发环境千差万别,特别是在云端沙箱环境里,你不知道上一轮对话之后环境有没有被重置、网络是否通畅、某个工具是否被卸载了。CodeArts 的做法是在每一步操作前都做环境探测,根据探测结果动态调整执行路径。这种设计让 CodeArts 的容错能力远高于传统脚本,但也带来了一个副作用:执行流程不可预测。你很难提前知道 CodeArts 这次会走哪条路径完成同样的任务——可能这次用 createHmTemplate 模板秒生成,下次因为环境变化就只能手动创建。这种不确定性在 CI/CD 场景里是个问题(你需要可复现的构建),但在交互式开发场景里是可接受的——用户关心的是结果对不对,不是过程一不一致。
5.3 CodeArts 的任务拆解逻辑
从截图里 CodeArts 展示的"已深度思考"过程来看,它内部走了一套类似 ReAct(Reasoning + Acting)的推理链:
表 6:CodeArts 的 ReAct 推理过程
| 阶段 | 内容 | 对应 ReAct 环节 |
|---|---|---|
| 观察 | 用户说没学过 ArkTS,要一个登录页工程 | Observation |
| 推理 | 这是鸿蒙开发任务,用户是新手,需要完整工程而非代码片段 | Reasoning |
| 决策 | 先尝试 createHmTemplate 模板工具 | Action |
| 观察 | 模板工具报错,templates 目录找不到 | Observation |
| 推理 | 模板不可用,需要手动创建。先确认标准工程结构 | Reasoning |
| 决策 | 搜索 harmonyos 技能,获取工程结构参考 | Action |
| 观察 | 找到 harmonyos-developer 子代理,可提供工程结构信息 | Observation |
| 推理 | 确认了 Stage 模型的标准结构,开始手动创建文件 | Reasoning |
| 决策 | 按顺序创建配置文件 → 入口文件 → 页面文件 → 资源文件 | Action |
| 观察 | 所有文件创建成功,JSON 校验通过 | Observation |
| 推理 | 工程结构完整,但需要给用户讲解语法要点 | Reasoning |
| 决策 | 输出工程路径 + 语法清单 + 使用说明 | Action |
这套推理链对用户是透明可见的——每一步"已深度思考"都可以展开查看 CodeArts 的推理内容。这比黑盒式地吐出最终结果要好,因为用户可以判断 CodeArts 的思路对不对,也能从中学到工程搭建的方法论。
5.4 生成的代码
最终生成的 LoginPage.ets 核心逻辑如下(从截图转录):
@Entry
@Component
struct LoginPage {
@State username: string = ''
@State password: string = ''
@State showPassword: boolean = false
build() {
Column() {
Text('欢迎登录')
.fontSize(24)
.margin({ bottom: 20 })
TextInput({ placeholder: '请输入用户名' })
.onChange((value: string) => {
this.username = value
})
TextInput({ placeholder: '请输入密码' })
.type(InputType.Password)
.onChange((value: string) => {
this.password = value
})
Button('登录')
.onClick(() => {
this.login()
})
}
}
login(): void {
if (!this.username || !this.password) {
// toast 提示
return
}
if (this.username === 'admin' && this.password === '123456') {
router.replaceUrl({ url: 'pages/Index' })
} else {
// toast 提示账号或密码错误
}
}
}
代码质量评价:

表 7:CodeArts 生成代码质量评价
| 维度 | 评价 | 说明 |
|---|---|---|
| 结构规范性 | 好 | @Entry/@Component/@State 用法正确,build() 内 Column 嵌套合理 |
| 状态管理 | 好 | @State 响应式变量绑定输入框,符合 ArkUI 声明式范式 |
| 导航方式 | 合理 | 用 router.replaceUrl 而非 pushUrl,登录场景替换路由栈更合理 |
| 安全性 | 仅限 Demo | 硬编码 admin/123456,无加密无后端,仅教学用途 |
| 代码注释 | 充分 | 每个关键语法点都有行内注释 |
| 密码可见性切换 | 预留了 showPassword 变量但未实现切换逻辑 | 可以手动补一个图标按钮来做切换 |
| 表单校验 | 基础 | 只做了非空检查,没有格式校验、长度限制等 |
CodeArts 还生成了完整的配置文件。其中 oh-package.json5 的内容:
{
"modelVersion": "5.0.0",
"description": "HarmonyOS ArkTS login demo (Stage model)",
"dependencies": {},
"devDependencies": {
"@ohos/hypium": "1.0.19"
}
}
@ohos/hypium 是鸿蒙官方的单元测试框架,CodeArts 把它加到了 devDependencies 里——虽然这个 Demo 暂时没写测试用例,但至少把测试框架的依赖准备好了。

关于 hypium 框架本身,值得多说几句。它是华为专门为 ArkTS 设计的 BDD 风格测试框架,API 风格和 JavaScript 社区里常见的 Jest/Mocha 类似,但运行在鸿蒙的测试运行时上。写一个典型的 hypium 测试用例大概长这样:先用 describe 定义测试套件,再用 it 定义测试用例,断言用 expect().assertEqual() 这种链式 API。和 Jest 最大的区别是 hypium 需要在真机或模拟器上运行——因为 ArkTS 组件依赖鸿蒙运行时环境,不能像 Jest 那样在纯 Node.js 环境跑。这意味着测试的反馈循环更长:写代码 → 编译 → 部署到设备 → 运行测试 → 查看结果,一轮下来可能要一两分钟。这也是为什么很多鸿蒙开发者不愿意写单元测试的原因——反馈太慢了。不过华为在 DevEco Studio 5.0 里引入了 @ohos/hypium 的增量测试能力,只运行受变更影响的测试用例,一定程度上缩短了反馈循环。CodeArts 预置 hypium 依赖虽然只是一个小动作,但说明它对鸿蒙工程的"最佳实践"是有认知的——一个规范的鸿蒙工程就应该包含测试框架依赖,哪怕暂时是空的。
5.5 CodeArts 附带的学习材料
除了代码本身,CodeArts 还附带输出了两个很有价值的材料:
给初学者的最小语法清单:
表 8:CodeArts 生成的 ArkTS 最小语法清单
| 语法 | 说明 |
|---|---|
@Entry @Component | 页面顶部两个必写装饰器 |
struct 组件名 { build(){} } | 定义组件,UI 写在 build() 里 |
@State 变量 | 声明状态,改了 UI 自动刷新,不用手动 setState |
Column() / Row() | 垂直 / 水平布局容器 |
Text() Button() TextInput() | 文本 / 按钮 / 输入组件 |
.width() .fontSize() .onClick() | 链式调用设属性和事件 |
router.replaceUrl({url: 'pages/Index'}) | 页面跳转 |
这个清单对一个完全没学过 ArkTS 的人来说相当实用——七条语法覆盖了写一个页面所需 80% 的知识点。

使用说明:
CodeArts 还输出了工程的使用方法,包括:
- 测试账号密码:admin / 123456(硬编码在
LoginPage.ets第 24 行) - 打开方式:用 DevEco Studio 5.0+ 导入
/workspace/HelloLogin目录 - 注意事项:当前云端环境没有 hvigor 构建工具,无法直接编译,需要本地用 DevEco Studio 运行
这个说明省去了用户"代码拿到了但不知道怎么跑"的困惑。
5.6 同步到代码仓库
工程生成后,用户又试了一句:
帮我初始化到一个鸿蒙相关的仓库
CodeArts 的处理过程同样值得拆解:
表 9:仓库同步流程
| 步骤 | CodeArts 动作 | 说明 |
|---|---|---|
| 1 | 检查 git 和 ag(AtomGit CLI) | which git、ag auth status |
| 2 | 发现 ag 未登录 | 提示用户去 atomgit.com 创建 Personal Access Token |
| 3 | 引导用户创建 Token | 给出详细步骤:登录 → 设置 → 个人访问令牌 → 创建 repo 权限的 token |
| 4 | 用户选择 AtomGit 平台 | CodeArts 用 token 配置 ag 认证 |
| 5 | 初始化 git 仓库 | git init、git remote add |
| 6 | 提交并推送 | git add . && git commit -m "init: HarmonyOS ArkTS login demo" && git push |
| 7 | 处理 .git 损坏 | 遇到 git 元数据损坏,用 git init 重新初始化修复 |
| 8 | 最终结果 | 推送到 atomgit.com/gcw_QH3WOVDS/hellologin,20 个文件,commit ce27e06 |
Token 安全处理。 CodeArts 在引导用户创建 Token 时,明确说了只需要 repo(读写)权限,不需要 admin 等更高权限,而且提醒用户推送完成后及时撤销 Token。这种最小权限原则在 AI 工具里做对了不容易——很多工具会图省事让用户给最大权限。
中间还遇到了一个插曲:工作目录被环境重置了(云端的 /workspace 不是持久化的),CodeArts 发现后自动从 AtomGit 克隆回来继续操作。这种环境自愈能力在云端开发场景里很重要——沙箱环境随时可能被回收,CodeArts 能自动从远程仓库恢复状态继续干活。

这个"环境自愈"的过程值得从技术角度拆解一下。CodeArts 在发现工作目录被清空后,并没有直接报错"文件找不到了,请重新生成",而是执行了一套恢复逻辑:首先检查远程仓库是否存在 → 确认 atomgit.com 上有之前的推送记录 → 执行 git clone 恢复工程文件 → 继续后续操作。这个过程的关键在于 CodeArts 维护了一个"状态检查点"——它知道之前做过什么操作(生成工程 → 推送仓库),所以能判断出"本地丢了但远程有备份"这个状态,并选择正确的恢复策略。如果 CodeArts 没有这个上下文记忆,它可能会尝试重新生成工程而不是从远程恢复,那就意味着之前的工作白做了。这种基于会话历史的自愈能力,是 CodeArts 区别于无状态脚本工具的重要特征。当然它也不是完美的——如果远程仓库也没推上去(比如推送之前环境就崩了),那确实没法恢复。所以从工程实践角度,最好的做法是在 CodeArts 完成关键节点后主动触发一次 git push,把状态持久化到远程仓库,减少环境重置带来的损失。
5.7 补充 README
后续用户发现仓库的 README 是空的(Gitee 页面上红箭头标注"项目 README 为空"),于是又让 CodeArts 补了一个 README。CodeArts 同样走了一遍:克隆 → 写 README.md → commit → push。
生成的 README 包含:
- 项目名称和简介
- 功能列表(登录页、首页跳转、中英文资源)
- 工程结构目录树
- 使用说明

最终仓库在 Gitee 上的展示效果:README 有内容、文件列表完整、语言占比显示 ArkTS 94.74%、TypeScript 5.26%、2 个 commit、3 次下载。
5.8 耗时对比
表 10:两种路径耗时对比
| 环节 | 传统新手路径 | AI CodeArts 路径 |
|---|---|---|
| 环境搭建 | 40-60 分钟 | 0 分钟(云端环境,无需本地安装) |
| 学习语法 | 1-2 小时 | 0 分钟(CodeArts 生成代码 + 附带语法清单) |
| 编写代码 | 1-2 小时 | 约 4 分钟(CodeArts 自动生成 20 个文件) |
| 调试验证 | 30-60 分钟 | 约 1 分钟(JSON 语法校验 + 文件完整性检查) |
| 仓库初始化 | 10-15 分钟 | 约 2 分钟(自动 git init + push) |
| 补充 README | 10-15 分钟 | 约 2 分钟(自动生成 + 推送) |
| 总计 | 约 3-5 小时 | 约 10 分钟 |
需要说明的是,CodeArts 路径的 10 分钟里,绝大部分时间是在等 CodeArts 执行——用户只需要在开头输入一句话,中间选一下仓库平台,最后确认一下推送。CodeArts 自己报告的总耗时约 3 分 49 秒,加上用户交互时间,差不多 10 分钟以内搞定。
六、从代码到运行:用户拿到工程后还要做什么
CodeArts 生成的工程在云端 /workspace/HelloLogin,但用户最终要把它跑起来还得过几关。
6.1 导入 DevEco Studio
表 14:从 CodeArts 生成到本地运行的步骤
| 步骤 | 操作 | 注意事项 |
|---|---|---|
| 1. 下载代码 | 从 AtomGit 克隆或下载 ZIP | 确保网络能访问 atomgit.com |
| 2. 安装 DevEco Studio | 5.0 以上版本 | 对应 API 12 的 SDK |
| 3. 导入工程 | File → Open → 选择 HelloLogin 目录 | 工程结构需要被 IDE 正确识别 |
| 4. 同步依赖 | IDE 自动执行 ohpm install | 需要网络下载 @ohos/hypium 等依赖 |
| 5. 配置签名 | Project Structure → Signing Configs | 模拟器可以用自动签名,真机需要手动配 |
| 6. 运行 | 选模拟器或真机,点 Run | Previewer 可以快速预览 UI 但不支持路由跳转 |
6.2 可能遇到的问题
表 15:从 CodeArts 代码到本地运行的常见问题
| 问题 | 原因 | 解决方案 |
|---|---|---|
| ohpm install 失败 | oh-package.json5 里的依赖版本在远程仓库找不到 | 检查网络,或手动改版本号 |
编译报错找不到 @kit.ArkUI | DevEco Studio 版本低于 5.0,不支持 kit 风格 import | 升级到 5.0+,或改回 @ohos.* 写法 |
| 应用图标显示异常 | CodeArts 用 PIL 生成的图标过于简陋 | 手动替换正式图标 |
| Previewer 白屏 | main_pages.json 里首个页面不是 LoginPage | 检查路由注册顺序 |
| 真机运行报签名错误 | 签名配置未完成 | 在 Project Structure 里配置自动签名 |
| 登录后跳转失败 | router.replaceUrl 的 URL 和 main_pages.json 注册的不一致 | 确认路径大小写和格式一致 |
这些问题不是 CodeArts 的锅——它生成的是标准工程,但"标准"不等于"能直接跑",中间还有环境适配的工作。这也是 CodeArts 路径目前没法完全替代人的原因之一:生成代码容易,让代码在特定环境里跑起来还需要人。

从更宏观的角度看,CodeArts 生成代码和本地运行之间存在一个"验证鸿沟"。CodeArts 在云端生成代码后,能做的验证只限于静态层面——文件是否齐全、JSON 语法是否正确、import 路径是否匹配。但代码能不能跑、UI 渲染对不对、路由跳不跳得通,这些动态验证需要编译 + 运行环境。目前码道 CodeArts 的云端环境没有装 hvigor 和鸿蒙 SDK,所以没法做编译验证。

这个限制的根因是鸿蒙 SDK 体积很大(几个 GB),在云端沙箱里为每个会话都配一套完整 SDK 成本太高。未来如果华为能在云端提供轻量级的 ArkTS 编译服务(类似 Go Playground 那种在线编译),CodeArts 就能在生成代码后立刻做编译验证,把"验证鸿沟"补上。在那之前,用户还是得接受"CodeArts 生成的代码结构正确但可能有运行时 bug"这个现实,准备好在本地做一轮编译测试。

七、总结
两种路径各有优劣,放在一起看就很清楚了:
表:总结对比
| 对比维度 | 传统新手手搓 | AI CodeArts 生成 |
|---|---|---|
| 上手门槛 | 高(需装环境、学语法) | 极低(一句话启动) |
| 耗时 | 3-5 小时 | 约 10 分钟 |
| 代码可控性 | 高(每行自己写的) | 中(需要读代码才能改) |
| 产出完整度 | 看个人经验 | 高(结构规范、带文档、带国际化) |
| 学习价值 | 高(踩坑即学习) | 中(附带语法清单但需主动消化) |
| 代码可运行性 | 本地可编译运行 | 需导入 DevEco Studio 后验证 |
| 适合场景 | 想系统学习鸿蒙开发 | 想快速出 Demo 验证想法 |
如果你的目标是"快速搞一个能跑的鸿蒙 Demo 看看效果",AI CodeArts 路径完胜。十分钟从一句话到完整工程 + 仓库推送,这个效率是手动不可能达到的。特别是 CodeArts 在生成代码的同时附带语法清单和使用说明,对于纯新手来说相当于"边做边学"——先有一个能跑的工程在手,再逐行去看代码理解语法,比纯看文档有效率得多。
如果你的目标是"深入掌握鸿蒙开发",CodeArts 生成的东西只能当起点,不能当终点。因为真正写鸿蒙应用要处理的远不止一个登录页——状态管理(@State/@Prop/@Link/@Provide/@Consume)、网络请求(@kit.NetworkKit 的 http 模块)、自定义组件、动画、多设备适配——这些复杂场景都需要你亲手写、亲手调过才能形成肌肉记忆。CodeArts 可以帮你搭骨架,但血肉得自己填。
如果你介于两者之间——有开发经验但没碰过鸿蒙,那最实际的路径是:先用 CodeArts 把第一个 Demo 跑起来,建立信心和整体认知;然后把生成的代码逐行过一遍,理解每个装饰器、每个组件的作用;最后在此基础上手动改功能——加密码可见性切换、加表单校验、接个假的后端 API——通过"改"来学,比从零开始"写"效率高得多。
更多推荐



所有评论(0)