
如果你正在考虑做 HarmonyOS 应用开发或者已经投了相关岗位但拿不准面试会问什么我劝你先别急着刷题。鸿蒙开发不是换一个 IDE 写同样的代码它的工程模型、UI 范式和发布链路和安卓/iOS 的差异比想象中大。这篇文章从岗位职责拆解到 API 12 时代的核心技术实践再到面试高频题和答题思路一次性讲清楚。适合刚入门的学生、准备转行的安卓开发以及已经在做鸿蒙但想系统梳理知识树的研发人员。先亮个底HarmonyOS NEXT 的 SDK 已经走到 API 12 / 5.0.0(12) 这个阶段开发语言是 ArkTSUI 是 ArkUI 声明式范式工程结构也全面转向 Stage 模型。如果你只盯着代码能不能跑不搞清楚背后的设计意图遇到问题会很难定位面试也很容易在“为什么这样设计”这一层被问住。下面我按实际项目的执行顺序来聊。1. 先看清鸿蒙开发的岗位职责与能力模型很多候选人一上来就刷面试题结果连岗位 JD 里写的“负责鸿蒙应用的设计、开发与维护”到底包含多少环节都不清楚。这个很吃亏。你得先知道一份典型的鸿蒙开发岗位日常在做什么技术栈要求到哪一层再对应去准备。1.1 岗位 JD 拆解哪些要求是真刀真枪我翻了几个招聘平台上的鸿蒙开发工程师 JD基本都包含这几类职责描述背后实际指的是什么负责鸿蒙应用功能开发与迭代用 ArkTS 写业务代码处理 UI、状态、网络、本地存储承担性能优化任务关注页面渲染、列表滑动流畅度、启动时间、包体积、内存占用负责与产品、设计、后端协作要能讲清楚鸿蒙的权限模型、发布包规范推动多端适配参与技术方案设计与评审不是只写页面要会设计模块拆分、路由方案、状态管理方案保障应用安全与隐私合规权限申请、隐私弹窗、数据最小化采集上架时审核重点这里面最容易忽略的是“技术方案设计”。很多新人以为鸿蒙开发就是“把 Java/Kotlin 页面翻译成 ArkUI”其实不然。真正的工作是需求下来后你要先判断这个页面应该用 UIAbility 还是元服务卡片承载是用 Navigation 还是 Tabs 做导航状态是放在组件里还是全局 Store 里数据请求失败怎么降级。这些决策直接影响后续维护成本。1.2 初、中、高级开发的能力边界我用三个级别来划一条能力线你对照自己现在的位置。初级开发能独立完成一个页面到另一个页面的完整流程。熟悉 ArkTS 基本语法、State 状态管理、列表组件、页面路由跳转、JSON 数据解析能上手 DevEco Studio 跑通真机调试。中级开发开始关注应用架构。理解 Stage 模型、UIAbility 生命周期函数的意义能使用 Navigation 管理复杂栈会处理组件间多层通信懂权限申请和隐私合规能通过状态管理 V1 和 V2 的差异去优化刷新范围。这一级别的人通常已经独立交付过一两个完整功能模块。高级开发关注性能、稳定性、多端适配和工程化。会做启动耗时分析、内存泄漏排查、列表懒加载优化、HSP 动态加载包拆分能设计跨工程复用的 HAR/HSP 库也会针对折叠屏、Pad、PC 做响应式布局。面试时这个层级的问题基本不会问 API 怎么调用而是问“这个方案为什么可行瓶颈在哪”。1.3 “鸿蒙应用开发基础认证”值得考吗热词里出现了“鸿蒙应用开发基础认证”我直接给结论值得但是别把它当万能通行证。基础认证覆盖的是 Stage 模型、ArkTS 基础语法、ArkUI 基础组件、权限模型、轻量级并发这些内容概念占比高代码量不大。对于转行或应届生它能帮你快速梳理出完整的知识地图对于有经验的人它侧重的知识点偏基础价值有限更建议去研究华为开发者官方的应用开发高级认证或元服务相关认证。复习认证时可以多用逆向整理法看到某个概念先想“如果我不用它项目会碰到什么麻烦”。比如 Stage 模型和 FA 模型的区别不是为了考试背的而是为了理解 HarmonyOS 为什么强制把 UI 和业务生命周期拆开。搞懂这个比刷一百道题管用。2. 核心技术实践API 12 阶段必须理解的设计差异这一部分几乎决定了你的开发体感。很多人从安卓转过来第一个不适应的就是“我写的代码怎么动不动要加装饰器”“文件结构怎么这么多层”。我会逐个讲清楚顺便给出实测过的建议。2.1 开发环境与工程结构连接 SDK 的第一关开发鸿蒙应用官方 IDE 是 DevEco Studio建议统一使用 HarmonyOS NEXT 版本的 SDK也就是 API 12 / 5.0.0(12) 这条线。下载后不要在本地混装多个版本的 SDK否则 hvigor 构建时经常出现依赖冲突。我踩过一次坑电脑上同时残留了 API 9 和 API 12 的 SDKsync 时报错找不到 symbol最后只能把旧版本全部清掉重新下载。新建工程时你会看到默认模块叫 entry模块内又有src/main、ets、resources等目录。重点解释一下ets目录它是你写 ArkTS 代码的地方页面组件通常放在ets/pages或ets/view。模块配置文件是module.json5应用级配置文件是app.json5权限在哪里申请、Ability 在哪里注册都在这两个文件里找。这一点和安卓的 AndroidManifest 很像但字段名和语义完全不同别直接套。工程里还会出现hvigorfile.ts这是构建脚本配置文件。普通开发者不需要经常改它但要知道它是基于 hvigor 的构建体系。如果你将来要做多模块工程比如拆成多个 HAR/HSP 模块就需要手动修改模块依赖这时候理解这个文件就很有必要。2.2 ArkTS 不只是 TypeScript语法限制要记牢HarmonyOS 应用开发默认使用 ArkTS它基于 TypeScript 做了大量裁剪和约束目的只有一个保证运行时性能稳定让静态分析能兜底。很多人以为写 ArkTS 就是在写 TS结果一编译就报错。两个最常见的差异点一是不能随意使用any。在 ArkTS 里类型必须明确尽量用interface、class、联合类型去描述数据结构。你从接口拿到的数据要定义一个interface JobItem然后使用JSON.parse转换。如果图省事写let data: any编译阶段可能能过但后续维护会非常痛苦官方编译器也明确建议避免。二是装饰器是核心。ArkUI 状态管理依赖Component、Entry、State、Prop、Provide、Consume等装饰器。它们不只是注解而是编译框架识别对象绑定关系的依据。状态变量前加State表示数据变化时会驱动 UI 刷新Prop表示从父组件传递过来的单向数据Link是双向绑定。初学时建议亲手写一个计数器分别用State和Link实现观察它们的行为差异。这一步是对“响应式”最直观的体感。2.3 ArkUI 声明式 UI从“怎么画”到“描述状态”ArkUI 的核心思想是声明式 UI你描述某个状态下的界面长什么样框架负责在状态变化时更新视图。这和 Compose、SwiftUI 是一个路子所以有相关经验的人上手会快。写页面时build()方法里声明组件树Entry Component struct Index { State message: string 你好鸿蒙 build() { Column({ space: 16 }) { Text(this.message) .fontSize(24) .fontWeight(FontWeight.Bold) Button(点击更新) .onClick(() { this.message 状态已更新 }) } .width(100%) .padding(16) } }Column是纵向容器Row是横向容器Stack是层叠布局。日常开发里90% 的页面布局靠这三种容器就够了。需要注意ArkUI 不是让你直接用固定像素到处写死而是提供px、vp、%等单位。建议用vp作为尺寸单位%做宽高比例字体大小也用fp这样才能适配不同分辨率。列表是应用最常见的场景一定要掌握List组件和ForEach的配合。一开始不要用Scroll嵌套一堆Column去模拟列表数据一多会很卡。正确做法是List({ space: 12 }) { ForEach(this.jobList, (item: JobItem) { ListItem() { JobCard({ job: item }) } }, (item: JobItem) item.id) }ForEach的第三个参数是键生成函数用唯一 id不要用数组下标否则增删数据时会触发多余的渲染甚至导致组件复用错乱。2.4 底部导航栏实例从 Tabs 到 Navigation很多教程一上来讲“鸿蒙应用开发底部导航栏”但基本都停留在调用Tabs和TabContent的层面。我就多说一层为什么 API 12 之后我建议你用Navigation来管理主要的导航结构。Tabs适合页签数量固定、切来切去很频繁的场景比如首页、职位、收藏、我的这类结构。它的优点是状态天然保留每个 TabContent 的页面实例会维持。但也有缺点Tab 之间跳转如果涉及二级页面只能往根路由上压栈不好控制返回行为。Navigation是更现代的导航容器配合NavPathStack管理路由栈。它能把 Tab 级的切换和页面级的路由压栈统一起来。我的做法是根页面用 Navigation底部用 TabsTabs 内部的内容区域用 Navigation 的子组件承载。具体示例如下Entry Component struct MainPage { private pathStack: NavPathStack new NavPathStack() build() { Navigation(this.pathStack) { Tabs() { TabContent() { HomePage() }.tabBar(首页) TabContent() { JobListPage() }.tabBar(职位) TabContent() { FavoritesPage() }.tabBar(收藏) } } .hideTitleBar(true) .mode(NavigationMode.Stack) } }如果你只是要实现一个简单的底部导航用Tabs就够了。但如果你预感到这个应用会越做越深比如首页卡片要跳到详情页详情页还要分享、收藏、拉起客服等建议直接上Navigation。详情页用this.pathStack.pushPathByName(JobDetail, itemId)就可以压栈返回逻辑由系统处理不需要自己维护返回栈。2.5 状态管理与数据流刷新范围控制是核心状态管理这块很多新手会忽略“刷新范围”。在 ArkUI 里State修饰的变量变化会触发组件重新渲染。如果一个大对象被放在组件顶层任何字段变化都可能让整棵子树重绘。解决方法是把状态下沉到更小的子组件或者使用更精确的状态装饰器。API 12 阶段官方主推状态管理 V2也就是ObservedV2和Trace这一类装饰器。它们能精确到对象的某个属性变化时触发对应 UI 更新避免无效渲染。如果你在做列表实时刷新、上报进度这类场景建议升级到 V2。但注意V2 和旧版 V1 混用时要小心部分场景有兼容限制迁移验证要做充分。组件间通信也要理清思路父子同层用参数传递和Prop/Link跨页面用路由参数全局数据用AppStorage或者LocalStorage深层次组件用Provide/Consume。最忌讳的是到处用AppStorage最后全局变量满天飞调试时根本不知道谁改的。3. 完整实操一个求职助手页面的开发闭环光讲概念容易飘我拿一个贴近应用场景的“求职助手”功能来走一遍完整流程。这个案例覆盖了列表加载、详情跳转、状态管理和权限声明你跟着跑完代码基本就掌握了常规鸿蒙应用的开发主线。3.1 需求拆解与路由设计假设需求是这样的首页展示职位列表点击职位卡片进入详情页详情页有关注按钮可以收藏职位。看起来很简单但落地时第一个问题是“页面怎么组织”。我采用三个页面首页HomePage、列表页JobListPage、详情页JobDetailPage。首页用快捷入口点击后通过 Navigation 跳转到列表页。列表页从本地 JSON 或远程接口读取职位数据详情页接收职位 id再从数据源查询详情。路由注册可以写在MainPage的Navigation里NavPathStack({ routes: [ { name: JobList, builder: () JobListPage() }, { name: JobDetail, builder: (param: object) JobDetailPage({ itemId: param as string }) } ] })如果你用的是Navigation但页面很多建议把路由表封装到一个单独的文件里避免 MainPage 无限膨胀。3.2 数据模型与网络请求定义数据模型不要用anyexport interface JobItem { id: string company: string title: string salary: string location: string publishedDate: string tags: string[] } export interface JobDetail extends JobItem { description: string requirements: string[] }网络请求我用的是ohos.net.http它提供了http.createHttp()等接口。一个典型请求长这样import http from ohos.net.http function fetchJobList(): PromiseJobItem[] { return new Promise((resolve, reject) { const httpRequest http.createHttp() httpRequest.request(https://api.example.com/jobs, { method: http.RequestMethod.GET, header: { Content-Type: application/json }, expectDataType: http.HttpDataType.STRING, timeout: 10000 }).then((response: http.HttpResponse) { const result JSON.parse(response.result as string) as { data: JobItem[] } resolve(result.data) }).catch((err: Error) { reject(err) }) }) }这里有个小细节expectDataType建议设置成STRING然后手动 JSON.parse。如果直接设置成OBJECT某些接口返回的 JSON 结构不标准时解析会意外失败。自己手动解析反而可控性更好。3.3 页面数据加载与下拉刷新列表页的数据加载需要处理三种状态加载中、加载成功、加载失败。不能只在页面启动时请求一次还得做下拉刷新。ArkUI 的Refresh组件可以包住ListState jobList: JobItem[] [] State loading: boolean false State hasError: boolean false build() { Refresh({ refreshing: this.loading, onRefreshing: () this.refresh() }) { List({ space: 12 }) { if (this.jobList.length 0) { ForEach(this.jobList, (item: JobItem) { ListItem() { JobCard({ job: item }) .onClick(() { this.pathStack.pushPathByName(JobDetail, item.id) }) } }, (item: JobItem) item.id) } else if (this.hasError) { ListItem() { ErrorView({ onRetry: () this.loadData() }) } } else { ListItem() { LoadingView() } } } } }我第一次写的时候把加载状态直接放在build()里判断结果每次刷新都要重建整个 List滚动位置会丢失。后来改成把状态判断放在ListItem内部列表结构保持稳定体验好了很多。具体做法是始终渲染 List 和 ForEach根据jobList.length和hasError决定列表项内容。3.4 权限声明与隐私合规你在请求远程接口时必须声明网络权限。HarmonyOS 的权限配置在模块的module.json5里{ module: { requestPermissions: [ { name: ohos.permission.INTERNET } ] } }上面的写法足以让应用具备访问网络的权限。但要注意如果涉及位置、相机、麦克风等敏感权限你不仅要在module.json5里声明还需要在运行时通过abilityAccessCtrl动态申请import abilityAccessCtrl from ohos.abilityAccessCtrl import common from ohos.app.ability.common async function requestPermission(context: common.UIAbilityContext) { const atManager abilityAccessCtrl.createAtManager() const permissions: Arraystring [ohos.permission.CAMERA] const result await atManager.requestPermissionsFromUser(context, permissions) if (result.authResults[0] 0) { // 已授权 } }很多新手在上架时被拒就是因为在隐私弹窗里没有把权限用途讲清楚。合规建议是不要在应用第一启动时把所有权限一次性要完而是在用户真正使用某个功能时再申请。比如用户点击“拍照上传简历”时才申请相机权限拒绝率反而低审核也更容易过。3.5 真机调试与构建发布开发过程中一定要用真机不能只在模拟器上跑。鸿蒙最大的测试难度在多设备布局模拟器覆盖不了所有屏幕形态。真机连接方式是在 DevEco Studio 中通过 hdc 工具命令行也可以操作hdc list targets hdc shell bm dump -a签名配置方面个人开发用自动签名即可。在File Project Structure Signing Configs里勾选自动签名登录华为账号后会自动生成调试证书。发布上架时需要在 AppGallery Connect 中创建应用配置发布证书和 Profile然后通过构建产物上传。上架前还要做的一件事是包体瘦身。这里我建议优先检查resources目录里的图片资源不要直接丢大量 PNG。ArkUI 支持多倍图资源目录比如resources/base/media和resources/base/media/。把图片压缩、使用同色系 SVG、删除无用的国际化文案都能有效缩小包体积。4. 面试指南高频题、答题思路与项目表达最后一部分集中讲面试。我把常见面试题按“原理题、实践题、项目题”三类整理每题给一个可以直接说的核心观点。4.1 原理高频题与回答要点面试题回答要点Stage 模型和 FA 模型的区别Stage 模型基于 UIAbility 窗口管理支持多实例、业务逻辑与 UI 分离FA 模型相对简单但扩展性和稳定性不足。强调“当前开发以 Stage 为准”UIAbility 生命周期有哪些onCreate、onWindowStageCreate、onForeground、onBackground、onDestroy。要能说出每个阶段适合做什么比如数据初始化放onCreateUI 初始化放onWindowStageCreateArkUI 状态管理的原理装饰器建立依赖关系变化时框架精准通知组件刷新。可以提 V1/V2 差异V2 更精确组件间通信方式有哪些父传子用Prop双向用Link跨级用Provide/Consume页面路由传参全局用AppStorage鸿蒙的权限模型普通权限直接声明敏感权限运行时申请使用abilityAccessCtrl注意用户拒绝后的降级处理路由和 Navigation说明NavPathStack可以管理栈、动画和转场比旧 router 更适合复杂项目回答原理题不要背定义。面试官问你生命周期你最好顺手带一个真实场景“我在这边启动时需要读本地缓存所以把缓存初始化放在onCreate但涉及 UI 渲染的放onWindowStageCreate避免窗口还没就绪就改界面”。这样说才有区分度。4.2 实践高频题与排查方法实践题会问“列表卡顿怎么排查”“应用启动慢怎么优化”“有内存泄漏怎么定位”。思路比答案重要。列表卡顿先看是否有未懒加载的图片、是否在ForEach中写复杂计算、是否频繁创建组件副本。然后打开 DevEco Studio 的 Profiler 工具抓 UI 渲染帧率重点看LazyForEach是否被正确使用。注意数据超过几百条建议改用LazyForEach避免一次性创建所有列表项。启动慢从冷启动时间拆解三个耗时点Ability 初始化、页面布局渲染、首帧数据请求。优化思路延迟加载非关键模块、首帧先用缓存数据、避免在主线程做同步 I/O、使用TaskPool分担计算任务。前期可以把console.log先注释掉日志输出在真机上也会拖慢启动速度这个细节很多人都忽略了。内存泄漏经常出现在页面关闭后仍有异步任务回调。排查方法是在页面aboutToDisappear里确认网络请求取消、定时器清除、全局单例引用移除。真机上用hdc shell配合内存快照比对定位泄漏对象。4.3 项目经验怎么讲才能不虚面试官最怕的是候选人说“我做过一个商城项目”问细节时只能说“我用了 xxx 组件会写页面”。正确方式是用 STAR 法则并把细节落在鸿蒙专属能力上。举个例子你说你做过“求职助手”应用。背景业务需要快速落地一个用于提升用户找工作效率的工具初期只需支持职位列表、职位详情、收藏功能。任务独自负责整体技术方案要求一次上架通过。行动使用 Stage 模型搭建应用用Navigation管理列表到详情页的路由跳转列表使用LazyForEach配合接口分页避免一次性渲染 500 条数据详情页用State缓存页面状态从列表页跳转时不重复请求已经传过的数据收藏功能使用关系型数据库RelationalStore保存本地数据权限申请只在用户点击收藏时请求本地存储权限顺便处理了拒绝场景。结果首包体积控制在 12MB 以内启动时间降低 20%一次通过审核。重点不是结果数字有多大而是你要能解释每一步为什么这么选。如果被追问“为什么不用 Tabs”你要答出 NPage 和 TabBar 在这种场景下的取舍如果被追问“LazyForEach 的键怎么写”你能说出键生成的规范就赢了。4.4 关于 AI 应用开发方向怎么切入现在很多岗位方向加上了“AI 应用开发”标签。HarmonyOS NEXT 在系统层面已经提供端侧智能能力比如文本摘要、语音识别、图像分类等可以通过系统接口集成。面试聊到 AI不要只停留在概念建议这样说“我在鸿蒙应用里考虑过集成端侧模型能力比如本地实现职位描述的摘要提取避免把用户数据上传到云端这样既保证隐私也降低响应延迟。”这句话一出面试官基本会认为你有架构思考而不是只会调云接口。但要注意端侧模型有模型体积和性能限制实际落地时通常还要配合服务端。你可以把“本地优先、云端兜底”这个思路讲清楚比空谈大模型要扎实得多。4.5 我的三点面试体会最后分享几个我在实际复盘里发现的关键点。第一个是“别背题动手跑”。有很多候选人能把生命周期的顺序倒背如流但问到“在onWindowStageCreate里loadContent加载的页面什么时候真正显示”就卡壳了。这只能说明他没调过真机没实际体验过断点到底在哪。第二个是“学会画系统框图”。面试时如果能快速画出一个应用的模块依赖图、路由关系、状态流表达会清晰很多。平时写项目时我建议每写完一个模块就花五分钟画一张简化图。不是为了交付而是强迫自己理解模块边界。第三个是“要把踩坑讲出来”。面试官问“项目困难”不要只说“我通过查文档解决了”。要讲清楚当时为什么卡住了卡了多久最后是怎么定位的。这个比结果本身更能体现解决问题的能力。比如前面我说 SDK 版本混装导致的构建失败就是一个很好的真实案例。我在实际开发中的体感是鸿蒙现在缺的不是“会写 API 的码农”而是能讲清楚分层架构、状态模型和性能瓶颈的人。你把底部导航、一个列表页、一个详情页完整跑通再配合一次性能优化面试的成功率就会高很多。希望这篇内容能帮你在岗位认知、技术实践和面试表达上少走弯路。