首页 / 资讯中心 / 文章详情

从CLI到上架:用DevEco CLI构建鸿蒙日程App全流程实战

从CLI到上架:用DevEco CLI构建鸿蒙日程App全流程实战 ★ FEATURED ARTICLE
1. 为什么做这个「宝贝日程表」作为一个长期在鸿蒙生态里折腾应用的开发者我一直在找一个合适的练手项目。市面上大多是记账、天气、待办清单总感觉缺少一点“温度”。家里有娃之后每天被“明天要带手工作品”“周三有游泳课”“周五打疫苗”这些事追着跑纸质便签贴满冰箱手机备忘录翻半天才找到对应日期。于是就有了这个想法用 DevEco CLI 从零写一个专门给家长和小朋友用的日程管理 App名字就叫「宝贝日程表」。这篇博文会完整记录我从设计到上架的整个流程涵盖 DevEco CLI 的命令行操作、ArkTS 页面开发、hvigor 构建打包、签名配置、AGC 上传审核等全部环节。不管你是刚接触鸿蒙开发的新手还是已经用 DevEco Studio 写过几个 Demo 但没走完上架全流程的开发者都能从里面找到可以直接抄作业的命令和配置。「宝贝日程表」解决的核心问题很简单用孩子的视角管理日程。传统日历工具对学龄前儿童太抽象对家长又太繁琐。我把日程分成“今天、明天、本周、自定义日期”几个维度每条日程配上 emoji 图标和颜色标签孩子一看就懂家长一键录入。技术上它涉及鸿蒙应用的典型功能集合数据持久化、日历计算、本地通知、多页面导航、深浅色适配麻雀虽小五脏俱全非常适合作为学习鸿蒙开发的完整样例。2. 开发前的技术选型与整体设计2.1 为什么要用 DevEco CLI 而不是纯 IDE很多新手接触鸿蒙开发打开 DevEco Studio 就是一顿图形化操作点按钮创建项目点按钮运行点按钮打包。这套流程当然没问题但有个隐患你不太清楚背后执行了什么。DevEco CLI命令行工具则是把工程创建、依赖安装、编译构建、签名打包这些动作全部变成了可复现、可脚本化的命令对后续持续集成、自动化发布特别有利。我选择 DevEco CLI 作为主力还有一个实际原因我经常需要在多台机器之间切换开发环境IDE 的图形化配置没法直接同步但命令行的hvigorw、ohpm、hdc配合一份package.json和一个build-profile.json5就能把整个工程的环境依赖完整复刻。说得直白点CLI 让开发流程变成了“配置即代码”这才是工程化的第一步。DevEco CLI 底层依赖的核心命令工具链有三个hvigorw负责构建任务类似前端的 webpackohpm负责包管理类似 npmhdc负责设备连接和调试类似 adb。整篇实战里都会围绕这三个命令展开。2.2 功能模块拆解与数据模型设计「宝贝日程表」的功能不要贪多我在第一版只规划了四个核心模块日程日历按月展示日期在日期上标记有没有日程。日程列表按天分组展示日程支持新增、编辑、滑动删除。提醒通知每条日程可设置提前提醒时间通过本地通知推送。我的与设置包含头像昵称、提醒偏好、深浅色切换。数据模型上日程表的核心实体是ScheduleItem字段设计直接决定后面开发顺不顺。我采用的是interface ScheduleItem { id: string; // 主键用 Date.now() 随机数生成 title: string; // 日程标题 emoji: string; // 图标 喂奶、 上学、 疫苗、 兴趣班 color: string; // 标签颜色日历上显示用 date: string; // 日期 yyyy-MM-dd startTime: string; // 开始时间 HH:mm endTime: string; // 结束时间 HH:mm reminderMinutes: number; // 提前多少分钟提醒0 表示不提醒 note: string; // 备注 createdAt: number; // 创建时间戳 updatedAt: number; // 更新时间戳 }存储方案我选择了 RelationalStore关系型数据库这是鸿蒙原生提供的 SQLite 封装性能稳定支持索引和复杂查询。初期数据量不大用 Preferences键值对也能实现但后期如果要做周视图统计、月度报表SQL 查询会更方便。开发中强烈建议一次到位避免数据迁移的麻烦。2.3 技术栈与依赖包规划工程使用的关键技术栈如下语言ArkTSTypeScript 的超集语法基本一致但取消了any类型强制静态类型。UI 框架ArkUI 声明式开发范式用Component、State、Builder等装饰器组织页面。数据库ohos.data.relationalStore。通知ohos.notificationManager。路由ohos.router。工具库kit.PerformanceAnalysisKit调优用、dayjs通过 ohpm 安装日期计算神器。依赖规划上dayjs不是鸿蒙内置的需要用ohpm install dayjs引入。官方仓库里能搜到很多优质三方库类似前端的 npm registry直接命令行安装即可不需要手动去官网下载文件。3. 环境准备与 CLI 初始化3.1 开发环境版本选择这个项目的构建环境是一套比较标准的配置操作系统Windows 11 / macOS 14 均可下面的命令在两个系统下通用。DevEco Studio5.0.0 及以上版本里面自带 SDK、命令行工具链。HarmonyOS SDKAPI 12 或更高版本。Node.js18.x 及以上ohpm 依赖 Node 运行时。华为账号用于 AGC 平台创建应用和签名。有个细节要特别提醒DevEco CLI 并不是一个独立安装的工具它随 DevEco Studio 一起分发。安装完 DevEco Studio 后在安装目录的command-line-tools文件夹下能找到所有 CLI 工具的二进制文件需要手动配置到系统环境变量里。macOS 下的环境变量配置示例export DEVECO_SDK_HOME/Applications/DevEco-Studio.app/Contents/sdk export PATH$PATH:/Applications/DevEco-Studio.app/Contents/tools/ohpm/bin export PATH$PATH:/Applications/DevEco-Studio.app/Contents/tools/hvigor/bin export PATH$PATH:/Applications/DevEco-Studio.app/Contents/tools/hdc/bin配置完成后在终端输入hvigorw --version、ohpm --version、hdc --version都能正确输出版本号说明环境就绪。3.2 使用 CLI 创建工程初始化工程用的是命令hvigorw init它可以基于模板快速生成一个标准工程骨架。执行后终端会交互式询问工程名称、包名、支持的设备类型等信息。我的输入大概是下面这样hvigorw init --name BabySchedule --namespace com.example.babyschedule --module-type entry执行完成后会生成一个标准的 HarmonyOS 工程主要目录结构如下BabySchedule/ ├── AppScope/ │ ├── app.json5 # 应用级配置图标、标签、权限声明 │ └── resources/ # 应用级资源 ├── entry/ │ ├── src/main/ │ │ ├── ets/ # ArkTS 源码目录 │ │ │ ├── entryability/ │ │ │ ├── pages/ # 页面文件 │ │ │ └── model/ # 数据模型与数据操作类 │ │ ├── resources/ # 模块级资源 │ │ └── module.json5 # 模块配置页面路由、权限 │ └── build-profile.json5 # 构建配置签名、混淆选项 ├── oh-package.json5 # 依赖管理文件 ├── build-profile.json5 # 工程级构建配置 └── hvigorfile.ts # 构建脚本入口用命令行创建工程和用 IDE 向导创建工程最终生成的目录是一模一样的所以 CLI 完全不会限制后续的图形化开发。想换回 IDE 写代码直接用 DevEco Studio 打开这个文件夹就行。3.3 安装三方依赖工程初始化后第一件事是把依赖装上。除了内建模块外我额外用到了日期处理库dayjs。用 ohpm 安装ohpm install dayjs国内网络环境下ohpm 默认走的华为仓库一般速度不错。如果遇到下载超时可以检查一下.ohpmrc文件里的 registry 配置确认指向的是官方镜像地址。安装完成后oh-package.json5里会自动写入依赖{ name: BabySchedule, version: 1.0.0, dependencies: { dayjs: ^1.11.10 } }这一刻开始「宝贝日程表」的前期准备工作就全部就绪可以开始写第一行业务代码了。4. 核心功能实现从日历到提醒4.1 数据持久化封装 RelationalStore 操作在写页面之前我习惯先把数据层搞定。RelationalStore 的 API 是异步的所以我在model/ScheduleDatabase.ts里封装了一个类把所有数据库操作集中管理避免页面代码里到处写 SQL。核心实现如下import { relationalStore } from kit.ArkData; import { common } from kit.AbilityKit; const DB_NAME baby_schedule.db; const TABLE_NAME schedule_item; export class ScheduleDatabase { private store: relationalStore.RdbStore | null null; async init(context: common.UIAbilityContext) { const config: relationalStore.StoreConfig { name: DB_NAME, securityLevel: relationalStore.SecurityLevel.S1 }; this.store await relationalStore.getRdbStore(context, config); await this.createTable(); } private async createTable() { const sql CREATE TABLE IF NOT EXISTS ${TABLE_NAME} ( id TEXT PRIMARY KEY, title TEXT NOT NULL, emoji TEXT, color TEXT, date TEXT NOT NULL, start_time TEXT, end_time TEXT, reminder_minutes INTEGER DEFAULT 0, note TEXT, created_at INTEGER, updated_at INTEGER ); await this.store?.executeSql(sql); } async insert(item: ScheduleItem): Promisenumber { const values new relationalStore.ValuesBucket(); values.id item.id; values.title item.title; values.emoji item.emoji; values.color item.color; values.date item.date; values.start_time item.startTime; values.end_time item.endTime; values.reminder_minutes item.reminderMinutes; values.note item.note; values.created_at item.createdAt; values.updated_at item.updatedAt; return await this.store!.insert(TABLE_NAME, values); } }几个值得注意的细节securityLevel设置成S1就够了应用私有数据级别不需要更高的安全级别这会影响数据库文件在设备上的加密程度。ValuesBucket的 key 必须和表结构的字段名保持一致否则插入直接失败这个坑我踩过报错信息还不清晰排查了好久。所有数据库操作都是异步的在页面里调用时记得用await。查询某一天日程的时候我用了 SQL 的date字段精确匹配速度非常快async queryByDate(date: string): PromiseScheduleItem[] { const predicates new relationalStore.RdbPredicates(TABLE_NAME); predicates.equalTo(date, date); predicates.orderByDesc(start_time); const resultSet await this.store!.query(predicates); // 遍历 resultSet 转成 ScheduleItem 数组 }4.2 日历视图月历生成与日程标记日历组件是「宝贝日程表」的门面。鸿蒙生态有不少三方日历组件但为了完全掌控样式和交互我还是选择自己写。核心思路是把一个月的日期数据生成一个DateInfo[]数组数组元素包含年、月、日、是否本月、是否有日程、选中状态等字段。生成逻辑用dayjs可以写得很优雅function generateMonthMatrix(year: number, month: number): DateInfo[] { const firstDay dayjs(${year}-${month}-01); const startWeekday firstDay.day(); // 0周日6周六 const daysInMonth firstDay.daysInMonth(); const cells: DateInfo[] []; // 补充上月末尾日期 for (let i startWeekday - 1; i 0; i--) { const d firstDay.subtract(i 1, day); cells.push({ year: d.year(), month: d.month() 1, date: d.date(), inMonth: false }); } // 本月全部日期 for (let day 1; day daysInMonth; day) { cells.push({ year, month, date: day, inMonth: true }); } // 补足到 6 行 7 列保持布局稳定 while (cells.length % 7 ! 0) { const last cells[cells.length - 1]; const d dayjs(${last.year}-${last.month}-${last.date}).add(1, day); cells.push({ year: d.year(), month: d.month() 1, date: d.date(), inMonth: false }); } return cells; }补充上月和下月的日期到网格里是为了保证 6 行 7 列的布局始终完整不会因为每个月 1 号是星期几不同而出现行数跳动。页面渲染时我使用Grid容器7 列固定每格显示日期数字和一个小圆点指示器。有日程的日期显示彩色圆点颜色取当天第一条日程的颜色。点击日期格子会触发事件刷新下方列表。整个逻辑不复杂但要注意性能如果月历上有大量日程一次渲染太多ForEach节点会有卡顿风险我通过把“有日程的日期集合”预先算成Setstring传给组件避免每个格子都去做数据库查询。4.3 本地通知实现提前提醒提醒功能是「宝贝日程表」区别于普通便签的关键。鸿蒙的本地通知能力由ohos.notificationManager提供。我在设置提醒时做了三件事发布一个本地通知设置触发时间。把日程 ID 写入通知的wantAgent参数用户点击通知可跳转到对应详情页。如果用户修改或删除日程先取消旧通知再重新发布。发布通知的简化代码import { notificationManager } from kit.NotificationKit; import { wantAgent, WantAgent } from kit.AbilityKit; async function publishReminder(item: ScheduleItem) { const triggerTime dayjs(${item.date} ${item.startTime}) .subtract(item.reminderMinutes, minute) .valueOf(); const request: notificationManager.NotificationRequest { id: Number(item.id), // 保证同一日程多次修改时通知 ID 不变 content: { notificationContentType: notificationManager.ContentType.NOTIFICATION_CONTENT_BASIC_TEXT, normal: { title: ${item.emoji} ${item.title}, text: 今天 ${item.startTime} 有安排别忘了哦, } }, deliveryTime: triggerTime, triggerTime: { timer: true }, wantAgent: await createWantAgent(item.id), }; await notificationManager.publish(request); }通知的id字段这里用了日程 ID 的数值形式这样后续要取消某条日程的提醒时直接notificationManager.cancel(id)就行非常干净。有一个比较隐蔽的问题deliveryTime和triggerTime的关系容易混淆。在鸿蒙的通知体系里deliveryTime表示通知实际投递的时间triggerTime表示定时触发的时间。实测下来发布定时通知时两者都要设置而且triggerTime.timer要置为true缺一个都会造成通知不触发或者立即弹出。另外一个必须处理的场景应用进程被杀掉后通知还会不会发答案是会。鸿蒙的定时通知由系统通知服务托管发布成功后不依赖应用进程存活。这个机制保证了「宝贝日程表」提醒功能的可靠性也是我敢把它作为核心卖点的原因。4.4 页面路由与生命周期管理「宝贝日程表」目前的页面有四个主页面日历列表、新建/编辑日程页、日程详情页、我的设置页。导航采用ohos.router跳转时通过router.pushUrl传递参数返回时router.back()。新建和编辑共用一个页面通过传入的scheduleId参数判断是新建还是编辑页面加载时如果有 ID 就去数据库查询并填充表单。使用 router 时有个容易踩的坑页面销毁后异步回调还在执行容易引起内存泄漏。我建议在页面aboutToDisappear生命周期里取消所有未完成的异步操作或者在异步回调里统一判断isDisappear标志位。这个小习惯能减少很多偶发崩溃。5. UI 实战ArkTS 声明式布局5.1 组件化把日程卡片抽成独立组件鸿蒙 ArkUI 的组件化方式和前端 Vue/React 的思路很像。页面上反复出现的“日程卡片”我就抽成了一个独立组件ScheduleCard这样新建页面、详情页面、列表页面都能复用样式也能统一调整。组件核心结构Component export struct ScheduleCard { Prop item: ScheduleItem; // 父组件传入的日程数据 State isExpanded: boolean false; build() { Row() { Text(this.item.emoji) .fontSize(28) .padding(8) Column() { Text(this.item.title) .fontSize(18) .fontWeight(FontWeight.Medium) Text(${this.item.startTime} - ${this.item.endTime}) .fontSize(14) .fontColor(#8A8A8E) } .alignItems(HorizontalAlign.Start) .layoutWeight(1) Text(this.reminderLabel()) .fontSize(12) .fontColor(#FFFFFF) .backgroundColor(this.item.color) .borderRadius(10) .padding({left: 8, right: 8, top: 4, bottom: 4}) } .width(100%) .padding(16) .backgroundColor(#FFFFFF) .borderRadius(16) .shadow({ radius: 8, color: #1A000000, offsetY: 2 }) .margin({ bottom: 12 }) } private reminderLabel(): string { if (this.item.reminderMinutes 0) return 不提醒; if (this.item.reminderMinutes 60) return 提前${this.item.reminderMinutes}分钟; return 提前${Math.round(this.item.reminderMinutes / 60)}小时; } }Prop装饰器表示这个值由父组件单向传入子组件内部修改不影响父组件。State则是组件内部可变状态任何修改都会触发 UI 刷新。这个区分是 ArkUI 状态管理的基础初学者最容易在这上面翻车。5.2 状态管理父组件数据驱动子组件刷新日程列表页面的状态管理方式是这样的父页面持有State currentDate: string和State scheduleList: ScheduleItem[]当用户点击日历上的某一天时currentDate改变触发一次数据库查询把结果赋给scheduleList。列表的ForEach会自动重新渲染不需要手动操作 DOM。这里有一个ForEach的 key 生成问题。我一开始这么写ForEach(this.scheduleList, (item: ScheduleItem) { ScheduleCard({ item: item }) }, (item: ScheduleItem) item.title)结果发现当两条日程标题一样的时候删除其中一条另一条也被误删或者 UI 不刷新。原因就是keyGenerator返回了重复值。后来改成用item.id作为唯一 key问题彻底消失。这个教训很典型所有用ForEach渲染的列表key 必须选唯一字段。5.3 深色模式适配鸿蒙 5.0 之后对深色模式的支持非常全面没有做适配的 App 在深色模式下会出现大面积白底刺眼的情况。「宝贝日程表」的适配策略有两层第一层是资源文件适配把颜色、图片放在resources/dark/element和resources/dark/media目录下系统切换深色模式时自动加载第二层是代码逻辑适配通过uiAbilityContext.config判断当前颜色模式动态设置个别无法用资源文件覆盖的颜色值。我的经验是尽量走资源文件的适配方案不要写太多if (isDark) { ... } else { ... }的判断逻辑后期维护会想哭。资源目录一配全局自动生效这才是声明式开发该有的姿态。6. 构建、调试与真机验证6.1 hvigorw 构建打包开发阶段最常用的构建命令是hvigorw assembleHap这个命令会编译整个工程生成 HAP 包。首次构建可能比较慢内部会下载 SDK 依赖和 npm 依赖后续有增量缓存就快多了。如果只想快速验证语法和编译错误也可以先用hvigorw compileArkTS只编译 ArkTS 代码不做资源和打包速度会快很多。开发大项目时我一般先跑这个命令做快速反馈。构建完成后的产物在entry/build/default/outputs/default/目录下常见文件名是entry-default-signed.hap签名过和entry-default-unsigned.hap未签名。6.2 hdc 连接设备与安装hdc 是鸿蒙的设备连接工具作用和 Android 的 adb 相同。连接真机前需要在开发者模式里打开“USB 调试”开关。连接后执行hdc list targets能看到设备的序列号。然后安装调试包hdc install entry/build/default/outputs/default/entry-default-signed.hap如果是签名过的包安装后能直接看到应用图标。如果安装报错error: install signature verify failed大概率是签名和调试证书不匹配回到第 7 节检查签名配置。用 hdc 也很方便抓取应用日志排查崩溃问题hdc shell hilog | grep BabySchedulehilog是鸿蒙的日志系统按应用包名过滤后能看到包含业务日志和异常栈的信息。我有一次遇到偶发崩溃日志厚厚一坨加了这个过滤才一分钟锁定了问题。6.3 性能优化列表滑动流畅度日历列表中日程多的时候滑动卡顿是最常见的问题。我用 DevEco Studio 自带的性能分析工具抓了几帧数据发现卡顿主要集中在两个地方第一个是ForEach列表里每个子项都做了复杂的样式计算和阴影渲染。解决方案是在ScheduleCard外层使用ListItem的sticky属性减少不必要的重绘同时阴影效果从八号降到四号视觉差异不大但渲染压力小了不少。第二个是数据库查询频繁。原来每次切换日期都会重新查询数据库后来我加了一层简单缓存用Mapstring, ScheduleItem[]缓存最近浏览过的日期数据同一个日期切换回来时直接取缓存秒开。6.4 真机调试中遇到的适配问题我的测试机是一台 HarmonyOS 4.0 的旧设备和 API 12 的模拟器行为有一点差异最明显的是通知权限。在新版本系统上通知权限默认是打开的但我那台旧设备是默认关闭的需要手动在设置里打开否则提醒功能完全不生效。后来我在引导流程中加入了“检查通知权限并引导开启”的步骤才算杜绝了这个体验黑洞。另外字体渲染在不同设备上也有细微差别。日程卡片上的小号字体在部分设备上会显示偏大我把关键文本从固定fontSize(12)改成了fontSize(12fp)fp单位会跟随系统字体缩放设置老人机用户把字体调到超大时界面不会乱掉。7. 签名、打包与正式上架7.1 应用签名配置上架华为应用市场最重要的一步是签名配置。签名相当于应用的身份证证明这个 HAP 确实是开发者上传的且没有被篡改。鸿蒙应用的签名体系比 Android 要严主要分成两段证书文件.cer在 AGC 平台申请标识开发者身份。Profile 文件.p7b包含应用包名、签名证书指纹、支持的设备类型等信息。DevEco Studio 里配置签名比较直观但我这里重点说 CLI 的做法。在工程根目录build-profile.json5中我配置了如下签名信息{ app: { signingConfigs: [ { name: default, type: HarmonyOS, material: { certpath: ./sign/release.cer, storePassword: ******, keyAlias: release_key, keyPassword: ******, profile: ./sign/release.p7b, signAlg: SHA256withECDSA, storeFile: ./sign/release.p12 } } ], products: [ { name: default, signingConfig: default } ] } }这份配置在生产环境绝对不能提交到 Git 仓库密码会明文泄露。我习惯把sign/目录整个加进.gitignore在 CI 环境里通过环境变量注入密码避免硬编码。7.2 HAP 产物与 AGC 上传签名配置完成后再次执行hvigorw assembleHap --mode module -p productdefault会生成带签名的 HAP 包。之后登录 AppGallery ConnectAGC平台在“我的应用”里创建一个新应用包名必须和工程里配置的一致然后进入“分发 版本管理”页面上传 HAP 包。上传后系统会自动识别应用版本号、包名、支持的 SDK 版本等信息。如果展示的信息和预期不符检查AppScope/app.json5里的versionName和versionCode字段。7.3 上架审核需要注意的细节华为应用市场的审核速度整体不错但被拒绝的经历也是有的。我整理的几个高频驳回点隐私政策缺失应用如果收集任何用户数据包括日程内容必须在应用内和上架资料里提供隐私政策链接。我的处理方式是写了一个静态隐私政策页面在“我的 隐私政策”里跳转。权限声明不完整日历应用会请求通知权限需要在module.json5里声明ohos.permission.NOTIFICATION_CONTROLLER或者对应的用户授权权限且要写清楚用途。未成年保护应用名称和内容涉及“宝贝”审核人员会重点关注是否有儿童个人信息收集行为。我的做法是不做账号系统、不收集任何儿童信息日程数据仅保存在本地这个设计也成了上架时的一项合规优势。截图和描述不一致上架填写简介时写了“支持周视图”但截图里没有体现会被打回。保持图文一致是基本要求。7.4 上架后的版本迭代流程第一版上架成功后后续迭代的流程就比较顺畅了。我在每次发版前都会走一遍这个固定流程更新versionName和versionCode。执行hvigorw assembleHap生成新包。用hdc真机安装跑一遍核心功能。上传 AGC填写更新日志提交审核。这个流程熟练之后从代码冻结到提交审核控制在半小时内。如果配置了 CI/CD还能做到打 Tag 自动构建自动上传不过个人项目没必要太自动化手动跑一遍反而能多一次质量检查。8. 常见问题与排错实录8.1 问题速查表整个开发过程中我遇到并解决的问题可以汇总成一张速查表方便大家直接查问题现象可能原因解决方案hvigorw命令找不到环境变量没配置检查 DevEco CLI 的 bin 目录是否在 PATH 中ohpm install超时镜像源配置异常检查.ohpmrc的 registry 配置编译报错Cannot find module dayjs依赖没安装或 SDK 未同步重新执行ohpm install然后清理构建缓存真机安装报签名错误Profile 和证书不匹配重新生成 Profile检查包名是否一致通知不触发权限未开启检查应用中引导用户开启通知权限日历 1 号位置不对星期的起始计算错误确认dayjs().day()的返回值设置列表删除错乱ForEachkey 重复key 必须使用唯一字段如id深色模式下文字看不清未做深色适配使用resources/dark目录配置深色资源审核被拒隐私政策缺失缺少隐私政策页面增加一个静态隐私政策说明页8.2 我踩过的三个最深的坑第一个是数据库升级问题。第一版数据库表结构里没有end_time字段后来加字段时只是简单修改了CREATE TABLE语句结果老用户升级后发现新字段根本不存在查询直接崩溃。后来我引入了数据库版本号机制在onUpgrade回调里执行ALTER TABLE才彻底解决。鸿蒙的 RelationalStore 默认版本号是 0第一次设置版本号时一定要从 1 开始后续升级逐级递增。第二个是路由传参的序列化问题。ArkTS 的router.pushUrl参数类型是Object但取值时如果直接强转成自定义类型在某些版本上会报类型错误。我的做法是传一个 JSON 字符串到达目标页面后用JSON.parse解析兼容性很好。第三个是通知 ID 冲突问题。我用Number(item.id)把字符串主键转成 number 当通知 ID一开始觉得没问题但实际运行中发现id字符串123和123.0转出来的都是 123导致两条日程的通知互相覆盖。后改为用日期时间戳取哈希取模 2^31才彻底避免冲突。8.3 独家避坑技巧除了上面这三个大坑还有一些细节值得分享日志要养成分级习惯关键业务路径首尾都打上日志出问题时能快速确认走到了哪一步。真机调试和模拟器行为不一致模拟器好的代码到真机上不一定好尽量多在不同版本设备上验证。构建产物目录默认不加入 Git 版本管理但建议保留build-profile.json5、oh-package.json5等构建配置文件的变更记录。版本升级导致工程构建不一致时diff 配置文件就能定位问题。9. 后续扩展与个人心得「宝贝日程表」上架之后我给自己留了几个后续迭代方向。一个是家庭共享孩子日程通常由父母双方共同维护这需要用到鸿蒙的分布式数据能力和账号授权体系技术门槛不低但产品价值很大。另一个是 AI 辅助录入比如拍照识别纸质通知单上的日程信息自动解析时间和活动名称生成日程条目。手写识别现在鸿蒙的 AI 组件可以直接调用实现起来比我预想中容易。还有一个动力来自社区反馈。上架后有用户留言说希望支持“每周重复”的周期日程比如每周三的舞蹈课不用每周手动录入。这个功能需要重新设计数据模型在表里加一个repeatType字段查询时动态扩展日期。我已经规划好了改造方案准备在下一个版本里落地。最后分享一点个人体会。从最初想做一个“给孩子的日程表”到真正走完设计、开发、测试、签名、上架这条完整链路我最大的收获并不是掌握了几条 CLI 命令而是理解了工程化思维在鸿蒙开发中的分量。DevEco CLI 让我摆脱了对 IDE 图形界面的依赖项目的每一步都能被复现和追溯ArkTS 的声明式语法让我写页面像搭积木状态一变 UI 自动响应。鸿蒙开发这几年迭代速度很快工具链也越来越成熟现在入场的开发者正赶上一个比较友好的时间窗口。如果你也想做一个自己的 App别光看教程直接开一个工程从最简功能做起跑通一次完整上架流程的价值比刷一百个小时教程都大。
阅读完成 · 觉得有帮助?
咨询建站