HarmonyOS应用开发实战:小事记 - 备份扩展 Ability 的注册机制与 onBackup/onRestore 生命周期
2026/7/22 16:06:27 网站建设 项目流程

前言

在移动应用中,数据备份与恢复是保障用户数据安全的核心能力。HarmonyOS 提供了BackupExtensionAbility这一标准化的数据备份框架,开发者只需要继承该类并实现onBackuponRestore两个回调方法,系统即可自动调度备份任务,无需手动处理文件拷贝、压缩和传输等底层操作。本文以 小事记(xiaoshiji_ohos_app) 项目中的EntryBackupAbility.ets为切入点,深入解析BackupExtensionAbility的注册机制、生命周期回调、备份配置文件和版本管理策略。

核心特点:

  • 简单易用:API 设计直观,上手成本低
  • 性能优异:底层优化充分,运行效率高
  • 扩展性强:支持自定义配置和扩展

本文参考 HarmonyOS 官方文档:application-models.md 和 application-package-structure-stage.md。

一、ExtensionAbility 体系概览

1.1 ExtensionAbility 的设计理念

ExtensionAbility是 HarmonyOS Stage 模型中用于后台任务的基类体系。与UIAbility不同,ExtensionAbility 没有 UI 界面,专注于在后台执行特定类型任务:

图:ExtensionAbility 的各类扩展及其适用场景

扩展类型系统类主要用途
BackupExtensionAbility@kit.CoreFileKit数据备份与恢复
ServiceExtensionAbility@kit.AbilityKit后台常驻服务
FormExtensionAbility@kit.FormKit桌面卡片(Widget)
WorkSchedulerExtensionAbility@kit.BackgroundTasksKit延迟任务调度
InputMethodExtensionAbility@kit.InputMethodKit输入法应用
AccessibilityExtensionAbility@kit.AccessibilityKit无障碍服务

1.2 备份扩展的独特性

在众多 ExtensionAbility 类型中,BackupExtensionAbility有几个独特之处:

  1. 系统自动调度— 备份任务由系统而非用户手动触发,在设备充电、连接 Wi-Fi 且空闲时自动执行
  2. 增量备份机制— 系统只备份发生变化的数据,而非每次都全量备份
  3. 配置驱动— 通过backup_config.json配置文件指定备份范围,无需代码干预
  4. 版本感知— 恢复时携带BundleVersion参数,支持版本兼容性处理
// EntryBackupAbility.ets — 小事记的备份扩展实现 import { hilog } from '@kit.PerformanceAnalysisKit'; import { BackupExtensionAbility, BundleVersion } from '@kit.CoreFileKit'; const DOMAIN = 0x0000; export default class EntryBackupAbility extends BackupExtensionAbility { async onBackup() { hilog.info(DOMAIN, 'testTag', 'onBackup ok'); await Promise.resolve(); } async onRestore(bundleVersion: BundleVersion) { hilog.info(DOMAIN, 'testTag', 'onRestore ok %{public}s', JSON.stringify(bundleVersion)); await Promise.resolve(); } }

二、备份扩展的注册与配置

2.1 在 module.json5 中注册

备份扩展需要在module.json5extensionAbilities数组中注册:

{ "module": { "extensionAbilities": [ { "name": "EntryBackupAbility", "srcEntry": "./ets/entrybackupability/EntryBackupAbility.ets", "type": "backup", "exported": false, "metadata": [ { "name": "ohos.extension.backup", "resource": "$profile:backup_config" } ] } ] } }

各字段详解

字段说明
nameEntryBackupAbility扩展名称,模块内唯一
srcEntry./ets/entrybackupability/EntryBackupAbility.ets实现文件的路径
typebackup扩展类型,必须为backup
exportedfalse不对外暴露,仅系统可调用
metadata包含系统约定的备份配置引用

提示type字段的值必须与系统定义的类型严格一致,"backup"不可拼写为"backupdata""databackup"

2.2 备份配置文件的定义

metadata中的resource: "$profile:backup_config"引用了resources/base/profile/backup_config.json文件,该文件定义了备份的具体范围:

// resources/base/profile/backup_config.json { "allowToBackup": true, "includes": [ "data/storage/el2/database/", "data/storage/el2/base/preferences/" ], "excludes": [ "data/storage/el2/base/cache/", "data/storage/el2/base/temp/" ] }

配置字段说明

字段类型说明是否必须
allowToBackupboolean是否允许备份
includesstring[]需要备份的路径列表
excludesstring[]排除的路径列表
fullBackupOnlyboolean是否仅全量备份

