ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

原生鸿蒙开发实战:从零构建备忘录应用

原生鸿蒙开发实战:从零构建备忘录应用

1. 项目概述:为什么选择原生鸿蒙开发?

2019年鸿蒙OS的诞生标志着国产操作系统进入新纪元。经过四年迭代,HarmonyOS 4.0的Stage模型和ArkUI 3.0框架已趋成熟,我最近用三周时间完整走通了原生鸿蒙App开发全流程。与Android开发相比,鸿蒙的原子化服务理念和分布式能力确实带来了全新体验,但开发过程中也遇到了不少官方文档未提及的"暗坑"。

这个项目从零构建了一个具备完整生命周期的备忘录应用,包含数据持久化、跨设备同步、服务卡片等核心功能。选择备忘录作为demo是因为它能覆盖90%的常规App开发场景:UI构建、事件处理、数据存储、多线程通信等。下面将分模块详解开发过程中的关键决策和技术实现。

提示:本文基于HarmonyOS 4.0 SDK和DevEco Studio 3.1,所有代码示例都经过真机(MatePad Pro)验证

2. 开发环境搭建与工程结构解析

2.1 工具链配置要点

官方推荐的DevEco Studio在代码提示和预览功能上表现优秀,但需要特别注意:

  • JDK必须使用OpenJDK 17(华为提供了定制版本)
  • Gradle插件版本需锁定在7.4-7.5之间
  • 首次同步依赖时建议关闭防火墙(某些资源域名会被误拦截)

工程目录结构中需要重点关注:

/applications /entry # 主模块 /src/main /ets /pages # 页面组件 /ability # Ability实现 /utils # 工具类 /resources # 资源文件 /build-profile.json5 # 构建配置

2.2 Stage模型设计原则

鸿蒙的Stage模型相比FA模型最大的改进是:

  • 应用级共享资源(如数据库连接)
  • 更好的多窗口支持
  • 更清晰的进程生命周期管理

在module.json5中需要明确定义:

{ "module": { "name": "entry", "type": "entry", "abilities": [ { "name": "MainAbility", "srcEntry": "./ets/ability/MainAbility.ts", "icon": "$media:icon", "label": "$string:app_name", "startWindowIcon": "$media:icon", "startWindowBackground": "$color:white", "exported": true, "skills": [ { "actions": [ "action.system.home" ], "entities": [ "entity.system.home" ] } ] } ] } }

3. ArkUI开发实战:构建备忘录界面

3.1 声明式UI布局技巧

ArkUI的声明式语法与Flutter类似但更简洁。实现一个带搜索框的备忘录列表页:

@Component struct MemoList { @State memos: Memo[] = [] @State searchText: string = '' build() { Column() { // 搜索框 TextInput({ placeholder: '搜索备忘录' }) .onChange((value: string) => { this.searchText = value }) .margin(10) // 列表项 List({ space: 10 }) { ForEach(this.memos.filter(m => m.content.includes(this.searchText)), (item: Memo) => { ListItem() { MemoItem({ memo: item }) } }) } .layoutWeight(1) } .height('100%') } }

关键优化点:

  • 使用@State实现数据驱动UI更新
  • List组件必须设置layoutWeight才能滚动
  • ForEach的性能优于传统循环渲染

3.2 自定义组件开发

封装可复用的备忘录项组件:

@Component export struct MemoItem { @Prop memo: Memo @Link isEditing: boolean build() { Row() { if (this.isEditing) { TextInput({ text: this.memo.content }) .onChange((value: string) => { this.memo.content = value }) } else { Text(this.memo.content) .fontSize(16) } } .padding(10) .borderRadius(5) .backgroundColor('#FFF') .shadow(2) } }

注意事项:

  • @Prop用于父向子传参(单向绑定)
  • @Link实现父子组件双向绑定
  • 样式建议使用StyleBuilder统一管理

4. 数据持久化方案选型

4.1 轻量级存储对比

方案容量限制适用场景读写性能
Preferences1MB配置项、用户偏好毫秒级
Database无结构化数据亚秒级
File无大文件、二进制流秒级

备忘录选择RDB关系型数据库实现:

// 数据库初始化 const STORE_CONFIG: StoreConfig = { name: 'memo.db', encrypt: false, schema: [{ name: 'memos', columns: [ { name: 'id', type: FieldType.INTEGER, isPrimary: true }, { name: 'content', type: FieldType.STRING }, { name: 'createdAt', type: FieldType.INTEGER } ] }] } // 获取RDB连接 const rdb = await relationalStore.getRdbStore(context, STORE_CONFIG)

4.2 数据同步策略

实现跨设备同步需要:

