自动更新 #

一、自动更新概述 #

1.1 更新流程 #

text
┌─────────────────────────────────────────────────────────────┐
│                     自动更新流程                             │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  ┌─────────────┐                                            │
│  │   应用启动   │                                            │
│  └──────┬──────┘                                            │
│         │                                                   │
│         ▼                                                   │
│  ┌─────────────┐                                            │
│  │   检查更新   │◄─────────────────────┐                    │
│  └──────┬──────┘                      │                    │
│         │                             │                    │
│         ▼                             │                    │
│  ┌─────────────┐     无更新           │                    │
│  │  有新版本?  │─────────────────────┤                    │
│  └──────┬──────┘                      │                    │
│         │ 有更新                       │                    │
│         ▼                             │                    │
│  ┌─────────────┐                      │                    │
│  │   下载更新   │                      │                    │
│  └──────┬──────┘                      │                    │
│         │                             │                    │
│         ▼                             │                    │
│  ┌─────────────┐                      │                    │
│  │   安装更新   │                      │                    │
│  └──────┬──────┘                      │                    │
│         │                             │                    │
│         ▼                             │                    │
│  ┌─────────────┐                      │                    │
│  │   重启应用   │──────────────────────┘                    │
│  └─────────────┘                                           │
│                                                             │
└─────────────────────────────────────────────────────────────┘

1.2 更新方式 #

方式 说明 适用场景
全量更新 下载完整安装包 大版本更新
增量更新 只下载差异文件 小版本更新
热更新 只更新渲染进程 Web 资源更新

二、electron-updater #

2.1 安装 #

bash
npm install electron-updater

2.2 基本配置 #

json
// package.json
{
    "build": {
        "publish": {
            "provider": "github",
            "owner": "your-username",
            "repo": "your-repo"
        }
    }
}

2.3 主进程更新逻辑 #

javascript
// electron/main/updater.js
const { autoUpdater } = require('electron-updater');
const { dialog, BrowserWindow } = require('electron');

let mainWindow;

function setupAutoUpdater(window) {
    mainWindow = window;
    
    // 设置更新服务器
    autoUpdater.setFeedURL({
        provider: 'github',
        owner: 'your-username',
        repo: 'your-repo'
    });
    
    // 检查更新失败
    autoUpdater.on('error', (error) => {
        console.error('更新检查失败:', error);
        dialog.showErrorBox('更新错误', error.message);
    });
    
    // 检查更新中
    autoUpdater.on('checking-for-update', () => {
        console.log('正在检查更新...');
    });
    
    // 发现新版本
    autoUpdater.on('update-available', (info) => {
        console.log('发现新版本:', info.version);
        dialog.showMessageBox(mainWindow, {
            type: 'info',
            title: '发现新版本',
            message: `发现新版本 ${info.version},是否立即下载?`,
            buttons: ['下载', '稍后提醒']
        }).then((result) => {
            if (result.response === 0) {
                autoUpdater.downloadUpdate();
            }
        });
    });
    
    // 没有新版本
    autoUpdater.on('update-not-available', (info) => {
        console.log('当前已是最新版本');
    });
    
    // 下载进度
    autoUpdater.on('download-progress', (progress) => {
        const percent = progress.percent.toFixed(1);
        const transferred = (progress.transferred / 1024 / 1024).toFixed(1);
        const total = (progress.total / 1024 / 1024).toFixed(1);
        
        console.log(`下载进度: ${percent}% (${transferred}MB / ${total}MB)`);
        
        // 发送进度到渲染进程
        mainWindow?.webContents.send('update-progress', {
            percent,
            transferred,
            total
        });
    });
    
    // 下载完成
    autoUpdater.on('update-downloaded', (info) => {
        console.log('更新下载完成');
        
        dialog.showMessageBox(mainWindow, {
            type: 'info',
            title: '更新就绪',
            message: '新版本已下载完成,是否立即安装?',
            buttons: ['立即安装', '稍后安装']
        }).then((result) => {
            if (result.response === 0) {
                autoUpdater.quitAndInstall();
            }
        });
    });
}

// 检查更新
function checkForUpdates() {
    autoUpdater.checkForUpdates();
}

// 手动检查更新
function checkForUpdatesAndNotify() {
    autoUpdater.checkForUpdatesAndNotify();
}

module.exports = {
    setupAutoUpdater,
    checkForUpdates,
    checkForUpdatesAndNotify
};

2.4 初始化更新 #

javascript
// electron/main/index.js
const { app, BrowserWindow } = require('electron');
const { setupAutoUpdater, checkForUpdates } = require('./updater');

let mainWindow;

app.whenReady().then(() => {
    mainWindow = new BrowserWindow({...});
    
    // 设置自动更新
    setupAutoUpdater(mainWindow);
    
    // 启动时检查更新
    if (!isDev) {
        checkForUpdates();
    }
});

三、更新通知 #

3.1 渲染进程通知 #

javascript
// preload.js
const { contextBridge, ipcRenderer } = require('electron');

contextBridge.exposeInMainWorld('electronAPI', {
    onUpdateProgress: (callback) => {
        ipcRenderer.on('update-progress', (event, progress) => {
            callback(progress);
        });
    },
    
    checkForUpdates: () => {
        ipcRenderer.invoke('check-for-updates');
    }
});
javascript
// renderer.js
// 监听更新进度
window.electronAPI.onUpdateProgress((progress) => {
    console.log(`下载进度: ${progress.percent}%`);
    updateProgressBar(progress.percent);
});

// 手动检查更新
document.getElementById('check-update').addEventListener('click', () => {
    window.electronAPI.checkForUpdates();
});

3.2 自定义更新 UI #

