第 9 章:自动更新与崩溃监控
应用发布后,你需要持续迭代和修复问题。本章将学习如何实现自动更新机制,让用户始终使用最新版本, 以及集成崩溃监控系统,及时发现和修复生产环境的问题。
9.1 自动更新概述
Electron 应用不像 Web 应用那样刷新就能获得更新。你需要实现自动更新机制,在后台下载新版本并提示用户安装。
electron-updater 是社区维护的自动更新库,支持 Windows、macOS 和 Linux。
把自动更新想象成 PWA 的 Service Worker 更新机制:检测到新版本 → 后台下载 → 提示用户刷新(重启)。 只不过 Electron 的"刷新"是重启整个应用。
自动更新流程
┌─────────────────────────────────────────────────────────┐
│ 自动更新流程 │
├─────────────────────────────────────────────────────────┤
│ 1. 应用启动时检查更新 │
│ ↓ │
│ 2. 向更新服务器查询最新版本 │
│ ↓ │
│ 3. 发现新版本,开始后台下载 │
│ ↓ │
│ 4. 下载完成,提示用户安装 │
│ ↓ │
│ 5. 用户确认后,退出并安装更新 │
│ ↓ │
│ 6. 应用重启,运行新版本 │
└─────────────────────────────────────────────────────────┘
9.2 配置 electron-updater
electron-updater 已经内置在 electron-builder 中,无需额外安装。只需要配置更新服务器即可。
安装与配置
# electron-updater 已包含在 electron-builder 中
# 如果需要单独安装:
npm install electron-updater
// main.js - 自动更新配置
const { app } = require('electron');
const { autoUpdater } = require('electron-updater');
const log = require('electron-log');
// 配置日志
autoUpdater.logger = log;
autoUpdater.logger.transports.file.level = 'info';
// 检查更新(开发环境也可以测试)
function setupAutoUpdater(mainWindow) {
// 配置更新服务器(使用 GitHub Releases)
// 需要在 electron-builder.yml 中配置 publish 选项
// ===== 更新事件 =====
// 发现可用更新
autoUpdater.on('update-available', (info) => {
log.info('发现新版本:', info.version);
mainWindow.webContents.send('update-available', {
version: info.version,
releaseDate: info.releaseDate,
releaseNotes: info.releaseNotes
});
});
// 没有可用更新
autoUpdater.on('update-not-available', () => {
log.info('当前已是最新版本');
});
// 下载进度
autoUpdater.on('download-progress', (progress) => {
const percent = Math.round(progress.percent);
log.info(`下载进度: ${percent}%`);
mainWindow.webContents.send('update-progress', { percent });
});
// 下载完成
autoUpdater.on('update-downloaded', (info) => {
log.info('更新下载完成:', info.version);
mainWindow.webContents.send('update-downloaded', {
version: info.version
});
});
// 错误处理
autoUpdater.on('error', (err) => {
log.error('更新错误:', err);
mainWindow.webContents.send('update-error', {
message: err.message
});
});
}
// 检查更新
function checkForUpdates() {
autoUpdater.checkForUpdates().catch(err => {
log.error('检查更新失败:', err);
});
}
// 立即安装更新(退出并重启)
function installUpdate() {
autoUpdater.quitAndInstall();
}
module.exports = { setupAutoUpdater, checkForUpdates, installUpdate };
渲染进程中的更新 UI
// Vue 组件 - 更新提示
🎉 发现新版本 {{ updateState.version }}
正在下载更新... {{ updateState.progress }}%
更新已下载,重启应用即可安装
有新版本可用,是否立即下载?
立即下载
重启安装
稍后提醒
9.3 更新策略
根据产品需求,可以选择不同的更新策略:强制更新、可选更新、静默更新等。
| 策略 | 说明 | 适用场景 |
|---|---|---|
| 强制更新 | 发现新版本必须更新才能使用 | 安全修复、重大Bug |
| 可选更新 | 提示用户,用户可选择稍后 | 功能更新、优化 |
| 静默更新 | 后台下载,下次启动时自动安装 | 小修复、非紧急更新 |
| 手动检查 | 用户点击"检查更新"按钮 | 节省服务器资源 |
强制更新实现
// 强制更新 - 发现新版本后禁用应用功能
autoUpdater.on('update-available', (info) => {
// 判断是否为强制更新(根据版本号或服务器配置)
const isForceUpdate = info.releaseNotes?.includes('[FORCE]');
mainWindow.webContents.send('update-available', {
version: info.version,
force: isForceUpdate
});
if (isForceUpdate) {
// 立即开始下载
autoUpdater.downloadUpdate();
}
});
autoUpdater.on('update-downloaded', () => {
// 强制更新:立即退出并安装
autoUpdater.quitAndInstall();
});
9.4 崩溃监控(Sentry 集成)
生产环境的应用难免会出现崩溃和错误。集成 Sentry 可以实时监控应用健康状况,收集崩溃报告和错误日志。
安装 Sentry SDK
# 安装 Sentry Electron SDK
npm install @sentry/electron
主进程配置
// main.js - Sentry 初始化
const Sentry = require('@sentry/electron/main');
Sentry.init({
dsn: 'https://your-dsn@sentry.io/project-id',
// 环境标识
environment: app.isPackaged ? 'production' : 'development',
// 发布版本(用于关联源码映射)
release: `rpa-assistant@${app.getVersion()}`,
// 采样率(生产环境建议 1.0,开发环境可以调低)
sampleRate: 1.0,
// 启用性能监控
tracesSampleRate: 0.1,
// 附加数据
initialScope: {
tags: {
platform: process.platform,
arch: process.arch
}
}
});
// 手动捕获异常
try {
riskyOperation();
} catch (error) {
Sentry.captureException(error);
}
// 添加面包屑(操作轨迹)
Sentry.addBreadcrumb({
category: 'user-action',
message: '用户点击了开始录制按钮',
level: 'info'
});
渲染进程配置
// renderer.js 或 Vue 入口文件
import * as Sentry from '@sentry/electron/renderer';
Sentry.init({
dsn: 'https://your-dsn@sentry.io/project-id',
// 启用 Vue 集成
integrations: [
Sentry.vueIntegration({
app, // Vue 应用实例
attachProps: true
})
],
// 跟踪 Vue 组件性能
tracesSampleRate: 0.1
});
// 在 Vue 组件中使用
function handleError() {
Sentry.captureException(new Error('用户操作失败'));
}
// 设置用户信息
Sentry.setUser({
id: 'user-123',
username: '张三',
email: 'zhangsan@example.com'
});
9.5 日志收集与分析
除了崩溃监控,还需要收集应用运行日志,帮助诊断用户遇到的问题。
日志上传实现
// logger.js - 带上传功能的日志系统
const log = require('electron-log');
const fs = require('fs').promises;
const path = require('path');
const { app } = require('electron');
class LogManager {
constructor() {
this.logDir = app.getPath('logs');
this.setupLogTransport();
}
setupLogTransport() {
// 文件日志
log.transports.file.resolvePath = () =>
path.join(this.logDir, 'app.log');
log.transports.file.maxSize = 10 * 1024 * 1024; // 10MB
// 控制台日志(开发环境)
log.transports.console.level = app.isPackaged ? false : 'debug';
}
// 获取最近的日志内容
async getRecentLogs(lines = 100) {
try {
const logPath = path.join(this.logDir, 'app.log');
const content = await fs.readFile(logPath, 'utf-8');
return content.split('\n').slice(-lines).join('\n');
} catch (err) {
return '无法读取日志文件';
}
}
// 上传日志到服务器
async uploadLogs() {
try {
const logs = await this.getRecentLogs(500);
const response = await fetch('https://your-api.com/logs', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
version: app.getVersion(),
platform: process.platform,
logs: logs,
timestamp: new Date().toISOString()
})
});
if (response.ok) {
log.info('日志上传成功');
return true;
}
} catch (err) {
log.error('日志上传失败:', err);
return false;
}
}
// 导出日志文件(供用户手动发送)
async exportLogs() {
const { dialog } = require('electron');
const result = await dialog.showSaveDialog({
defaultPath: `logs-${Date.now()}.txt`,
filters: [{ name: '日志文件', extensions: ['txt'] }]
});
if (!result.canceled) {
const logs = await this.getRecentLogs(1000);
await fs.writeFile(result.filePath, logs, 'utf-8');
return result.filePath;
}
}
}
module.exports = { LogManager };
9.6 性能监控
监控应用性能指标,及时发现性能瓶颈。
// performance-monitor.js
const { app } = require('electron');
class PerformanceMonitor {
constructor() {
this.metrics = {
startupTime: 0,
memoryUsage: [],
cpuUsage: []
};
this.startMonitoring();
}
// 记录启动时间
recordStartupTime() {
this.metrics.startupTime = Date.now() - global.appStartTime;
console.log(`应用启动时间: ${this.metrics.startupTime}ms`);
}
// 监控内存使用
startMonitoring() {
setInterval(() => {
const usage = process.memoryUsage();
this.metrics.memoryUsage.push({
timestamp: Date.now(),
rss: Math.round(usage.rss / 1024 / 1024), // MB
heapUsed: Math.round(usage.heapUsed / 1024 / 1024),
heapTotal: Math.round(usage.heapTotal / 1024 / 1024)
});
// 只保留最近100条记录
if (this.metrics.memoryUsage.length > 100) {
this.metrics.memoryUsage.shift();
}
// 内存告警(超过500MB)
if (usage.rss > 500 * 1024 * 1024) {
console.warn('内存使用过高:', usage.rss);
}
}, 30000); // 每30秒采样一次
}
// 获取性能报告
getReport() {
const memStats = this.metrics.memoryUsage;
const avgMemory = memStats.reduce((sum, m) => sum + m.rss, 0) / memStats.length;
return {
startupTime: this.metrics.startupTime,
averageMemoryMB: Math.round(avgMemory),
maxMemoryMB: Math.max(...memStats.map(m => m.rss)),
platform: process.platform,
electronVersion: process.versions.electron,
nodeVersion: process.versions.node
};
}
}
module.exports = { PerformanceMonitor };
- 版本追踪:每个错误报告都要包含应用版本号,便于定位问题
- 分级告警:根据错误频率和影响范围设置不同级别的告警
- 用户反馈:提供"发送反馈"功能,让用户主动报告问题
- 灰度发布:新版本先小范围推送,确认稳定后再全量发布
- 回滚机制:保留旧版本安装包,紧急情况下可快速回滚