决定用 DevEco CLI 这条命令行路线把一款鸿蒙 App 完整做出来并且最终推到应用市场上架这个想法最初来自一个很普通的场景我家孩子每天放学后要完成的几件小事刷牙、整理书包、看绘本、早睡总得追着提醒催多了孩子烦我也累。于是我想不如干脆自己写一个日程打卡类的鸿蒙小应用名字就叫「宝贝日程表」让孩子自己对着手机完成任务打卡。真正动手之后才发现在纯血鸿蒙的工程体系下从命令行建工程、写 ArkTS 页面、真机调式、打包签名到提交审核上架整个过程踩的坑比预想的多得多。这篇文章就把我完整复刻这条开发链路的过程记录下来包括每一步的选型理由、命令细节、报错排查和上架前必须准备的材料给正在做鸿蒙应用的朋友一个可以直接参考的实战样本。1. 为什么一个日程表项目最终选择用 DevEco CLI 硬啃到底这个项目最开始的计划很简单在 DevEco Studio 里用可视化向导新建一个工程拖拖拽拽写几个页面打包出来安装到手机上就完事。但做到一半我发现用图形界面建工程有两个问题让后续开发非常难受一个是工程参数一旦生成后再去改包名、改签名配置要通过好几层界面操作容易漏另一个是我习惯在多个设备间切换工作甚至偶尔想直接扔到 CI 服务器上做自动化打包这时候图形界面完全帮不上忙。所以这个项目起手的位置就不是 IDE而是 DevEco CLI——也就是鸿蒙官方提供的命令行工具链。它能把工程初始化、依赖安装、编译构建、签名打包、安装调试这一整条链路都用命令驱动起来整个过程可脚本化、可记录、可复现也能和其他自动化流程串起来。1.1 图形界面能做的事命令行真正做到多少先说结论DevEco CLI 的能力覆盖度比大部分人的第一印象要强。它可以做这样几件事创建完整工程、添加模块、安装 ohpm 依赖包、执行构建任务、管理签名信息以及通过 hdc 工具安装应用到模拟器或真机。我这次实际用下来发现日常开发里 90% 的工作都不需要打开 DevEco Studio 就能完成真正需要回到 IDE 的场景只剩下两个写 ArkTS 页面代码时想要实时的语法检查和 UI 预览以及查看崩溃日志里比较复杂的调用栈。CLI 对这两块的体验确实不如 IDE但项目代码本来就需要一个顺手趁手的编辑器来写我用的是 VS Code 加 ArkTS 语言插件勉强够用。1.2 从空目录到 hap 产物的真实命令序列DevEco CLI 在安装 DevEco Studio 之后就已经可以用了命令行入口一般位于安装目录的 bin 目录下。新建一个项目的最简命令是devecocli create后面跟上模板类型、包名和项目名称。我实际执行的是类似这样的命令devecocli create -t app -p com.example.babyschedule BabySchedule这里-t app表示创建一个标准的 Stage 模型应用工程-p指定包名最后是项目名。执行完之后目录结构会是 entry 模块加 AppScope 的标准形态。如果你是第一次用可能会卡在模板选项上因为 CLI 支持的模板比较多常见的有app、library和server分别对应应用、HAR 静态共享库和 Hsp 动态共享库。我的项目里主工程就是一个 app 模板因为没打算拆成多包复用后面也没有新增 library 模块的必要。2. 宝贝日程表的工程骨架与数据模型设计工程创建好之后先别急着写页面我建议先用十分钟把工程目录结构和配置文件的含义弄清楚免得后面模块配置改来改去都不知道自己在改什么。Stage 模型下最重要的几个位置是 AppScope/app.json5、entry/src/main/module.json5以及 entry/build-profile.json5它们分别对应全局应用配置、模块级声明和构建签名相关配置。像应用名称、图标、版本号这类信息如果直接在 IDE 里操作就是在 app.json5 和 module.json5 里来回改用命令行的时候就只能手动编辑这些 JSON 文件了。2.1 ArkTS 状态管理项目里用到的 State、Prop、Link、Observed宝贝日程表主要的功能是展示每日任务列表、记录打卡状态、切换日期查看历史记录。在 ArkTS 里最核心的就是状态驱动 UI 更新这套机制。我在项目里用到了四个装饰器页面内部状态用的State父组件向子组件传值用Prop子组件反向操作父组件数据用Link跨组件共享那一份会被修改的对象则用Observed配合ObjectLink。实际经验是用State的优先级最高能用它解决的就别引入更复杂的联动关系否则一个小页面传参链会把你绕晕。代码里的任务模型大概是这样的Observed export class TaskItem { id: number 0; title: string ; isDone: boolean false; targetTime: string 20:00; constructor(id: number, title: string, targetTime: string) { this.id id; this.title title; this.targetTime targetTime; } }日期页签和任务列表组件之间的传值就是典型的State加Prop组合。首页持有当前选中日期字符串传给子组件做过滤展示子组件只读不改。打卡按钮状态翻转则用Link把父组件里的任务数组引用传下去子组件里直接修改task.isDone界面就会同步刷新。这套组合在 ArkTS 的 Stage 模型下是最高频的写法之一理解了这四种装饰器很多页面逻辑都能往这个模式上套。2.2 日历核心算法不依赖第三方库的纯本地实现因为宝贝日程表本身不联网也没接任何后端服务日历数据完全由本地计算。月份天数、当月第一天是星期几、闰年判断这些逻辑都是自己写工具函数实现的。这类通用算法其实并不难真正要注意的是跨月切换时状态的一致性。我封装了一个 CalendarUtil 工具类输入年月返回当月日期网格二维数组同时提供getTodayString()返回yyyy-MM-dd格式的字符串用于高亮今天。最开始我踩过一个逻辑坑把数组索引当成星期值用导致日期偏移了一天。原因是Date.getDay()返回的星期日是 0而我习惯把星期一排在第 0 列两者对不上。后来统一在 CalendarUtil 里做了一次转换把周日当成每列的最后一天处理问题就解决了。类似这种边界值问题在写工具类的时候特别容易埋雷建议写完立刻写测试用例验证别偷懒。2.3 数据持久化方案Preferences 与关系型数据库的选择任务清单和打卡记录都需要在 App 杀掉之后保留下来所以必须做本地持久化。鸿蒙提供的数据持久化方案有两类比较常用首选项 Preferences 适合存键值对关系型数据库 RDB 适合存结构化表格数据。宝贝日程表里任务列表适合用 RDB打卡记录也可以按日期存成一张表。不过我的需求实在不算复杂总共就二三十条任务和每天对应的打卡状态最后我选择了更轻量的一种方式用 Preferences 存整个 JSON 字符串日期字符串作为 key对应当天的任务打卡状态数组就序列化存进去。这样做的优势在于实现简单启动时一次性读出来内存里自己维护一份全量数据写完就序列化回写不用担心数据库版本迁移和 SQL 语句问题。缺点是数据量大了以后读写效率会变差但日程表这种轻量工具类应用完全在承受范围内。如果你做的是数据量较大的应用我建议还是要认真用 RDB把表和索引的设计做在前面。3. 真机调试与模拟器体验从 hdc 到 DevEco Studio 的拉扯开发阶段最影响幸福感的环节就是调试。鸿蒙提供的调试方式有三种本地模拟器、远程模拟器和真机。这个项目里我三种都试过踩了不少坑尤其是模拟器在启动速度和架构一致性上的表现会直接影响你排查问题的效率。3.1 模拟器与真机差异手势、定位、后台行为模拟器最大的优势是启动方便尤其是看 UI 布局的时候。但宝贝日程表有这么几个问题在模拟器上很难暴露第一是通知权限弹窗时机模拟器里系统服务不太一样弹窗表现和真机有偏差第二是电池优化和后台运行限制真机上如果用户把 App 加入了省电白名单或者限制后台定时提醒这类功能可能就直接失效了这个问题在模拟器上基本复现不出来第三是触摸反馈儿童用的 App 按钮一般都做得比较大但手指在真机上的滑动摩擦感和模拟器鼠标操作完全是两回事。所以我的结论是模拟器适合看 UI真机才是排查功能和性能问题的唯一标准。3.2 USB 调试授权那个“坑”和 hdc 常用命令真机调试之前必须在开发者选项里打开 USB 调试这个大家应该都知道了。但有一个坑可能第一次接触的人都会遇到手机插上数据线后执行hdc list targets能看到设备可一旦执行hdc install却提示 fail而且不报任何具体原因。排查到最后发现是手机上的调试授权弹窗没有点掉USB 连接后系统会弹出“允许 USB 调试吗”的确认框不点允许或者那次误点了“仅充电”模式后续所有调试命令都会失败。hdc 的常用命令我列一下方便直接抄hdc list targets # 查看当前连接的设备 hdc install path/to/app.hap # 安装应用 hdc uninstall com.example.babyschedule # 卸载应用 hdc shell aa start -b com.example.babyschedule -a EntryAbility # 启动应用 hdc file send local remote # 推送文件到设备 hdc hilog # 查看设备日志3.3 日志排查hilog 里我最后悔没早做的事应用崩溃或者逻辑不对的时候我习惯先在 hilog 里过滤关键词来找线索。最开始我是直接hdc hilog全量输出结果日志刷屏刷得根本没法看。后来才学会先hdc shell hilog -x清除旧日志再带| grep去过滤自己应用的 tag。鸿蒙的日志分级和 Android 不太一样常见的有 DEBUG、INFO、WARN、ERROR 和 FATAL。我自己的排查习惯是先看 FATAL 再往上翻 ERROR并且优先处理带ArkTS前缀的报错因为 ArkTS 层抛出的异常往往直接指向代码里出错的那一行。4. 打包与签名hap、hsp、har 三种产物到底怎么选开发调试阶段用的是自动签名也就是 DevEco Studio 自动帮你生成调试证书安装到测试机上没问题。但准备上架时必须手动处理正式签名还要理解鸿蒙工程构建出来的几种产物格式项目本身越复杂这一步越绕不过去。4.1 hap、hsp、har 的区别和适用场景先说最核心的概念。HAP 是应用安装包也就是最终要装到用户设备上的东西一个 App 可以包含一个或多个 HAP 模块。HAR 是静态共享库可以理解成传统意义上的库里面的代码和资源会被打包进引用它的 HAP 中一般用来抽取公共组件和工具方法。HSP 是动态共享库它不会打进 HAP 里而是等 App 运行到需要时再加载适合做按需加载的模块或独立大功能包。我这个项目的规模不大结构上就只有一个 entry 模块所以最终产物就是一个单独的 HAP。但如果你在做一个多模块应用比如首页、商城、设置各自想分开构建那就得考虑 HAP 分包或者 HSP 的动态加载了。我建议这样选择纯工具类代码抽成 HAR业务量较大且需要独立迭代的模块用 HSP主入口保持轻量目录清晰可维护性也高。4.2 从调试签名到正式签名证书、Profile、密钥库三件套正式签名需要三样东西证书文件.cer、Profile 文件.p7b和密钥库文件.p12。这三样需要在鸿蒙应用生态平台申请和生成。证书的逻辑是先用 KeyStore Explorer 或者命令行生成密钥对上传公钥信息获取证书然后把证书和 App 信息关联生成 ProfileProfile 里记录了这个包能使用的权限、能安装的设备范围等等。拿到三件套之后要在 entry/build-profile.json5 里的 signingConfigs 节点里配好。这里有一个非常容易忽略的点签名信息的name必须和证书文件里的信息保持一致否则构建时直接报签名校验失败。我在测试流程里就因为签名 name 写错了反反复复去检查 keystore 密码和别名浪费了两个小时。后来学乖了每次从命令行打包之前统一跑一遍构建脚本签名的流程完全由脚本接管基本不会再出现手滑填错配置的情况。4.3 自动化构建脚本让 hap 生成只在一行命令之间日常开发时可以在 IDE 里点按钮构建但到了准备 Release 包的时候我强烈推荐用命令行。鸿蒙工程的命令行构建入口是项目根目录下的 hvigorw 脚本配合 Deveco CLI 一起用只需要执行./hvigorw assembleHap --mode module -p productdefault -p buildModerelease第一次跑这个命令之前要先装好依赖ohpm install需要在工程根目录执行一次对应的是 HarmonyOS 的包管理工具。构建成功后 hap 会输出到entry/build/default/outputs/default/下。我写了一个简单的 shell 脚本把这些命令串起来每次提交版本只需要改版本号然后执行一次既省时间又保证每次都走同样的构建逻辑。这里建议大家把生成的签名参数从命令行传入而不要平铺写在配置里这样可以把密钥文件单独保护起来不会因为工程提交到仓库导致签名信息泄露。5. 上架前的最后准备版本审核自查清单与可能要踩的坑应用开发到功能完整了不代表就能顺利上架。上架前有大量以审核视角来审视应用的琐碎工作。审核过程很在意权限申请的合理性、隐私政策的完整性以及应用本身是否包含违规内容。宝贝日程表这个项目因为不涉及用户账号体系不采集任何个人信息隐私风险相对较低但反而有一个坑比较隐蔽儿童类应用的年龄分级和说明。5.1 年龄分级与隐私政策儿童应用躲不开的合规话题鸿蒙应用市场要求开发者在上架时提供详细的年龄分级信息如果应用是面向儿童的审核会特别关注是否包含广告、是否有外部链接、是否包含社交功能、是否含有内购。宝贝日程表是做儿童习惯养成的工具我老老实实选择了全年龄级别同时在隐私政策里明确写了应用不收集任何个人信息、不需要网络权限。这一步看似无关紧要但审核人员真的会逐条核对你在权限声明里多申请了一个用不上的权限就多一分被拒的风险。配套材料方面还需要准备应用图标、不同尺寸的宣传图、4 到 8 张功能截图、一句话简介和较长的应用描述。截图要真实反映界面Android 上架的开发者都懂那种截图和实际进入后长得不一样会被驳回的痛鸿蒙这边审核尺度只会更严所以我没有做任何虚化或拼接操作直接截真机画面提交。5.2 版本与权限声明最容易忽略的三个细节第一是版本号不能乱填主版本号、次版本号和修订号的递增规则要符合平台规范不能出现上个版本是 1.0.0下个版本直接跳到 1.2.0 这种不合理跳变。第二是权限列表需要和代码实际申请保持一致比如我一开始在 module.json5 里声明了位置权限但代码根本没用后来排查排掉了。第三是应用市场里填写的应用所支持的设备范围要和自己测试过的设备型号对照填写别图省事直接全选万一用户设备上跑不起来投诉率高了会影响账号信誉。5.3 从测试版到正式上架的整体时间线参考如果准备顺利提交审核到最后通过通常需要一到三个工作日。我第一次提交的时候因为隐私政策链接填写不规范被打回了一次改完之后重新提审又等了大半天。所以我的建议是把上架准备细化成一份清单提前检查齐全再点提交不要抱有先提交试试、被打回再改的心态一次过对你账号后续的权限有好处。6. 后续优化方向与对这个技术栈的几点真实感受宝贝日程表上架之后我后续计划做三个方向的小迭代一个是把通知提醒真正做好鸿蒙系统里的通知渠道需要在通知管理里注册并让用户授权这块的体验直接决定这类工具应用的用户留存另一个是桌面卡片鸿蒙的桌面卡片框架可以把今天的任务列表直接展现在桌面上长按就能打卡这种“免打开”的轻交互非常契合宝贝日程表的使用场景第三个是给打卡数据做周统计和月统计画个简单的趋势图让家长能够在每周日晚上清晰看到孩子这一周的执行情况。最后聊一点个人真实感受。鸿蒙的开发工具链这两年进步确实非常明显但从命令行角度去用它的生态还不算特别完善很多资料分散在官方文档和论坛里碰到报错想搜一个现成的答案并不容易。但换个角度看正因为如此把这个技术栈吃透之后能建立很深的护城河——市面上真正能从devecocli create一路写到hvigorw assembleHap再完成上架的人还不多而这套全链路能力恰恰是跨团队做工程化建设最需要的。做宝贝日程表这半个多月我的收获不只是一款应用更是把自己从 IDE 图形化操作的舒适区里拽出来重新理解了鸿蒙工程从源码到交付的每一个环节。