javascript
// electron/main/updater.js
class UpdateManager {
    constructor(mainWindow) {
        this.mainWindow = mainWindow;
        this.updateInfo = null;
    }
    
    showUpdateNotification(info) {
        this.mainWindow.webContents.send('update-available', info);
    }
    
    showDownloadProgress(progress) {
        this.mainWindow.webContents.send('download-progress', progress);
    }
    
    showUpdateReady(info) {
        this.mainWindow.webContents.send('update-ready', info);
    }
}

四、更新服务器 #

4.1 GitHub Releases #

json
// package.json
{
    "build": {
        "publish": {
            "provider": "github",
            "owner": "your-username",
            "repo": "your-repo",
            "releaseType": "release"
        }
    }
}

4.2 私有服务器 #

json
{
    "build": {
        "publish": {
            "provider": "generic",
            "url": "https://updates.example.com/"
        }
    }
}
javascript
// 服务器目录结构
// https://updates.example.com/
// ├── latest.yml          (Windows)
// ├── latest-mac.yml      (macOS)
// ├── latest-linux.yml    (Linux)
// ├── my-app-1.0.0.exe
// ├── my-app-1.0.0.dmg
// └── my-app-1.0.0.AppImage

4.3 S3/CDN #

json
{
    "build": {
        "publish": {
            "provider": "s3",
            "bucket": "my-app-updates",
            "region": "us-east-1",
            "path": "updates/"
        }
    }
}

五、更新配置 #

5.1 自动下载配置 #

javascript
// electron-builder.yml
publish:
    provider: github
    owner: your-username
    repo: your-repo

# 自动下载更新
autoUpdater:
    autoDownload: false  # 不自动下载
    autoInstallOnAppQuit: true  # 退出时自动安装
javascript
// main.js
autoUpdater.autoDownload = false;  // 手动控制下载
autoUpdater.autoInstallOnAppQuit = true;  // 退出时安装

5.2 更新频率 #

javascript
// 定时检查更新
function scheduleUpdateCheck() {
    // 每小时检查一次
    setInterval(() => {
        autoUpdater.checkForUpdates();
    }, 60 * 60 * 1000);
    
    // 或每天检查一次
    const checkTime = new Date();
    checkTime.setHours(10, 0, 0, 0);  // 每天 10:00
    
    const delay = checkTime - Date.now();
    setTimeout(() => {
        autoUpdater.checkForUpdates();
        scheduleUpdateCheck();
    }, delay);
}

5.3 增量更新 #

yaml
# electron-builder.yml
nsis:
    differentialPackage: true

六、更新日志 #

6.1 显示更新日志 #

javascript
// electron/main/updater.js
autoUpdater.on('update-available', async (info) => {
    // 获取更新日志
    const releaseNotes = info.releaseNotes;
    
    mainWindow.webContents.send('update-available', {
        version: info.version,
        releaseDate: info.releaseDate,
        releaseNotes: releaseNotes
    });
});
javascript
// renderer.js
window.electronAPI.onUpdateAvailable((info) => {
    showUpdateDialog({
        version: info.version,
        changes: info.releaseNotes
    });
});

6.2 CHANGELOG 格式 #

markdown
## [1.1.0] - 2024-01-15

### Added
- 新功能 A
- 新功能 B

### Changed
- 改进 C

### Fixed
- 修复 D

七、回滚机制 #

7.1 版本回滚 #

javascript
// 存储上一版本信息
const Store = require('electron-store');
const store = new Store({ name: 'app-state' });

// 检测是否回滚
function checkRollback() {
    const lastVersion = store.get('lastVersion');
    const currentVersion = app.getVersion();
    
    if (lastVersion && lastVersion !== currentVersion) {
        // 版本变化
        const versionCompare = compareVersions(currentVersion, lastVersion);
        
        if (versionCompare < 0) {
            // 版本回滚
            console.log('检测到版本回滚');
        }
    }
    
    store.set('lastVersion', currentVersion);
}

7.2 更新失败处理 #

javascript
autoUpdater.on('error', (error) => {
    console.error('更新失败:', error);
    
    // 记录失败信息
    const failedUpdates = store.get('failedUpdates', []);
    failedUpdates.push({
        version: autoUpdater.currentVersion,
        error: error.message,
        timestamp: new Date().toISOString()
    });
    store.set('failedUpdates', failedUpdates);
    
    // 提示用户手动下载
    dialog.showMessageBox(mainWindow, {
        type: 'error',
        title: '更新失败',
        message: '自动更新失败,请手动下载最新版本',
        buttons: ['前往下载', '取消']
    }).then((result) => {
        if (result.response === 0) {
            shell.openExternal('https://github.com/user/repo/releases');
        }
    });
});

八、最佳实践 #

8.1 更新检查清单 #

markdown
- [ ] 配置更新服务器
- [ ] 实现更新检查逻辑
- [ ] 添加下载进度显示
- [ ] 实现安装提示
- [ ] 处理更新错误
- [ ] 测试更新流程

8.2 更新测试 #

javascript
// 开发环境测试更新
if (isDev) {
    autoUpdater.updateConfigPath = path.join(__dirname, 'dev-app-update.yml');
}

// dev-app-update.yml
owner: your-username
repo: your-repo
provider: github

九、总结 #

9.1 核心要点 #

要点 说明
electron-updater 推荐的更新库
更新服务器 GitHub/私有服务器
更新流程 检查→下载→安装→重启
进度通知 通知渲染进程
错误处理 处理更新失败

9.2 下一步 #

现在你已经掌握了自动更新机制,接下来让我们学习 代码签名,深入了解各平台的代码签名流程!

最后更新:2026-03-28