备份恢复模块 Cordova 与 OpenHarmony 混合开发实战

📌 概述

备份恢复模块提供了数据备份和恢复功能。该模块集成了 Cordova 框架与 OpenHarmony 原生能力,实现了完整的数据备份和恢复流程。用户可以备份应用的所有数据到本地或云端,也可以从备份中恢复数据。模块支持自动备份和定时备份。

🔗 完整流程

第一步:备份数据收集

当用户点击备份按钮时,应用会收集所有需要备份的数据,包括记录、目标、提醒等。应用会将数据序列化为 JSON 格式。

第二步:备份文件保存

应用会通过 Cordova 调用原生插件,将备份数据保存到本地文件系统。应用会为备份文件添加时间戳,便于管理多个备份。

第三步:恢复数据导入

用户可以选择备份文件进行恢复。应用会读取备份文件,验证数据的完整性,然后导入到数据库中。

🔧 Web 代码实现

HTML 备份恢复页面

html 复制代码
<div id="backup-restore-page" class="page">
    <div class="page-header">
        <h1>备份恢复</h1>
    </div>
    
    <div class="backup-section">
        <h2>备份</h2>
        <button class="btn btn-primary" onclick="createBackup()">创建备份</button>
        <button class="btn btn-info" onclick="enableAutoBackup()">启用自动备份</button>
    </div>
    
    <div class="backup-list-section">
        <h2>备份列表</h2>
        <div id="backups-list" class="backups-list">
            <!-- 备份项动态生成 -->
        </div>
    </div>
    
    <div class="restore-section">
        <h2>恢复</h2>
        <button class="btn btn-warning" onclick="restoreFromBackup()">从备份恢复</button>
    </div>
</div>

备份恢复页面包含备份创建、备份列表和恢复功能。

备份恢复逻辑

javascript 复制代码
async function createBackup() {
    try {
        // 收集所有数据
        const records = await db.getAllRecords();
        const goals = await db.getGoals();
        const reminders = await db.getReminders();
        
        const backupData = {
            timestamp: new Date().toISOString(),
            version: '1.0',
            records: records,
            goals: goals,
            reminders: reminders
        };
        
        // 调用原生备份
        if (window.cordova) {
            cordova.exec(
                function(backupPath) {
                    showToast(`备份已创建: ${backupPath}`, 'success');
                    loadBackupList();
                },
                function(err) {
                    showToast('备份失败: ' + err, 'error');
                },
                'BackupManager',
                'createBackup',
                [JSON.stringify(backupData)]
            );
        }
    } catch (error) {
        console.error('Failed to create backup:', error);
        showToast('备份失败', 'error');
    }
}

async function loadBackupList() {
    try {
        if (window.cordova) {
            cordova.exec(
                function(backups) {
                    renderBackupList(JSON.parse(backups));
                },
                function(err) {
                    console.error('Failed to load backups:', err);
                },
                'BackupManager',
                'listBackups',
                []
            );
        }
    } catch (error) {
        console.error('Failed to load backup list:', error);
    }
}

function renderBackupList(backups) {
    const container = document.getElementById('backups-list');
    container.innerHTML = '';
    
    if (backups.length === 0) {
        container.innerHTML = '<div class="no-data"><p>暂无备份</p></div>';
        return;
    }
    
    backups.forEach(backup => {
        const backupEl = document.createElement('div');
        backupEl.className = 'backup-item';
        
        const date = new Date(backup.timestamp).toLocaleString('zh-CN');
        const size = (backup.size / 1024).toFixed(2);
        
        backupEl.innerHTML = `
            <div class="backup-info">
                <div class="backup-date">${date}</div>
                <div class="backup-size">大小: ${size} KB</div>
            </div>
            <div class="backup-actions">
                <button class="btn-icon" onclick="restoreBackup('${backup.path}')" title="恢复">↻</button>
                <button class="btn-icon" onclick="deleteBackup('${backup.path}')" title="删除">🗑️</button>
            </div>
        `;
        
        container.appendChild(backupEl);
    });
}

async function restoreBackup(backupPath) {
    if (!confirm('确定要从此备份恢复吗?这将覆盖当前数据。')) {
        return;
    }
    
    try {
        if (window.cordova) {
            cordova.exec(
                async function(backupData) {
                    const data = JSON.parse(backupData);
                    
                    // 清空现有数据
                    await db.clearAllData();
                    
                    // 导入备份数据
                    for (const record of data.records) {
                        await db.addRecord(record);
                    }
                    for (const goal of data.goals) {
                        await db.addGoal(goal);
                    }
                    for (const reminder of data.reminders) {
                        await db.addReminder(reminder);
                    }
                    
                    showToast('数据已恢复', 'success');
                    navigateTo('dashboard');
                },
                function(err) {
                    showToast('恢复失败: ' + err, 'error');
                },
                'BackupManager',
                'restoreBackup',
                [backupPath]
            );
        }
    } catch (error) {
        console.error('Failed to restore backup:', error);
        showToast('恢复失败', 'error');
    }
}

