ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

鸿蒙应用从0到1上架全流程:基于宝贝日程表的DevEco CLI实战

鸿蒙应用从0到1上架全流程:基于宝贝日程表的DevEco CLI实战 正式上架前后我身边好几个做独立开发的朋友都问我同一个问题现在鸿蒙到底好不好做从一个想法到应用真正能上架中间要趟多少坑这篇文章算是我用「宝贝日程表」这个项目从头到尾完整走了一遍之后交的一份作业。整个过程中我只用DevEco CLI命令行工具链搞定工程创建、依赖安装、编译构建、签名打包没有碰图形化IDE的一键式操作每一步都是自己敲命令完成的。写出来既是对自己踩坑路的复盘也希望能给打算在鸿蒙生态里试试水、或者正卡在开发到上架某个环节的人一些具体参考。我得先说清楚适用范围我做的这个App功能不算复杂就是一个给孩子用的日常日程管理小工具记录吃饭、睡觉、上课、游玩这些固定事项到点推送本地通知提醒没有服务端没有账号体系数据全部存在本机。但正因为功能边界清晰反而很适合用来完整验证一条鸿蒙应用从0到1的工业化链路工程结构长什么样、ArkTS开发体验如何、关系型数据库在真机上稳不稳、本地通知权限怎么申请、签名证书怎么配置、上架审核到底卡在什么细节上。如果你正准备做一个鸿蒙小工具类App或者你正在纠结是否要用HAP这种新的应用形态来试水独立开发这篇内容应该能在你下单之前把整个链路的路况帮你提前摸一遍。1. 项目定位与整体设计先想清楚再敲代码1.1 产品定位与核心功能拆解「宝贝日程表」的出发点其实特别朴素。我家孩子自从上了幼儿园之后每天的节奏全乱套早上磨蹭、中午不睡、晚上该睡的时候精神百倍。市面上现成的儿童日程App我不是没试过但普遍有两个问题一是功能太重明明就只需要几条固定日程偏要搞社交、搞积分系统二是启动链路太长点开App要看好几秒广告才能进主界面孩子自己根本操作不了。所以我自己定义的产品原则就三条打开就能看见今天要干什么、操作一步就能新增一个日程、到点自动响铃提醒。功能清单我梳理成四个模块日程展示首页以时间线形式展示当天的日程按时间先后顺序排列已过的时间自动折叠。顶部提供一个小的日历区间可以左右滑动切换日期通过红点标记当天是否有日程。日程管理支持新增、编辑、删除日程。每条日程包含标题、日期、开始时间、结束时间、重复规则只一次、每天、每周某几天、提醒提前量不提醒、提前5分钟、15分钟、30分钟、1小时、备注和颜色标签。本地通知日程创建后立即注册对应的本地通知到点触发系统级提醒即使App不在前台也能收到通知。通知点击后重新回到App并定位到对应的日程详情页。设置提供提醒总开关、通知铃声选择、默认提前量设置、宝宝信息录入昵称和头像颜色以及数据导出备份功能。这个功能量级对开发周期也算是比较合适的从建工程到提交审核我实际投入了大概三周左右的业余时间。如果你想快速跑通一个鸿蒙应用的全流程我建议也把MVP范围控制住后面增加的每一个功能都是要付出维护成本的。1.2 技术选型为什么用ArkTS ArkUI 本地关系型数据库技术选型这块我在开工前其实做了几种方案的比较。鸿蒙应用开发目前主流的编程语言有ArkTS、JS、还有通过跨端框架来做的方案。先排除跨端框架原因很简单没意思。既然要做鸿蒙原生那就看看ArkTS和经典JS的区别。我的建议很明确新项目直接上ArkTS ArkUI声明式范式。主要理由有三点第一ArkTS是官方现在全力投入的演进方向网上能查到的资料、官方的示例工程、社区里活跃讨论的内容绝大多数都是ArkTS写的遇到问题能搜到的答案数量完全不是一个量级。如果是从Java或者TypeScript转过来的开发者上手成本其实很低它本质上是TypeScript的一个超集只是在类型安全上做了更严格的约束。第二ArkUI的声明式写法对UI开发效率的提升非常明显。以前写鸿蒙的类Web前端需要手动操作DOM现在直接在ets文件里写build方法描述UI结构用State装饰器管理状态数据变了UI自动刷新这个开发体验和现在流行的SwiftUI、Flutter已经非常接近了写起来很顺畅。第三本地数据存储的方案我选择了关系型数据库RelationalStore而不是轻量级偏好存储Preferences或者数据库KVStore。原因在于日程数据天然就是结构化、需要按时间排序、需要范围查询的数据。比如要查询某一天的所有日程用Preferences把数据全量加载进来再在内存里过滤数据量小的时候可行但一旦日程积累到几百条每次查询都在做无意义的全量遍历性能和代码规范都过不去。关系型数据库直接写SQLSELECT * FROM schedule WHERE day ? ORDER BY start_time ASC这类操作是它最擅长的事。1.3 工程结构规划与模块划分工程结构在开工前也要规划好后面改起来成本很高。我采用的是单HAP 多module的模式但考虑到项目不大最终实际用的是单module的简单结构。这里我给你的建议是小项目直接单模块没问题但目录内部一定要按功能分包别把所有的页面文件堆在一个page目录下。我的工程模块结构是这样的AppScope/ app.json5 // 应用全局配置 entry/ src/main/ ets/ entryability/ EntryAbility.ets // 应用入口Ability pages/ Index.ets // 首页-今日日程 CalendarPage.ets // 月历页 ScheduleEditPage.ets // 新增/编辑日程 SettingPage.ets // 设置页 model/ Schedule.ets // 日程数据模型 ReminderRule.ets // 提醒规则枚举 database/ DatabaseHelper.ets // 数据库工具类 ScheduleDao.ets // 日程数据访问对象 service/ NotificationService.ets // 本地通知服务 common/ ColorConst.ets // 全局颜色常量 DateUtils.ets // 日期工具函数 resources/ base/ element/ // 字符串、颜色资源 media/ // 图片资源 profile/ // 配置文件 module.json5 // 模块配置文件把不同职责的代码拆到不同的包里后面加功能的时候才不会越写越乱。我见过很多新手把数据库操作和UI逻辑全写在一个页面文件里刚开始看着挺方便等代码量上来之后改一个需求就想把整个文件推倒重写。2. 环境准备与DevEco CLI命令行工具链实战2.1 开发环境搭建从零装出一台能编译的机器环境搭建是很多新手第一道坎但如果你按照官方文档一步步来耐心点其实不会出太大问题。我用的是macOS环境Win平台步骤类似主要就是下载、解压、配置环境变量三步。首先需要从官网下载DevEco Studio。下载的时候注意选对版本我用的是DevEco Studio 5.0版本对应的API是HarmonyOS 5.0.0API 12。为什么强调版本因为鸿蒙的版本演进节奏相当快不同大版本之间API差异不小网上搜到的代码片段经常出现版本不兼容的问题。建议你在网上搜资料前先看对方用的API版本一边是API 9的代码一边用API 12编译肯定报错。安装完DevEco Studio之后第一次启动会让你下载SDK和Platform Tools这步一定要走完。SDK里面包含了编译鸿蒙应用需要的所有工具链和API库文件Platform Tools里面则有后面命令行调试要用的hdc工具相当于Android的adb。然后就是把命令行工具加到系统的PATH里。这一步是后面全部命令行操作的基础。我需要用到的命令主要有三个hvigorw构建工具负责编译和打包自动管理编译依赖关系类似Gradle之于Android工程ohpm包管理器负责第三方OpenHarmony包和鸿蒙生态库的安装类似npm之于Node生态hdc设备连接工具负责真机的连接、应用安装、日志抓取等配置方式就是在bashrc或zshrc中添加类似下面的路径export DEVECO_SDK_HOME/Users/你的用户名/Library/Huawei/Sdk export DEVECO_HOME/Applications/DevEco-Studio.app/Contents/tools export PATH$PATH:$DEVECO_HOME/ohpm/bin:$DEVECO_HOME/hvigor/bin配好之后执行hvigorw --version和ohpm --version验证一下能正常输出版本号就说明环境OK了。2.2 命令行创建工程与依赖管理接下来就是核心环节通过命令行创建一个鸿蒙工程。这里需要说明一下DevEco Studio的IDE向导本质上也是在后台调用模板生成器所以我命令行操作就是直接加载官方工程模板来完成创建但对于纯命令行来说最稳妥的方式是先通过DevEco Studio的勾选模板创建一次因为工程模板文件比较多手工拼写很容易少东西。不过如果你的场景是CI/CD流水线里需要自动创建工程其实DevEco CLI是支持通过devecostudio命令配合启动参数来在无GUI环境下创建的。我这里把两种方式都跑通过但考虑到大部分读者是个人开发者我觉得简单说一下IDE创建再补充命令行相关的操作就足够了。创建好工程之后项目根目录下面会出现一个oh-package.json5文件这是鸿蒙工程的依赖清单配置文件作用等同于Node项目的package.json。我需要的依赖通过命令行安装ohpm install ohos/axios注意鸿蒙的第三方库生态和npm是两套体系有些在npm上能搜到的库在ohpm上不一定有。我这个项目里依赖了一个日期处理库和一个时间选择器组件实际操作中发现还是自己写比较靠谱。日期的格式化、计算、比较这些操作在鸿蒙这边都建议直接用系统提供的ohos.i18n模块来处理它的国际化能力涵盖日期格式化但如果你需要算两个日期之间差了多少天还是建议自己写个工具函数代码并不多还能减少依赖体积。2.3 常用构建命令详解编译、安装、调试一条龙工程建好之后我最常执行的命令就这几条hvigorw clean清理上次构建的产物每次改完module.json5配置建议先跑一次再编译hvigorw assembleHap编译并生成HAP包产物在entry/build/default/outputs/default/目录下编译的时候注意观察命令行输出的日志级别。如果只想快速看报错可以加上--mode module -p productdefault --no-daemon这些参数来控制。我自己最常用的是hvigorw assembleHap --mode module -p productdefault编译完成后如果手边有真机用hdc连接并安装hdc list targets # 查看连接的设备 hdc install /path/to/entry-default-signed.hap这里有一个很多新手容易踩的坑直接编译出来的HAP是未签名的如果直接hdc install会报错安装失败。所以编译和签名要配套来看要么在编译时配置好签名信息要么用签名工具对HAP做一次签名再安装。签名相关的坑我会在后面专门用一节来讲。如果只是想在模拟器上跑一下也可以先不安装直接用hdc启动应用hdc shell aa start -a EntryAbility -b com.example.babyschedule通过hdc shell hilog可以实时看日志这个调试体验和adb logcat区别不大用惯Android的人很快就能上手。3. 核心功能实现与关键代码解析3.1 数据模型设计日程数据在数据库里怎么放日程这个数据模型我把它拆成了这些字段id主键自增用于唯一标识每条日程title日程标题文本day日程日期格式为YYYY-MM-DD的字符串便于按天查询start_time开始时间格式为HH:mm字符串end_time结束时间同上repeat_rule重复规则0只一次1每天2每周repeat_days重复的星期组合用逗号分隔的整数位掩码存储比如周日加周一是3remind_before提前提醒的分钟数-1表示不提醒color_tag颜色标签编号UI上用于区分不同分类note备注文本create_time创建时间戳毫秒级我用字符串而不是直接用Date对象来存日期和时间原因很简单SQLite在鸿蒙封装好的这个库里对DateTime类型的处理不够直观字符串在查询时也符合通用的字典序WHERE day 2025-01-15这种写法直来直去不会有坑。建表SQL写成这样CREATE TABLE IF NOT EXISTS schedule ( id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT NOT NULL, day TEXT NOT NULL, start_time TEXT NOT NULL, end_time TEXT, repeat_rule INTEGER DEFAULT 0, repeat_days TEXT, remind_before INTEGER DEFAULT -1, color_tag INTEGER DEFAULT 0, note TEXT, create_time INTEGER )这里我建议提前给day字段建一个索引因为后面所有的核心查询都是按日期来的CREATE INDEX idx_schedule_day ON schedule(day)3.2 数据库操作封装Dao层的增删改查鸿蒙的关系型数据库操作是异步接口所以Dao层我全部用异步函数封装返回Promise对象。初始化数据库的代码核心就是拿到一个RdbStore实例import { relationalStore } from kit.ArkData; import { common } from kit.AbilityKit; let store: relationalStore.RdbStore | null null; export async function initDatabase(context: common.Context): Promisevoid { const config: relationalStore.StoreConfig { name: baby_schedule.db, securityLevel: relationalStore.SecurityLevel.S1 }; store await relationalStore.getRdbStore(context, config); await store.executeSql(CREATE_TABLE_SQL); }关于securityLevel这个参数值得多说一句。它表示这个数据库的安全级别如果应用后续涉及多设备协同或者数据同步这个级别会影响能否把数据库文件直接同步到其他设备上。我这种纯本地存储场景用S1就够了再往上提级别反而会增加开销。增删改查封装成方法后业务层调用起来非常清爽export async function insertSchedule(schedule: Schedule): Promisenumber { const values new relationalStore.ValuesBucket(); values.put(title, schedule.title); values.put(day, schedule.day); values.put(start_time, schedule.startTime); // ... 其他字段 const rowId await store?.insert(schedule, values); return rowId ?? -1; } export async function querySchedulesByDay(day: string): PromiseSchedule[] { const predicates new relationalStore.RdbPredicates(schedule); predicates.equalTo(day, day); predicates.orderByAsc(start_time); const resultSet await store?.query(predicates); // 遍历ResultSet组装为Schedule对象 }这里我需要强调一个在真机上踩过的坑resultSet遍历结束后一定要手动调用close()释放资源。ArkTS在资源管理上偏向严格如果不关闭日志里会出现资源泄漏警告而且长时间频繁操作数据库会导致剩余可分配内存越来越少应用莫名的卡顿甚至闪退都会接踵而来。这是一个非常典型的“看起来是小问题实际上致命伤”的坑。3.3 UI实现用ArkUI声明式写法快速搭建日历和时间线ArkUI写UI的体验和Flutter很像核心是嵌套的组件树加上状态管理。我的首页用一个垂直滚动容器包住当天的时间线卡片顶部放一个自定义的周视图组件。这里我挑比较有代表性的日历区间来做说明。刚开始我想用公司开源的日历组件但研究了下API觉得对一个日程表来说太多余了直接用Grid重新实现了一个月历代码并不复杂。核心逻辑就是把一个月的日期按星期排列每行7列首行根据本月1号是星期几来空出对应的格子State currentMonth: Date new Date(); build() { Grid() { ForEach(this.dayCells, (cell: DayCell) { GridItem() { Column() { Text(cell.day.toString()) .fontSize(16) .fontColor(cell.isCurrentMonth ? #333333 : #BBBBBB) if (cell.hasSchedule) { Circle({ width: 6, height: 6 }) .fill(#FF6B35) } } .onClick(() this.onSelectDay(cell.date)) } }) } .columnsTemplate(1fr 1fr 1fr 1fr 1fr 1fr 1fr) }State装饰器监听currentMonth的变化切换月份时重新计算dayCells数组Grid自动重新渲染这个响应式能力用起来是真的省心。时间线卡片部分我用了List组件来承载当天的日程列表借助LazyForEach实现懒加载。这里有一个性能上的细节如果一个月内的日程很多全量ForEach会产生大量节点首屏渲染时间会比较长。用LazyForEach配合IDataSource接口列表滚动时按需生成组件实测在几百条日程下依然能保持流畅。3.4 本地通知让系统在正确的时间提醒你日程的提醒功能是这类App的灵魂。鸿蒙的本地通知API走的是ohos.notificationManager模块实现逻辑是这样的创建通知前必须先申请授权。这一步原本在旧的API上是在module.json5里声明权限即可但现在系统对通知权限的要求更严格了需要在运行时用notificationManager.requestEnableNotification()这行代码来向用户弹窗请求授权。注意用户如果拒绝了需要在后续的UI上提供一个入口让用户能再次发起请求因为一旦拒绝系统不再自动弹窗你需要在设置页放一个按钮来重复触发这个授权请求。通知内容构建起来很直观import { notificationManager } from kit.NotificationKit; async function publishScheduleReminder(schedule: Schedule) { const request: notificationManager.NotificationRequest { id: schedule.id, content: { notificationContentType: notificationManager.ContentType.NOTIFICATION_CONTENT_BASIC_TEXT, normal: { title: schedule.title, text: 现在时间到了该${schedule.title}啦, } }, notificationSlotType: notificationManager.SlotType.SOCIAL_COMMUNICATION, }; await notificationManager.publish(request); }这里通知的id字段很重要它是后续取消通知的唯一标识。比如用户编辑了日程时间或者删除了日程你需要调用notificationManager.cancel(schedule.id)把旧的定时通知取消掉否则会出现“日程已经改到明天了但今天通知还是响了”的尴尬情况。定时触发通知我选择了reminderAgentManager提醒代理来实现它能配置精确到分钟级的定时提醒并且支持按周重复。这个模块是鸿蒙做得比较完善的一个系统能力底层会自己唤醒服务端来保证消息可靠送达。配置方式大致是import { reminderAgentManager } from kit.BackgroundTasksKit; const reminder: reminderAgentManager.ReminderRequestAlarm { reminderType: reminderAgentManager.ReminderType.REMINDER_TYPE_ALARM, hour: hours, minute: minutes, daysOfWeek: repeatDays, title: schedule.title, content: 到时间啦, actionButton: [{ title: 查看, type: reminderAgentManager.ActionButtonType.ACTION_BUTTON_TYPE_CLOSE }], wantAgent: { pkgName: com.example.babyschedule, abilityName: EntryAbility } }; const reminderId await reminderAgentManager.publishReminder(reminder);发布成功后返回的reminderId也要存起来同样是为了后续修改和取消用。提醒代理的daysOfWeek字段要求传入一个数字数组数组里1代表周一7代表周日和我前面日程数据模型里的位掩码存储方式要做一次转换这个转换逻辑值得单独写个工具函数并加上单测因为很容易因为数组下标搞错而出现“提前一天提醒”的诡异问题。4. 调试、测试与性能优化实录4.1 模拟器与真机联调从日志到断点的完整流程开发阶段我大部分时间其实在DevEco Studio的模拟器上跑的因为启动速度快、随时可以调整屏幕尺寸做适配。模拟器目前对CPU和内存的占用还是比较高的我用了整整16GB内存的机器跑起来还算顺畅。但模拟器跑得通不代表真机没问题。我遇到过一个特别典型的差异模拟器上数据库查询和UI刷新完全正常一放到真机上首页进来自动加载当天日历时偶发出现冷启动白屏两三秒的情况。排查下来根本不是代码逻辑问题是数据库初始化没有异步等待好UI先渲染了再等数据回来导致的短暂空白。解决方式是把数据库初始化逻辑提前到Ability的onWindowStageCreate生命周期钩子里并且在首页的aboutToAppear钩子里等待初始化完成再拉数据async aboutToAppear() { await ensureDatabaseInitialized(); this.loadTodayData(); }同时页面上要加一个加载中的占位状态数据未返回前显示进度条而不是空白。这样改完再冷启动基本能做到首页数据秒出。4.2 性能优化减少掉帧与延迟加载ArkUI的性能优化其实和绝大多数声明式UI框架的思路是一致的减少无效渲染、降低组件层级、复用长列表。首页这个时间线列表是整页的性能关键。我第一版直接写的ForEach扫过全部日程条目每个条目还动态加了阴影和模糊效果结果在低端机上滑动时帧率掉得厉害。改成LazyForEach之后就明显流畅了因为只是按需渲染可视区域内的那些条目。还有一个优化点值得专门提阴影和模糊这类视觉效果在真机上非常昂贵尤其是在列表条目上反复使用。我在真机上对比过去掉一层模糊效果后帧率从40帧左右回升到了55帧以上。小工具App也没必要用那么多花哨的视觉效果能给用户带来顺滑的体验比什么光效都重要。4.3 多设备适配手机和平板的兼容性鸿蒙最吸引人的地方之一就是它跑在各种形态的设备上。虽然「宝贝日程表」的核心场景是手机端但我也在平板上跑了一遍做了基础适配毕竟有用户可能拿平板当家庭共享屏。ArkUI的布局用了栅格系统之后对屏幕尺寸的适应会轻松很多。我的首页用GridRow和GridCol来划分区域在宽屏幕上自动变成左右两栏左边是月历右边是当天日程列表在窄屏手机上则自动堆成上下结构。这个能力只需要在布局代码里指定断点范围和对应的列数比Android里的响应式适配要省心不少。另外还要关注字体缩放和触控目标尺寸。平板上的用户普遍离屏幕远按钮如果太小不好点而设置了系统大字体后固定宽高的容器很可能出现文字截断。我专门做了在系统字体放大模式下标题和正文的字体动态缩放的适配验证。鸿蒙提供了一套vp动态尺寸单位用它来做字体大小就不用每个地方都写适配逻辑了。5. 打包签名与上架全流程详解5.1 签名证书从申请到自动配置的完整步骤上架前最大的一道坎就是签名配置。鸿蒙应用签名体系保姆级繁琐从公钥、CSR、证书、Profile每一步都有严格的格式要求而且官方文档里细节散落各处初次操作很容易卡住。我的经验是分两条路走开发调试阶段用自动签名省心省力上架发布则用手动签名走正规流程。自动签名在DevEco Studio里勾一下就会自动帮你申请好调试证书并配置但如果要在命令行打包需要能拿到签名的正确参数。这里说一下命令行的签名配置。签名信息配置是写在build-profile.json5文件里的关键内容长这样{ app: { signingConfigs: [ { name: release, type: HarmonyOS, material: { certpath: /path/to/release.cer, storePassword: your_store_password, keyAlias: your_alias, keyPassword: your_key_password, profile: /path/to/release.p7b, signAlg: SHA256withECDSA, storeFile: /path/to/release.p12 } } ], products: [ { name: default, signingConfig: release } ] } }实际开发中我见过有开发者把密码明文写在配置文件里提交到Git仓库结果整个项目被人拿到了证书和Profile去冒名签名。密码和证书文件都不应该入库。建议在CI系统里通过环境变量注入的方式来管理这些敏感信息。鸿蒙当前版本的命令行工具对从环境变量读取密码的适配还不太完善我通常是在CI里用脚本读取环境变量后临时生成配置文件打包完成后再把生成的文件删掉。5.2 正式包构建命令行打出一个可上架的HAP签名配置好之后正式打包的命令还是那句熟悉的hvigorw assembleHap但会多一个release模式的选择。我实践下来最稳的方式是hvigorw clean hvigorw assembleHap --mode module -p productdefault --build-mode release构建成功后在entry/build/default/outputs/default/目录下会生成entry-default-signed.hap这就是最终用于上架的安装包。关于HAP包体积鸿蒙默认打出来的是没有做资源混淆和体积裁剪的。我在提交审核前把包从12MB优化到了4.8MB主要做了三件事第一检查了资源目录下有没有被引用的图片删掉了设计过程留下的几张未使用的大图第二把一些纯色背景图改成了代码里直接设置背景色没必要为每种颜色单独放一张图片第三确认第三方依赖没有把不必要的模块带进包里。对审核来说体积不是硬性指标但下载转化率会受影响能小一点是一点。5.3 应用市场上架审核材料的准备与要点上架走的是华为应用市场的AppGallery Connect。注册开发者账号后创建应用填写基本信息然后上传包、提交审核。审核材料这边有几个值得提前准备的点应用名称要提前想好上架之后想改名流程比较麻烦需要走更严格的审核。我的应用名就叫「宝贝日程表」简洁直白搜索也容易命中。应用介绍、截图、隐私政策这些材料都要提前准备好。截图尺寸要严格按后台要求的规格来不同分辨率各做一套。隐私政策尤其重要因为应用会申请通知权限并保存本地数据隐私政策里要把数据收集和处理方式写清楚。App的图标要准备高分辨率版本后台会给出具体的格式和尺寸要求注意图标设计的中心区域避免被裁切到核心元素。审核周期做了两轮第一轮提交后大概两天左右就收到了反馈。反馈意见列了两个问题一个是隐私政策链接打不开需要换成可以直接访问的线上地址第二个是应用内的某些功能描述字眼不够准确。这些问题都不复杂修改后重新提交又等了大概两天就通过了整个流程比我预想的要顺畅。5.4 上架之后版本更新与应用内体验优化应用上架不等于完事了反而意味着新阶段开始了。用户在真实环境下遇到的各种问题会通过应用市场反馈过来你要认真对待每一条评价。我上架后的第一个小版本更新就是根据用户反馈加了一个“清空过期日程”的功能。因为很多日程设置了每天重复用户根本想不起来去清理几个月下来数据库里堆积了几百条历史记录影响查询速度不说看着也别扭。这个功能实现起来其实简单写一个删除语句把day字段小于今天且repeat_rule等于0的记录删掉然后加到设置页里给用户一个手动清理的按钮。另外i18n也值得早点规划。虽然是面向国内用户的应用但在鸿蒙生态里把英文等语言资源做完整没坏处因为华为设备在海外的保有量其实不小而且基础的多语言支持能在设置里直接切换系统语言来调整成本不高收益却明显。我这版把中英文两个语言资源文件都补齐了前端代码里没有硬编码的字符串全部走资源引用。开发初期可能觉得麻烦但真到需要的时候再改会非常痛苦。6. 常见问题排查与避坑经验6.1 高频问题速查表我把开发中遇到的出现频率最高且最影响效率的问题整理成了表格按我的实际经验给出对应方案。问题现象根因分析解决办法hdc install报错INSTALL_PARSE_FAILED_NO_CERTIFICATEHAP未签名或签名无效检查build-profile.json5的signingConfigs配置用有效签名后重新打包ohpm install下载依赖超时网络问题或仓库源不稳定检查ohpm源配置必要时切换到镜像仓库地址编译时报错Cannot find module ohos...SDK版本不匹配或依赖未安装完整检查DevEco Studio SDK版本是否满足要求执行ohpm install完整安装模拟器运行时页面白屏常见于资源加载路径错误检查resources目录下资源引用路径尤其注意文件名大小写通知不触发应用通知权限未开启或提醒代理未正确配置在设置里开启通知权限确认reminderAgentManager配置的提醒ID有效数据库查询崩溃ResultSet未正确关闭导致资源泄漏在遍历结束后显式调用resultSet.close()真机调试连接不上hdc服务未启动或USB调试模式问题执行hdc kill和hdc start重启服务检查手机端开发者选项每条对应的场景我基本都实际踩过一遍如果你开发时遇到类似报错可以对照排查。6.2 三个值得单独说的坑第一个坑是ArkTS的严格类型模式。ArkTS对动态类型非常不友好很多在普通TypeScript里合法写法在ArkTS环境里会直接被编译错误拦截。比如你在TS里写const obj {}; obj.a 1在ArkTS里就不允许这样隐式给空对象挂属性。刚开始写起来确实不太适应觉得处处受限制但适应之后就会发现这种严格约束对保证大型项目的可维护性很有帮助编译阶段能挡住很多运行时才会暴露的类型错误。这个限制官方文档里有完整列举建议写之前花半小时通读一遍比一边写一边撞错误效率高得多。第二个坑是生命周期和异步任务的配合。鸿蒙的Ability销毁是很干脆的页面不可见就销毁但异步任务不会自动取消。我在开发时遇到过一次用户在编辑页输入了一堆内容结果不小心滑动了返回手势页面瞬间销毁异步保存中的代码还没跑完就导致部分数据丢失了。后来我在所有异步操作的入口都加了生命周期状态检查同时对于编辑页采用onPageHide就自动保存草稿的策略用户即使在编辑到一半时退出下次打开也还能恢复这个体验问题才算真正解决。第三个坑和审核有关。应用市场上架很看重App的“完整可用性”如果提交个空壳应用或者功能明显残缺的版本基本是过不了审的。我第一次提交时太着急图标里还有一处从设计稿带过来的文字模糊没看清结果审核不通过。这个提醒大家上架前务必要用一个干净的手机全新安装你要提交的正式包真实地从头到尾把核心流程走一遍看看安装、启动、注册、授权、创建数据、收到通知、删除数据整个闭环是否正常。6.3 自动化构建与持续集成的一点展望如果后面我还要继续在鸿蒙生态里做项目一定会尽早把命令行构建流程接到站到CI上。DevEco CLI这套工具链目前已经足够支撑一个最基本的自动化流水线代码推到仓库后自动拉取最新代码、执行ohpm install、构建HAP、跑一部分针对核心逻辑的单测然后把产物和构建日志归档。日常开发中本地执行这套命令已经是我每天的常规操作了命令行工具对自动化场景的支持是IDE图形界面无法替代的。最后再分享一个小技巧开发过程中的调试日志建议你们像我一样在LogUtils工具类里加一个全局的日志开关发布前把它关掉。鸿蒙的hilog本身性能消耗不算大但把大量无意义的调试日志带到生产环境里既增加了暴露内部实现细节的风险也会让出问题时的排查难度增加。这个开关只看一个布尔变量多写几行代码的事对以后维护帮助很大。
返回列表