备份恢复模块 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 层的用户界面和交互,结合原生层的文件管理,为用户提供了完整的数据安全保护。

相关推荐
程序猿零零漆2 小时前
Spring之旅 - 记录学习 Spring 框架的过程和经验(五)Spring的后处理器BeanFactoryPostProcessor
java·学习·spring
虾说羊2 小时前
java中的反射详解
java·开发语言
特立独行的猫a2 小时前
C++23 std::expected 详解:告别传统错误码和异常,构建现代健壮代码
开发语言·c++23·expected·错误码处理
星火飞码iFlyCode2 小时前
iFlyCode实践规范驱动开发(SDD):招考平台报名相片质量抽检功能开发实战
java·前端·python·算法·ai编程·科大讯飞
廋到被风吹走2 小时前
【Spring】HandlerInterceptor解析
java·后端·spring
leaves falling2 小时前
c语言-根据输入的年份和月份,计算并输出该月份的天数
c语言·开发语言·算法
云栖梦泽2 小时前
鸿蒙企业级工程化与终极性能调优实战
开发语言·鸿蒙系统
毛小茛2 小时前
若依框架搭建基础知识
java
Eloudy2 小时前
通过示例看 C++ 函数对象、仿函数、operator( )
开发语言·c++·算法
2501_937193142 小时前
中兴机顶盒纯净固件|多机型适配+刷机解析
android·源码·源代码管理·机顶盒