路径规则

  1. 路径相对于data/storage/el2/base/(应用的文件根目录)
  2. 支持目录路径(以/结尾)和文件路径
  3. 不支持通配符(*),但目录路径会递归包含所有子文件

2.3 文件分区模式

备份路径中的el2指的是加密分区模式,HarmonyOS 提供了两种文件分区:

分区模式常量说明存储内容
EL1AreaMode.EL1设备级加密,开机即可访问应用配置、缓存
EL2AreaMode.EL2用户级加密,需要解锁后访问用户数据库、偏好设置
// 获取不同分区的路径 import { common } from '@kit.AbilityKit'; let context = this.context.getApplicationContext(); let el1Path = context.getDatabaseDir(); // EL1 分区数据库路径 let el2Path = context.getPreferencesDir(); // EL2 分区偏好设置路径

小事记的备份配置包含了el2分区的数据库和偏好设置,因为用户的事件数据(LifeEvent)和设置项都存储在这个分区中。

三、onBackup 生命周期详解

3.1 备份触发时机

系统在以下场景会触发onBackup回调:

  1. 设备充电状态— 接入电源后
  2. 网络条件— 连接 Wi-Fi(非蜂窝网络)
  3. 空闲状态— 设备处于空闲状态
  4. 时间间隔— 距离上次备份超过 24 小时

以上条件全部满足时,系统才会触发备份。开发者无法手动触发备份,但可以通过onBackup回调中的代码执行自定义的预处理逻辑。

3.2 onBackup 的完整实现

当前小事记的onBackup只记录了日志,但在生产环境中,应该进行数据完整性校验:

// 增强版 onBackup 实现 import { hilog } from '@kit.PerformanceAnalysisKit'; import { BackupExtensionAbility, BundleVersion } from '@kit.CoreFileKit'; import { fileIo } from '@kit.CoreFileKit'; const DOMAIN = 0x0000; export default class EntryBackupAbility extends BackupExtensionAbility { async onBackup() { hilog.info(DOMAIN, 'testTag', 'onBackup started'); try { // 1. 检查数据库完整性 await this.checkDatabaseIntegrity(); // 2. 清理过期缓存,减少备份体积 await this.cleanExpiredCache(); // 3. 记录备份时间戳 await this.recordBackupTimestamp(); hilog.info(DOMAIN, 'testTag', 'onBackup completed'); } catch (err) { hilog.error(DOMAIN, 'testTag', 'onBackup failed: %{public}s', JSON.stringify(err)); throw err; // 抛出异常,系统会记录备份失败 } } private async checkDatabaseIntegrity(): Promise<void> { // 数据库完整性检查逻辑 // 如果数据损坏,在此处抛出自定义异常 } private async cleanExpiredCache(): Promise<void> { let cacheDir = this.context.cacheDir; // 清理 7 天前的缓存文件 // 减少备份体积 } private async recordBackupTimestamp(): Promise<void> { let lastBackupTime = new Date().toISOString(); // 将备份时间写入偏好设置 // 用于在 UI 中展示"上次备份时间" } }

3.3 备份文件的解密与恢复

系统在备份时会对数据进行加密。备份数据存储在云端,用户无法直接查看备份文件内容,只能通过onRestore恢复。

四、onRestore 生命周期详解

4.1 恢复触发场景

onRestore在以下场景被触发:

  1. 用户在新设备登录— 首次启动应用时,系统检测到云端有备份数据
  2. 应用重装后— 卸载重装后,系统自动恢复备份数据
  3. 跨设备迁移— 通过华为账号将数据从旧设备迁移到新设备

4.2 BundleVersion 版本管理

onRestore的参数BundleVersion包含了备份数据的版本信息,用于处理版本兼容性:

// BundleVersion 的数据结构 interface BundleVersion { major: number; // 主版本号 minor: number; // 次版本号 patch: number; // 补丁版本号 build: number; // 构建号 versionName: string; // 版本名称,如 "1.0.0" }

4.3 版本兼容性处理

在恢复数据时,需要处理备份版本与当前应用版本不同的情况:

// 带版本兼容性处理的 onRestore 实现 async onRestore(bundleVersion: BundleVersion): Promise<void> { hilog.info(DOMAIN, 'testTag', 'onRestore called, version: %{public}s', JSON.stringify(bundleVersion)); try { // 1. 获取当前应用版本 let currentVersion = this.getCurrentAppVersion(); // 2. 版本对比 if (this.isNewerVersion(bundleVersion, currentVersion)) { // 备份版本比当前应用版本新 → 数据降级处理 await this.downgradeData(bundleVersion, currentVersion); } else if (this.isOlderVersion(bundleVersion, currentVersion)) { // 备份版本比当前应用版本旧 → 数据迁移处理 await this.migrateData(bundleVersion, currentVersion); } else { // 版本相同 → 直接恢复 await Promise.resolve(); } // 3. 恢复完成后的回调 this.onRestoreCompleted(); hilog.info(DOMAIN, 'testTag', 'onRestore completed'); } catch (err) { hilog.error(DOMAIN, 'testTag', 'onRestore failed: %{public}s', JSON.stringify(err)); throw err; } } private getCurrentAppVersion(): BundleVersion { // 从 Context 获取当前应用版本号 let appInfo = this.context.applicationInfo; return { major: Math.floor(appInfo.versionCode / 1000000), minor: Math.floor((appInfo.versionCode % 1000000) / 10000), patch: Math.floor((appInfo.versionCode % 10000) / 100), build: appInfo.versionCode % 100, versionName: appInfo.versionName }; } private isNewerVersion(backup: BundleVersion, current: BundleVersion): boolean { if (backup.major > current.major) return true; if (backup.major === current.major && backup.minor > current.minor) return true; return false; } private isOlderVersion(backup: BundleVersion, current: BundleVersion): boolean { if (backup.major < current.major) return true; if (backup.major === current.major && backup.minor < current.minor) return true; return false; } private async downgradeData(backup: BundleVersion, current: BundleVersion): Promise<void> { // 备份版本更新 → 数据降级 // 例如:备份中有新版本才有的字段,需要降级处理 hilog.info(DOMAIN, 'testTag', 'Downgrading data from %{public}s to %{public}s', JSON.stringify(backup), JSON.stringify(current)); } private async migrateData(backup: BundleVersion, current: BundleVersion): Promise<void> { // 备份版本更旧 → 数据迁移 // 例如:数据库 schema 变更,需要执行 ALTER TABLE hilog.info(DOMAIN, 'testTag', 'Migrating data from %{public}s to %{public}s', JSON.stringify(backup), JSON.stringify(current)); } private onRestoreCompleted(): void { // 恢复完成后的回调,例如弹出 Toast 提示用户 hilog.info(DOMAIN, 'testTag', 'Restore completed successfully'); }

4.4 版本号编码规范

小事记的versionCode1000000,对应的版本编码规则如下:

// 版本号编码规则:MAJOR * 1000000 + MINOR * 10000 + PATCH * 100 + BUILD // 1.0.0.0 → 1000000 // 1.1.0.0 → 1010000 // 2.0.0.0 → 2000000
版本名称versionCode分解
1.0.0.01000000major=1, minor=0, patch=0, build=0
1.1.0.01010000major=1, minor=1, patch=0, build=0
1.2.3.41020304major=1, minor=2, patch=3, build=4

五、备份与恢复的数据流

5.1 完整备份流程

[系统触发备份条件] ↓ 系统调用 BackupExtensionAbility.onBackup() ↓ onBackup 中执行预处理(数据校验、清理缓存) ↓ 系统根据 backup_config.json 的 includes 路径收集文件 ↓ 跳过 excludes 路径中的文件 ↓ 系统对文件进行加密和压缩 ↓ 将加密数据上传到云端 ↓ onBackup 返回,备份完成

5.2 完整恢复流程

[用户在新设备安装应用] ↓ 系统检测到云端有备份数据 ↓ 系统调用 BackupExtensionAbility.onRestore() ↓ onRestore 接收 BundleVersion 参数 ↓ 版本对比 → 执行数据迁移或降级 ↓ 系统解密备份数据 ↓ 将数据恢复到 includes 指定的路径 ↓ onRestore 返回,恢复完成 ↓ 用户打开应用,看到已恢复的数据

5.3 备份范围测试

测试场景预期结果测试方法
新增一条事件记录下次备份包含该记录在应用中添加事件,触发备份,恢复后检查
删除一条事件记录下次备份不再包含该记录删除事件,触发备份,恢复后检查
变更应用设置备份包含新设置修改设置项,触发备份,恢复后检查
备份文件完整性恢复后数据完整无误比较备份前后的数据记录总数

六、备份扩展的异常处理

6.1 常见异常场景

异常场景原因处理方式
onBackup超时数据量过大,超过 30 秒分片处理,或减少 includes 范围
备份文件损坏存储介质故障在 onRestore 中增加完整性校验
版本不兼容数据库 schema 变更在 onRestore 中实现数据迁移逻辑
存储空间不足设备空间不足系统会自动跳过备份,记录错误日志

