导入导出-Cordova&openharmony数据迁移实践
本文介绍了一个喝水记录应用的跨设备数据迁移方案,通过Web层和原生插件结合实现数据导入导出功能。主要内容包括: 在Web端设计简洁的导入导出界面,提供JSON文件下载和选择功能; 使用IndexedDB存储数据,并通过JavaScript实现数据收集、序列化为JSON和触发下载; 通过文件选择器读取JSON文件并验证数据后写入数据库; 结合OpenHarmony ArkTS插件提供原生侧文件管理能

一、功能概述
喝水记录应用虽然是本地应用,但很多用户会在更换设备或重装系统时希望"带走自己的喝水历史"。因此,一个可靠的"数据导出/导入"能力非常重要。本篇文章围绕"导入导出"模块展开,介绍如何在 Cordova Web 层 将 IndexedDB 中的记录序列化为 JSON 文件,并通过文件选择器导入外部 JSON;同时结合 OpenHarmony ArkTS 插件,在原生侧提供文件保存目录选择或导出结果提示等能力。
和前面的文章一样,我们将采用"一段代码一段说明"的结构,通过 HTML/JavaScript 和 ArkTS 示例,构建一条完整的数据迁移动线。
二、Web 端导出/导入界面结构
<div id="data-transfer-page" class="page page-data-transfer">
<h1>数据导入导出</h1>
<div class="transfer-actions">
<button id="btn-export" class="btn-primary">导出数据为 JSON</button>
<button id="btn-import" class="btn-secondary">从 JSON 导入数据</button>
</div>
<p id="transfer-status" class="text-muted"></p>
</div>
这段 HTML 定义了数据迁移页面的基本结构。两个按钮分别负责触发导出和导入操作,transfer-status 用于展示操作结果或错误信息。界面设计刻意保持简洁,让用户一眼就能理解两个核心操作:将当前数据导出为 JSON 文件,或从已有 JSON 文件中恢复数据。
.page-data-transfer {
padding: 16px 24px;
}
.transfer-actions {
display: flex;
gap: 12px;
margin-bottom: 12px;
}
CSS 为页面添加内边距,并使用 flex 布局将两个按钮横向排列,适当增加间距,避免误触。状态文本 transfer-status 可以通过全局样式中的 .text-muted 控制颜色和字号,与应用中其他提示文案保持一致。
三、导出:从 IndexedDB 收集数据并生成 JSON
async function exportData() {
const records = await db.getAllDrinkRecords();
const types = await db.getAllDrinkTypes();
const containers = await db.getAllContainers();
const payload = {
version: 1,
exportedAt: new Date().toISOString(),
records,
types,
containers,
};
const json = JSON.stringify(payload, null, 2);
triggerDownload(json, 'water-tracker-backup.json');
updateTransferStatus('导出完成:已生成 JSON 文件');
}
exportData 函数负责从 IndexedDB 中收集需要迁移的全部数据,并打包为一个 JSON 对象。这里示例性地导出三张表:喝水记录 records、类型 types 和容器 containers,并额外保存版本号和导出时间,便于以后做兼容性处理。通过 JSON.stringify 将对象转换为字符串后,调用 triggerDownload 生成一个可下载的文件,文件名设为 water-tracker-backup.json。最后调用 updateTransferStatus 在页面上更新导出状态.
function triggerDownload(content, filename) {
const blob = new Blob([content], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = filename;
a.click();
URL.revokeObjectURL(url);
}
triggerDownload 使用浏览器原生的 Blob 和 URL API 创建一个临时的下载链接,并模拟点击行为触发下载。通过这种方式,用户可以直接在浏览器中保存一个包含所有关键数据的 JSON 文件,无需依赖额外插件。在 HarmonyOS Cordova 环境中,ArkWeb 也支持类似的下载行为,只是具体存储路径会由系统文件管理器来决定。
function updateTransferStatus(message) {
const p = document.getElementById('transfer-status');
if (!p) return;
p.textContent = message;
}
updateTransferStatus 是一个小型辅助函数,用于将最近一次导入/导出操作的状态文案展示在页面上。这样用户在点击按钮后可以清楚知道当前操作是否成功,以及接下来需要做什么(例如"请保存下载的文件")。
四、导入:通过文件选择器读取 JSON 并写入数据库
function bindImportButton() {
const btnImport = document.getElementById('btn-import');
if (!btnImport) return;
btnImport.addEventListener('click', () => {
const input = document.createElement('input');
input.type = 'file';
input.accept = 'application/json';
input.addEventListener('change', () => {
if (!input.files || input.files.length === 0) return;
const file = input.files[0];
readImportFile(file);
});
input.click();
});
}
bindImportButton 为"从 JSON 导入数据"按钮绑定点击事件。点击时动态创建一个隐藏的 <input type="file"> 元素,并限制文件类型为 JSON。当用户选择文件后,触发 change 事件,从 input.files 中取出第一个文件,交给 readImportFile 进行解析。通过这种方式,我们可以完全基于 Web API 完成文件选择流程,与底层平台(包括 HarmonyOS)无关。
function readImportFile(file) {
const reader = new FileReader();
reader.onload = async () => {
try {
const text = reader.result as string;
const payload = JSON.parse(text);
await applyImportedData(payload);
updateTransferStatus('导入完成:数据已写入本地数据库');
} catch (err) {
console.error('[Import] parse or apply failed', err);
updateTransferStatus('导入失败:文件格式不正确或数据损坏');
}
};
reader.readAsText(file);
}
readImportFile 使用 FileReader API 读取用户选择的 JSON 文件。在 onload 回调中,先通过 JSON.parse 解析文件内容为对象,然后调用 applyImportedData 将数据写入 IndexedDB。如果解析或写入过程中出现错误,会捕获异常并向用户展示友好的错误提示。通过这种错误处理,用户不会因为导入失败而丢失现有数据。
async function applyImportedData(payload) {
if (!payload.records || !Array.isArray(payload.records)) {
throw new Error('Invalid payload: missing records array');
}
for (const record of payload.records) {
await db.addDrinkRecord(record);
}
if (payload.types && Array.isArray(payload.types)) {
for (const type of payload.types) {
await db.addDrinkType(type);
}
}
}
applyImportedData 负责将导入的数据逐条写入 IndexedDB。首先验证 payload 中是否包含有效的 records 数组,如果不存在则抛出错误。随后遍历每条记录并调用 db.addDrinkRecord 写入数据库;如果还有类型数据,也一并导入。通过这种逐条写入的方式,可以更精细地控制导入过程,并在某条数据有问题时及时发现。
document.addEventListener('DOMContentLoaded', () => {
document.getElementById('btn-export')?.addEventListener('click', exportData);
bindImportButton();
});
在 DOMContentLoaded 事件中绑定导出按钮和导入按钮的事件处理器,确保页面加载完成后用户可以立即使用这两个功能。
五、通过 Cordova 通知原生层导出完成
function syncExportStatusToNative(success, filename) {
if (!window.cordova) {
console.warn('[DataTransfer] cordova not ready, skip native sync');
return;
}
cordova.exec(
() => {
console.info('[DataTransfer] sync export status success');
},
(err) => {
console.error('[DataTransfer] sync export status failed', err);
},
'WaterTrackerDataTransfer',
'onExportComplete',
[{ success, filename }]
);
}
syncExportStatusToNative 在导出完成后通知 ArkTS 插件。通过传递 success 标志和文件名,原生侧可以决定是否展示一个"导出成功"的通知,或者提供一个"打开文件所在目录"的快捷操作。这种反向通知机制让原生层能够参与到 Web 的数据迁移流程中,提升整体用户体验。
六、OpenHarmony ArkTS 插件与数据迁移
// entry/src/main/ets/plugins/WaterTrackerDataTransferPlugin.ets
import common from '@ohos.app.ability.common';
export interface ExportStatus {
success: boolean;
filename: string;
}
export class DataTransferStore {
private static _lastExportStatus: ExportStatus | null = null;
static setLastExportStatus(status: ExportStatus) {
this._lastExportStatus = status;
}
static get lastExportStatus() {
return this._lastExportStatus;
}
}
export default class WaterTrackerDataTransferPlugin {
context: common.UIAbilityContext;
constructor(ctx: common.UIAbilityContext) {
this.context = ctx;
}
onExportComplete(args: Array<Object>, callbackId: number) {
const status = args[0] as ExportStatus;
DataTransferStore.setLastExportStatus(status);
console.info(`[DataTransferPlugin] export ${status.success ? 'success' : 'failed'}`);
}
}
ArkTS 侧的 WaterTrackerDataTransferPlugin 插件接收来自 Web 的导出状态,并通过 DataTransferStore 缓存最新结果。这样 ArkUI 组件可以随时读取导出状态,并据此展示相应的提示或操作按钮。
七、ArkUI 中展示导出结果
// entry/src/main/ets/pages/DataTransferPage.ets
import { DataTransferStore } from '../plugins/WaterTrackerDataTransferPlugin';
@Component
struct DataTransferView {
build() {
const status = DataTransferStore.lastExportStatus;
Column() {
Text('数据迁移状态')
.fontSize(18)
.margin({ bottom: 8 });
if (status) {
Text(`上次导出:${status.success ? '成功' : '失败'}`)
.fontSize(14);
if (status.success) {
Text(`文件名:${status.filename}`)
.fontSize(14)
.margin({ top: 4 });
}
} else {
Text('暂无导出记录')
.fontSize(14);
}
}
.padding(16)
}
}
DataTransferView 组件在原生界面中展示最近一次导出的状态。如果导出成功,会显示文件名;如果失败,则显示相应提示。这样用户在原生页面也能了解到数据迁移的进度和结果。
八、小结
本篇文章从导出表单、JSON 生成、文件下载到导入选择、文件解析、数据写入,再到 Cordova 桥接和 ArkTS 插件,完整演示了"导入导出"在 Cordova&openharmony 混合应用中的实现路径。Web 层通过 exportData 和 triggerDownload 实现了数据导出,通过 bindImportButton 和 readImportFile 实现了数据导入;syncExportStatusToNative 则将导出结果推送给原生侧,ArkTS 侧通过 DataTransferStore 和 WaterTrackerDataTransferPlugin 缓存状态,ArkUI 组件 DataTransferView 则提供原生展示入口。
通过"一段代码一段说明"的方式,我们把整个数据迁移流程拆解得足够细致。你可以在此基础上进一步扩展,例如添加数据验证、版本兼容性处理、加密导出等功能,让"导入导出"真正成为用户在设备迁移或数据备份时的可靠助手.
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
更多推荐


所有评论(0)