  1. 在module.json5声明分布式权限
{ "reqPermissions": [ { "name": "ohos.permission.DISTRIBUTED_DATASYNC" } ] }
  1. 注册设备状态监听
import deviceManager from '@ohos.distributedDeviceManager' // 监听设备变化 deviceManager.createDeviceManager().then(manager => { manager.on('deviceStateChange', (data) => { if (data.action === 'online') { this.syncData() } }) })

5. 服务卡片开发实战

5.1 卡片配置要点

在form_config.json中定义卡片模板:

{ "forms": [ { "name": "widget", "description": "快捷备忘录", "src": "./ets/widget/WidgetCard.ets", "uiSyntax": "arkts", "window": { "designWidth": 360, "autoDesignWidth": true }, "colorMode": "auto", "type": "JS", "formConfigAbility": "ability://MainAbility" } ] }

卡片组件需要特殊处理生命周期:

export default struct WidgetCard { @State message: string = '' onFormEvent() { // 卡片事件处理 } build() { Column() { Text(this.message) Button('添加备忘录') .onClick(() => { postFormEvent({ action: 'addMemo' }) }) } } }

5.2 卡片数据刷新机制

  1. 定时刷新(最长30分钟):
{ "updateDuration": 30, "scheduledUpdateTime": "10:30", "defaultDimension": "2*2" }
  1. 主动触发刷新:
import formProvider from '@ohos.app.form.formProvider' // 更新卡片数据 formProvider.updateForm(formId, { "message": "新备忘录内容" }).catch(err => { console.error('更新卡片失败') })

6. 调试与性能优化

6.1 真机调试技巧

  1. 开启开发者模式:
# 连续点击版本号7次 # 启用USB调试和HDB认证
  1. 常见错误处理:
  • INSTALL_PARSE_FAILED:检查build-profile.json5中的targetSDK版本
  • PERMISSION_DENIED:确认权限申请逻辑和config.json声明一致
  • REMOTE_DEVICE_NOT_TRUSTED:重新绑定设备公钥

6.2 性能优化指标

指标优秀值测试工具
冷启动时间<500msHiTrace
列表滚动FPS>55fpsDevEco Profiler
内存占用峰值<150MBMemory Monitor
数据库查询耗时<100ms打点日志

优化案例:列表项使用cachedCount预加载

List({ space: 10 }) { // ... } .cachedCount(5) // 屏幕外预渲染数量

7. 应用发布流程

7.1 证书生成最佳实践

  1. 创建调试证书:
keytool -genkeypair -alias "debug" -keyalg EC -sigalg SHA256withECDSA -validity 180 -keystore debug.p12 -storepass 123456
  1. 生产证书建议:
  • 使用2048位RSA密钥
  • 有效期不超过3年
  • 通过AppGallery Connect自动管理

7.2 上架审核要点

常见被拒原因:

  • 未适配深色模式
  • 隐私政策未明确数据收集范围
  • 动态权限未提供拒绝后的降级方案
  • 服务卡片未正确处理点击事件

建议在提审前完成:

  • [ ] 隐私声明链接测试
  • [ ] 权限使用场景检查
  • [ ] 分布式功能跨设备验证

8. 进阶开发技巧

8.1 Native API调用示例

通过FFI调用C++库:

  1. 创建native/src/main/cpp/math_util.cpp:
#include "math_util.h" extern "C" int Add(int a, int b) { return a + b; }
  1. 在ArkTS中调用:
import native from 'libmath_util.so' let result = native.Add(1, 2)

8.2 原子化服务开发

配置abilities支持免安装运行:

{ "abilities": [ { "name": "QuickMemoAbility", "formsEnabled": true, "forms": [ { "name": "quick_memo", "type": "service" } ] } ] }

实现要点:

  • 包体积需控制在10MB以内
  • 不能依赖后台进程
  • 必须支持即用即走

9. 避坑指南(血泪经验)

  1. ArkUI线程模型:
  • UI操作必须在主线程
  • 耗时任务需用TaskPool分发
  • 跨线程通信使用Emitter代替回调
  1. 资源管理陷阱:
  • $r引用资源在Preview模式可能失效
  • 多设备适配建议使用vp/fp单位
  • 图片必须放在resources/base/media
  1. 分布式数据同步:
  • 设备组网需要用户手动确认
  • 单次传输限制在512KB以内
  • 冲突解决建议采用时间戳策略
  1. 生命周期管理:
  • onDestroy不一定被调用
  • 页面返回时要手动释放资源
  • 使用windowStage.on('windowStageEvent')监听窗口状态

10. 生态现状与发展建议

当前鸿蒙原生开发的主要挑战:

  • 第三方库生态尚不完善(可用库约Android的30%)
  • 部分API文档示例缺失
  • 社区解决方案较少

建议学习路径:

  1. 先掌握ArkUI基础组件
  2. 深入理解Stage模型生命周期
  3. 实践分布式能力
  4. 参与开源社区贡献

我维护的示例代码库已包含:

  • 完整备忘录实现
  • 单元测试方案
  • CI/CD自动化脚本
  • 性能优化checklist

(因平台限制不展示具体链接,可在华为开发者论坛搜索"HarmonyOS完整示例"找到)

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进