从传统App开发切到鸿蒙Harmony开发一开始我是拒绝的倒不是觉得技术难而是被那套全新工程结构、声明式UI写法以及五花八门的配置文件搞得有点头大。不管怎么说硬着头皮啃了一段时间后我发现自己积累了不少容易被人忽略的实操细节。今天干脆整理一份开发备忘录把我自己走过的弯路、验证过可行的方案以及一些反复记不住的API细节都摊开来讲权当给自己留个底也给准备入坑的同行做个参考。如果你正打算接触鸿蒙应用开发或者已经写了几个页面但总觉得哪里没弄透这份备忘录应该能帮你省下不少瞎折腾的时间。我尽可能按“从工程搭建到上架发布”的完整路径来讲中间会穿插一些只有实际动手才会发现的坑和细节。1. 工程搭建与项目结构先把地基打稳1.1 DevEco Studio版本与API版本选择这一步可能是大部分新手最迷茫的地方。打开官网下载DevEco Studio你会发现有好几个版本而且对应的SDKAPI版本也不同。我个人的建议是稳定优先除非你有特殊需求否则不要一上来就追最新API版本。新的API往往意味着新特性但也意味着社区方案还不成熟网上能搜到的有效信息也最少。项目兼容性如果你的项目需要兼顾老设备最低支持的API版本就不要定太高。实测下来API 9和API 11之间的API变更虽然不至于伤筋动骨但部分接口的调用方式确实有调整凭空增加不少适配工作量。我自己的主力环境用的是某个长期支持的稳定版本配套的SDK版本也固定在某个大版本上工程不会动不动就报SDK不兼容的错。你可能会遇到DevEco Studio提示SDK组件未安装这时候直接在Tools菜单里的SDK Manager里勾选下载就行网络条件不好的话切换镜像源能快不少。1.2 工程目录结构到底该怎么理解新建一个Stage模型工程后你会看到一堆目录第一次打开真的会有点懵。这里我按功能帮你理一理AppScope存放应用级配置比如app.json5里面定义了应用的包名、版本号、图标等基础信息。entry模块目录可以理解为应用的主入口模块。entry/src/main/ets放ArkTS源代码的地方里面会按entryability、pages等子目录组织代码。entry/src/main/resources资源目录字符串、颜色、图片等资源都放这里注意目录的命名规则比如base和en_US这种限定词目录不能搞错。build-profile.json5模块级构建配置你引用的依赖、签名信息都在这里声明。很多教程会直接让你在pages下面新建页面但你最好先搞清楚entryability里的onPageStart或者路由配置怎么指向你的第一个页面不然页面建好了却不知道入口在哪那才叫一个头疼。1.3 模拟器与真机的选择策略我的实操经验是日常逻辑调试用模拟器涉及传感器、性能、或者需要和服务端做复杂交互的场景尽早换真机。模拟器启动快、环境干净适合快速验证UI布局和基础逻辑。但它的性能模拟和真机还是有差距尤其是渲染复杂动画或者处理大图时。真机调试需要先申请签名证书在DevEco Studio里配置好之后用USB连接就能直接跑。这个过程看起来要多几步但长远来说收益很大因为很多问题只有真机上才能复现比如某些权限弹窗的时机、弱网环境下的表现等。在这里提醒一句模拟器上测试网络请求时访问localhost指的是模拟器自身而不是你的开发机。如果你服务端跑在本地要访问你的开发机IP并且得确认防火墙没有拦截端口。2. 核心开发语言与UI框架ArkTS与声明式UI2.1 ArkTS语言上手别被“TS超集”这几个字骗了ArkTS确实是基于TypeScript的但它做了不少约束。你知道最坑的是什么吗它不支持any类型对严格模式有强制要求。所有变量的类型在编译期就必须明确下来这对习惯了动态类型的人来说初期会有点难受。我实际写下来的感觉是你最好把TypeScript的优雅特性联合类型、泛型、接口用扎实很快就能适应ArkTS的节奏。官方文档里的语法规范读一遍值回票价尤其是那些标注为“ArkTS限制使用”的部分比如不能用in运算符、不能用with语句等等。这不是说这些特性不能用而是为了保证运行时性能和安全性语言层面直接禁了。举个例子早期我在代码里写了一个简单的工具函数返回一个对象其中有个字段可能不存在。在普通TypeScript里你可能会用可选链(?.)和空值合并(??)来处理空值问题但ArkTS里常见的做法是用联合类型显式声明字段可能为undefined然后在逻辑层做好分支判断。这样虽然代码多写几行但类型安全性和可维护性确实大幅提升。2.2 声明式UI开发范式从命令式思维中跳出来在鸿蒙开发里你写的不是“怎么一步步画出UI”而是“UI在某个状态下长什么样”。这就像你用PS是一张图一张图地调但用CSS是一个样式规则适配所有情况思维模式完全不同。你只需要记住三个核心概念后面的路就顺了状态驱动用State修饰的变量一旦值发生变化绑定该变量的UI组件就会自动刷新。组件化把页面拆成一个个自定义组件每个组件管理自己的状态通过Prop、Link等装饰器接收父组件的参数传递。条件渲染与循环渲染用if/else处理动态显示用ForEach处理列表类数据渲染。我在最初写自定义组件时犯过一个典型错误把一个比较复杂的业务逻辑直接塞进了组件的aboutToAppear生命周期里导致状态还没就绪就去访问UI组件属性直接报错。正确的做法是状态初始化和业务逻辑尽早解耦组件属性相关的操作尽量放到onReady或首次渲染完成之后再执行。2.3 常见UI组件使用细节Scroll、List、TextInput等基础的Text、Button、Image这些组件用法和别的框架差不多重点讲几个含金量高的Scroll组件你给它固定高度后内容超长会自动滚动这没问题。但如果在Scroll里再嵌套一个List或者Grid滚动冲突就会冒出来。我试过的有效方案是内层组件关闭滚动嵌套设置nestedScroll相关属性或者干脆将内层组件换成ForEach平铺。TextInput除了常规的placeholder、text绑定建议每次在输入事件里做一次输入值格式化比如限制纯数字输入避免到业务层再花力气清洗数据。List/Grid需要展示长列表时记得设置LazyForEach或者开启数据懒加载否则列表元素一多首帧渲染时间直接飙升用户看着白屏只好杀掉App。2.4 状态管理别把所有东西都塞进State很多从其他框架转过来的朋友习惯把所有变化的值都用State怼上去后面代码就乱了。实际上鸿蒙提供了更精细的层级设计State组件内部状态。Prop从父组件单向传入的初始化值。Link实现父子组件双向绑定。Provide和**Consume**跨层级比如祖父和孙组件共享状态。AppStorage应用级状态类似于全局变量但更规范。选型其实非常简单谁需要用这个状态就离谁最近的地方定义它。我个人倾向把网络请求的数据放到页面级别的State里而一些跟设备交互、需要跨页面同步的数据比如实时电量信息、用户登录态等放到AppStorage统一管理。这样既不会过度设计也不会让数据流混乱。3. 多模块协同与生命周期管理3.1 UIAbility生命周期要背下来如果你做过Android开发对Activity的生命周期肯定很熟。鸿蒙的UIAbility生命周期与它有相似之处但有些地方完全别着来。核心无外乎这几个回调onCreate、onWindowStageCreate、onForeground、onBackground、onDestroy。业务上你要注意的几点次启动冷启动时onCreate必定被调用但从后台回前台时只会触发onForeground。不要在这两个回调里重复写初始化逻辑。参数获取onCreate里拿到的Want对象类似Android的Intent可以在冷启动时解析参数。但热启动时你可能会在onNewWant回调里拿到最新的参数记得两个入口都要处理。后台限制应用在后台时不要做大量CPU密集任务系统会限制资源严重的直接给你杀掉。3.2 页面路由与跨模块跳转程序员最烦的就是各种跳转和传参问题。鸿蒙页面跳转核心有两种方式Navigation推荐的方式适合应用内的复杂导航支持页面栈管理也支持转场动画。router轻量级的页面路由适合简单的页面替换和URL传参。我自己习惯在模块内部使用Navigation管理子页面模块间的跳转统一抽成一个路由管理工具类传入目标页面名称和参数由工具类统一处理。这样做的好处是页面间解耦以后修改跳转路径时不需要改每个页面里的硬编码路由。这里有个小细节路由跳转传参时参数对象尽量保持扁平化别嵌套太深。你序列化的数据过大解析耗时会增加而且出Bug时排查也困难。3.3 线程模型与任务分发UI主线程负责所有渲染和用户交互绝对不能做耗时操作。我见过有开发者在点击事件里直接做图片压缩结果整个页面卡住不动两三秒后才弹出来结果体验极差。鸿蒙提供了一系列并发能力TaskPool适合CPU密集任务比如图片处理、数据解析。Worker适合长时间运行的独立任务比如大的文件读写。异步回调/Promise适合网络请求和数据库操作等IO密集型任务。实操中我习惯把耗时超过100ms的任务都丢给异步或者TaskPool处理。使用TaskPool时需要在任务中传递的数据必须支持序列化这对一些复杂自定义类型不太友好建议传值类型的对象或者轻量的JSON字符串。4. 调试与发布全流程从擦屁股到上架4.1 基础调试技巧与日志定位一旦开发起来你肯定离不开日志。普通的console.log打印在鸿蒙里也能用但建议尽早用上hiLog。它能按级别debug/info/warn/error过滤日志还可以带业务标签多模块协同开发时按标签过滤日志的效率会高很多。日志也不是越多越好生产环境注意别把敏感信息打出来。Debug真机上查看日志时DevEco Studio自带的Log窗口已经够用但你做系统级调试比如看崩溃信息时用命令行工具hdc去抓全量日志会更清晰。4.2 崩溃分析与问题定位崩溃日志是排查问题的第一手线索。鸿蒙应用崩溃后日志里通常会带一个调用栈和对应的行号。根据行号你就能定位到出错的代码位置。但有一种情况是崩溃发生在系统框架层光看调用栈是不明不白的这时候建议按下面的思路排查先看日志前200行找是否有自定义的业务日志确定崩溃前最后执行的代码在做什么。检查内存使用情况尤其时大图加载和列表滚动场景这类问题多半是内存陡增打爆了。查看是否有资源找不到的问题比如图片资源名称拼写错误、字符串键值没有适配全语言包。4.3 签名、证书与上架审核的硬核细节应用构建出来还只是一个安装包想上真机测试和发布到应用市场就必须做签名。签名信息可以在DevEco Studio界面上配置但我还是建议手写那套.p12、.cer、.p7b文件对应的配置项理解得更透。调试证书用于DevEco Studio直接运行到真机申请快但有效期半年几个月不等到期需要重新生成。发布证书用于构建正式包上架申请流程严格有效期时间更长。真机上每次调试时自动签名配好之后DevEco Studio会帮你把调试证书装到手机里。这里有一个容易踩的坑如果项目里用到了系统高级权限比如某些特定API调试证书默认是不带这些权限的你必须额外申请对应权限白名单否则运行时直接鉴权失败。另外说句上架审核方面的体会隐私政策、权限声明、用户协议这三样一定要提前准备。审核人员最介意的不是你代码多复杂而是你申请的权限跟你实际的业务场景是否匹配。位置权限拿来做天气App是完全没问题的但你一个手电筒应用也申请通讯录那就等着被拒吧。5. 我收藏的几条避坑原则这里再给你补充几条我认为价值极高的原则性建议都是多次踩坑之后提炼出来的不要在项目初期就疯狂引入第三方依赖库。鸿蒙生态虽然成熟了不少但很多第三方库的版本兼容性还有待验证。非必要不引入引入之前先在真实工程里跑通一个Demo。做好日志分级上线版本关掉调试日志。尤其是包含网络数据或敏感信息的日志一旦上了生产环境随时都是隐患。备份配置文件记录签名文件的密码和有效期。真的很多人因为忘记证书密码卡在上架前最后一步。UI自动化测试尽量早介入。鸿蒙官方提供的测试框架已经比较完善日常开发虽然不一定跑全量用例但核心路径回归测试一定要做。性能优化要前置不要等到卡得不行才回头优化列表渲染和图片加载缓存。我自己的开发习惯是每天下班前把当天的编译报错和排查过程整理进自己的小巧备忘录一个月下来回头看就是一份非常有价值的项目经验。很多问题你当时觉得不可能再遇到结果三个月后又会有新人踩进同一个坑那时你这份备忘录就成了团队的救命文档。6. 最后一个实用技巧快速排查页面布局异常写UI最烦的就是布局错乱。新写的某个页面在模拟器里看着挺正常一跑到真机上就出现元素重叠、控件被拉伸的情况这个问题几乎人人都会遇到。我的排查技巧很简单先把可疑区域背景颜色调成半透明的对比色或者加临时border边框一眼就能看出内容区域实际的大小和位置。这种方式比盯着布局属性猜快得多。你可以在代码里加一条临时代码比如.backgroundColor(rgba(255,0,0,0.3))调试完再删掉。还有一种常见情况是自定义组件的尺寸设置不正确明明内容只有一点点组件却占了一大块空白区域。解决办法就是检查父容器、子组件各自的宽高约束以及flexShrink、flexGrow这类弹性布局属性的设置方式绝大多数错乱原因都逃不开这几个参数。说实话鸿蒙开发刚开始的门槛主要不是难而是新。新的语言规范、新的开发范式、新的工具链很多以前几十年的经验不能直接套用得换个思路重新理解。但换个角度想这其实也是一件有意思的事把注意力从“搬运代码”拉回到“理解系统”本身很多思考方式都会更新换代。我在实际调试中感受最深的是遇到问题不要急着找现成的代码片段先花10分钟翻一翻官方文档搞懂接口的预期行为和底层限制往往比盲目复制别人的代码高效太多。希望这份备忘录对你有点用也欢迎你有自己的心得后再回头来和我聊聊。
阅读完成 · 觉得有帮助?