6.2 超时与重试策略

// 大文件备份的超时处理 async onBackup(): Promise<void> { const BACKUP_TIMEOUT = 25000; // 25 秒超时 const timeoutPromise = new Promise((_, reject) => { setTimeout(() => reject(new Error('Backup timeout')), BACKUP_TIMEOUT); }); const backupPromise = this.performBackup(); try { await Promise.race([backupPromise, timeoutPromise]); hilog.info(DOMAIN, 'testTag', 'Backup completed within timeout'); } catch (err) { hilog.error(DOMAIN, 'testTag', 'Backup failed: %{public}s', JSON.stringify(err)); throw err; } } private async performBackup(): Promise<void> { // 实际的备份逻辑 await this.checkDatabaseIntegrity(); await this.cleanExpiredCache(); await this.recordBackupTimestamp(); }

七、区别于 FA 模型的数据备份

7.1 模型对比

对比维度FA 模型Stage 模型
备份方式手动处理文件 IOBackupExtensionAbility 框架
配置方式无标准化配置backup_config.json声明式
加密支持需自行实现系统自动加密
增量备份不支持系统支持
恢复回调onRestore(BundleVersion)版本感知

7.2 迁移建议

从 FA 模型迁移到 Stage 模型时,备份功能的迁移需要注意:

  1. 移除手动文件操作— 不再需要手动拷贝databases/目录下的文件
  2. 添加备份配置— 创建backup_config.json文件声明备份范围
  3. 实现回调方法— 在onBackuponRestore中添加版本兼容性处理
  4. 测试恢复流程— 确保数据在不同版本间可以正确恢复

八、最佳实践总结

8.1 备份配置的推荐策略

{ "allowToBackup": true, "includes": [ "data/storage/el2/database/", // 包含用户数据库 "data/storage/el2/base/preferences/", // 包含偏好设置 "data/storage/el2/base/haps/entry/files/" // 包含用户生成的文件 ], "excludes": [ "data/storage/el2/base/cache/", // 排除缓存 "data/storage/el2/base/temp/", // 排除临时文件 "data/storage/el1/base/preferences/" // 排除设备级配置 ] }

8.2 onBackup 中的注意事项

  1. 不要执行耗时操作— 系统对onBackup有超时限制(30 秒)
  2. 不要修改用户数据onBackup应该只读取数据,不修改数据
  3. 异常必须抛出— 如果备份失败,应该抛出异常让系统感知
  4. 避免网络请求— 备份时的网络状态不可预测

8.3 onRestore 中的注意事项

  1. 版本号必须校验— 确保备份数据与当前应用版本兼容
  2. 数据迁移必须幂等— 多次恢复同一个备份,结果应该一致
  3. 恢复失败要回滚— 如果恢复过程中出现错误,应该回滚到初始状态
  4. 用户数据优先— 恢复时不要覆盖用户当前已有的新数据

总结

本文从xiaoshiji_ohos_app项目的EntryBackupAbility.ets出发,深入解析了 HarmonyOSBackupExtensionAbility的注册机制、生命周期回调、备份配置文件和版本管理策略。核心要点如下:

  1. 注册机制:在module.json5中通过extensionAbilities注册,typebackup,通过metadata引用backup_config.json配置文件
  2. 备份配置:通过backup_config.jsonincludes/excludes声明式指定备份范围,系统自动处理文件加密和传输
  3. onBackup:系统在充电+Wi-Fi+空闲时自动触发,开发者可在此执行数据校验和缓存清理
  4. onRestore:接收BundleVersion参数,需要实现版本兼容性处理(数据迁移/降级)
  5. 版本管理versionCode编码规范(MAJOR1000000 + MINOR10000 + PATCH*100 + BUILD)确保版本号能精确比较

下一篇文章将深入解析应用包结构:HAP/HSP/HAR 的三层架构与 deliveryWithInstall 策略

如果这篇文章对你有帮助,欢迎点赞👍、收藏⭐、关注🔔,你的支持是我持续创作的动力!


相关资源:

  • 小事记项目源码:xiaoshiji_ohos_app
  • 官方文档 - 应用模型:application-models.md
  • 官方文档 - 包结构:application-package-structure-stage.md
  • 官方文档 - 包开发:application-package-dev.md
  • 官方文档 - 包基础:application-package-fundamentals.md
  • 官方文档 - 安装卸载:application-package-install-uninstall.md
  • 官方文档 - 配置文件:application-configuration-file-stage.md
  • 开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询