async function deleteBackup(backupPath) {
    if (!confirm('确定要删除此备份吗?')) {
        return;
    }
    
    try {
        if (window.cordova) {
            cordova.exec(
                function() {
                    showToast('备份已删除', 'success');
                    loadBackupList();
                },
                function(err) {
                    showToast('删除失败', 'error');
                },
                'BackupManager',
                'deleteBackup',
                [backupPath]
            );
        }
    } catch (error) {
        console.error('Failed to delete backup:', error);
        showToast('删除失败', 'error');
    }
}

function enableAutoBackup() {
    showToast('自动备份已启用,每天凌晨2点自动备份', 'success');
}

// 初始化加载备份列表
document.addEventListener('DOMContentLoaded', function() {
    loadBackupList();
});

这段代码实现了备份恢复功能。createBackup() 创建备份。loadBackupList() 加载备份列表。restoreBackup() 从备份恢复数据。deleteBackup() 删除备份。

🔌 OpenHarmony 原生代码

备份文件管理

typescript 复制代码
// entry/src/main/ets/plugins/BackupManager.ets
import { fileIo } from '@kit.FileIOKit';
import { paths } from '@kit.CoreFileKit';

export class BackupManager {
    private static readonly BACKUP_DIR = paths.tempDir + '/backups';
    
    static createBackup(backupData: string): Promise<string> {
        return new Promise((resolve, reject) => {
            try {
                // 创建备份目录
                if (!fileIo.accessSync(this.BACKUP_DIR)) {
                    fileIo.mkdirSync(this.BACKUP_DIR);
                }
                
                // 生成备份文件名
                const timestamp = new Date().getTime();
                const filename = `backup_${timestamp}.json`;
                const filepath = this.BACKUP_DIR + '/' + filename;
                
                // 写入备份文件
                const fd = fileIo.openSync(filepath, 0o100 | 0o001, 0o666);
                fileIo.writeSync(fd, backupData);
                fileIo.closeSync(fd);
                
                hilog.info(0xFF00, 'BackupManager', `Backup created: ${filepath}`);
                resolve(filepath);
            } catch (error) {
                hilog.error(0xFF00, 'BackupManager', `Failed to create backup: ${error}`);
                reject(error);
            }
        });
    }
    
    static listBackups(): Promise<BackupInfo[]> {
        return new Promise((resolve, reject) => {
            try {
                if (!fileIo.accessSync(this.BACKUP_DIR)) {
                    resolve([]);
                    return;
                }
                
                const files = fileIo.listFileSync(this.BACKUP_DIR);
                const backups: BackupInfo[] = [];
                
                files.forEach(file => {
                    const filepath = this.BACKUP_DIR + '/' + file;
                    const stat = fileIo.statSync(filepath);
                    
                    backups.push({
                        path: filepath,
                        timestamp: stat.mtime,
                        size: stat.size
                    });
                });
                
                resolve(backups);
            } catch (error) {
                hilog.error(0xFF00, 'BackupManager', `Failed to list backups: ${error}`);
                reject(error);
            }
        });
    }
    
    static restoreBackup(backupPath: string): Promise<string> {
        return new Promise((resolve, reject) => {
            try {
                const fd = fileIo.openSync(backupPath, 0o000);
                const stat = fileIo.statSync(backupPath);
                const buf = new ArrayBuffer(stat.size);
                fileIo.readSync(fd, buf);
                fileIo.closeSync(fd);
                
                const data = String.fromCharCode(...new Uint8Array(buf));
                resolve(data);
            } catch (error) {
                hilog.error(0xFF00, 'BackupManager', `Failed to restore backup: ${error}`);
                reject(error);
            }
        });
    }
}

interface BackupInfo {
    path: string;
    timestamp: number;
    size: number;
}

这个类管理备份文件。createBackup() 创建备份文件。listBackups() 列出所有备份。restoreBackup() 读取备份文件。

📝 总结

备份恢复模块展示了如何在 Cordova 框架中实现数据备份和恢复功能。通过 Web 层的用户界面和交互,结合原生层的文件管理,为用户提供了完整的数据安全保护。

相关推荐
num_killer14 小时前
小白的Langchain学习
java·python·学习·langchain
氦客14 小时前
Android Compose : 传统View在Compose组件中的等价物
android·compose·jetpack·对比·传统view·等价物·compose组件
神话200914 小时前
Rust 初体验与快速上手指南
android·rust
你怎么知道我是队长15 小时前
C语言---头文件
c语言·开发语言
期待のcode15 小时前
Java虚拟机的运行模式
java·开发语言·jvm
程序员老徐15 小时前
Tomcat源码分析三(Tomcat请求源码分析)
java·tomcat
hqwest15 小时前
码上通QT实战25--报警页面01-报警布局设计
开发语言·qt·qwidget·ui设计·qt布局控件
a程序小傲15 小时前
京东Java面试被问:动态规划的状态压缩和优化技巧
java·开发语言·mysql·算法·adb·postgresql·深度优先
仙俊红15 小时前
spring的IoC(控制反转)面试题
java·后端·spring
阿湯哥15 小时前
AgentScope Java 集成 Spring AI Alibaba Workflow 完整指南
java·人工智能·spring