应用生命周期 #
一、应用生命周期概述 #
1.1 生命周期流程图 #
text
┌─────────────────┐
│ 应用启动 │
└────────┬────────┘
│
▼
┌─────────────────┐
│ will-finish- │
│ launching │ 应用即将完成启动
└────────┬────────┘
│
▼
┌─────────────────┐
│ ready │ 应用准备就绪
└────────┬────────┘
│
▼
┌─────────────────┐
│ 创建窗口 │
└────────┬────────┘
│
▼
┌─────────────────┐
│ 运行中 │◄──────────────┐
└────────┬────────┘ │
│ │
│ ┌─────────────────┐ │
└──┤ window-all-closed├──┘
└─────────────────┘
│
▼
┌─────────────────┐
│ before-quit │ 应用即将退出
└────────┬────────┘
│
▼
┌─────────────────┐
│ will-quit │ 应用正在退出
└────────┬────────┘
│
▼
┌─────────────────┐
│ quit │ 应用已退出
└─────────────────┘
1.2 核心模块 app #
javascript
const { app } = require('electron');
// app 模块提供的主要功能
// - 控制应用生命周期
// - 获取应用信息
// - 管理应用路径
// - 处理系统事件
二、启动阶段 #
2.1 启动事件 #
javascript
const { app, BrowserWindow } = require('electron');
// 应用即将完成启动(macOS 特有)
app.on('will-finish-launching', () => {
console.log('应用即将完成启动');
// macOS 上处理文件打开
app.on('open-file', (event, path) => {
event.preventDefault();
console.log('打开文件:', path);
});
});
// 应用准备就绪
app.on('ready', () => {
console.log('应用准备就绪');
createWindow();
});
// 推荐使用 whenReady()
app.whenReady().then(() => {
console.log('应用准备就绪(Promise)');
createWindow();
});
2.2 创建窗口 #
javascript
let mainWindow = null;
function createWindow() {
mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: false,
contextIsolation: true,
preload: path.join(__dirname, 'preload.js')
}
});
mainWindow.loadFile('index.html');
mainWindow.on('closed', () => {
mainWindow = null;
});
}
// 确保在应用准备就绪后创建窗口
app.whenReady().then(createWindow);
2.3 macOS 特殊处理 #
javascript
// macOS 上点击 Dock 图标时重新创建窗口
app.on('activate', () => {
// 在 macOS 上,当点击 Dock 图标且没有其他窗口打开时,
// 通常会在应用程序中重新创建一个窗口
if (BrowserWindow.getAllWindows().length === 0) {
createWindow();
}
});
三、退出阶段 #
3.1 退出事件 #
javascript
// 所有窗口关闭
app.on('window-all-closed', () => {
console.log('所有窗口已关闭');
// 在 macOS 上,除非用户按 Cmd + Q,否则应用不会退出
if (process.platform !== 'darwin') {
app.quit();
}
});
// 应用即将退出
app.on('before-quit', (event) => {
console.log('应用即将退出');
// 可以阻止退出
// event.preventDefault();
});
// 应用正在退出
app.on('will-quit', (event) => {
console.log('应用正在退出');
// 清理资源
cleanup();
// 也可以阻止退出
// event.preventDefault();
});
// 应用已退出
app.on('quit', (event, exitCode) => {
console.log(`应用已退出,退出码: ${exitCode}`);
});
3.2 退出流程详解 #
javascript
// 完整的退出流程控制
let isQuitting = false;
// 1. 用户触发退出
app.on('before-quit', (event) => {
if (hasUnsavedChanges()) {
event.preventDefault();
dialog.showMessageBox({
type: 'question',
buttons: ['保存并退出', '放弃更改', '取消'],
title: '确认退出',
message: '有未保存的更改'
}).then((result) => {
if (result.response === 0) {
saveChanges().then(() => {
isQuitting = true;
app.quit();
});
} else if (result.response === 1) {
isQuitting = true;
app.quit();
}
});
}
});
// 2. 窗口关闭时判断是否退出
mainWindow.on('close', (event) => {
if (!isQuitting) {
event.preventDefault();
mainWindow.hide();
}
});
// 3. 清理资源
app.on('will-quit', () => {
// 关闭数据库连接
// 保存配置
// 清理临时文件
});
3.3 强制退出 #
javascript
// 正常退出(触发事件)
app.quit();
// 强制退出(不触发事件)
app.exit(0); // 0 为退出码
// 立即退出(不推荐)
process.exit(0);
四、单例模式 #
4.1 单例锁定 #
javascript
const gotTheLock = app.requestSingleInstanceLock();
if (!gotTheLock) {
// 如果获取不到锁,说明已有实例运行,退出
app.quit();
} else {
// 当第二个实例启动时,聚焦到已有窗口
app.on('second-instance', (event, commandLine, workingDirectory) => {
if (mainWindow) {
if (mainWindow.isMinimized()) {
mainWindow.restore();
}
mainWindow.focus();
}
});
// 创建窗口
app.whenReady().then(createWindow);
}
4.2 完整单例实现 #
javascript
const { app, BrowserWindow } = require('electron');
let mainWindow = null;
const gotTheLock = app.requestSingleInstanceLock();
if (!gotTheLock) {
app.quit();
} else {
app.on('second-instance', (event, commandLine, workingDirectory) => {
// 处理命令行参数
const fileToOpen = commandLine.find(arg => !arg.startsWith('-'));
if (mainWindow) {
if (mainWindow.isMinimized()) {
mainWindow.restore();
}
mainWindow.focus();
// 如果是通过文件关联打开的
if (fileToOpen) {
mainWindow.webContents.send('open-file', fileToOpen);
}
}
});
app.whenReady().then(() => {
mainWindow = createWindow();
});
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
});
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
mainWindow = createWindow();
}
});
}
五、应用信息 #
5.1 基本信息 #
javascript
// 应用名称
console.log('名称:', app.getName()); // 从 package.json 读取
console.log('显示名称:', app.getName()); // 可通过 setName() 设置
// 版本信息
console.log('版本:', app.getVersion()); // 从 package.json 读取
console.log('Electron 版本:', process.versions.electron);
console.log('Chrome 版本:', process.versions.chrome);
console.log('Node 版本:', process.versions.node);
console.log('V8 版本:', process.versions.v8);
// 应用 ID
console.log('应用 ID:', app.getAppPath());
5.2 设置应用信息 #
javascript
// 设置应用名称
app.setName('我的应用');
// 在 package.json 中设置
{
"name": "my-app",
"productName": "我的应用",
"version": "1.0.0"
}
六、应用路径 #
6.1 获取路径 #
javascript
// 应用路径
console.log('应用路径:', app.getAppPath());
// 用户数据目录
console.log('用户数据:', app.getPath('userData'));
// Windows: C:\Users\<user>\AppData\Roaming\<appName>
// macOS: ~/Library/Application Support/<appName>
// Linux: ~/.config/<appName>
// 临时目录
console.log('临时目录:', app.getPath('temp'));
// 桌面目录
console.log('桌面:', app.getPath('desktop'));
// 文档目录
console.log('文档:', app.getPath('documents'));
// 下载目录
console.log('下载:', app.getPath('downloads'));
// 音乐目录
console.log('音乐:', app.getPath('music'));
// 图片目录
console.log('图片:', app.getPath('pictures'));
// 视频目录
console.log('视频:', app.getPath('videos'));
// 日志目录
console.log('日志:', app.getPath('logs'));
// 可执行文件路径
console.log('可执行文件:', app.getPath('exe'));
// 模块路径
console.log('模块:', app.getPath('module'));
6.2 设置路径 #
javascript
// 设置用户数据目录(必须在 ready 之前)
app.setPath('userData', '/custom/user/data/path');
// 设置日志目录
app.setAppLogsPath('/custom/logs/path');
七、系统事件 #
7.1 电源事件 #
javascript
const { powerMonitor } = require('electron');
// 系统挂起
powerMonitor.on('suspend', () => {
console.log('系统即将挂起');
// 保存状态
});
// 系统恢复
powerMonitor.on('resume', () => {
console.log('系统已恢复');
// 恢复状态
});
// 电源状态变化
powerMonitor.on('on-ac', () => {
console.log('使用交流电源');
});
powerMonitor.on('on-battery', () => {
console.log('使用电池');
});
// 锁屏
powerMonitor.on('lock-screen', () => {
console.log('屏幕已锁定');
});
// 解锁
powerMonitor.on('unlock-screen', () => {
console.log('屏幕已解锁');
});
// 获取电池状态
const batteryState = powerMonitor.getBatteryState();
console.log('电池状态:', batteryState);
7.2 网络事件 #
javascript
// 网络状态变化(需要手动检测)
let online = navigator.onLine;
setInterval(() => {
if (navigator.onLine !== online) {
online = navigator.onLine;
mainWindow.webContents.send('network-changed', online);
}
}, 5000);
7.3 系统主题变化 #
javascript
const { nativeTheme } = require('electron');
// 监听主题变化
nativeTheme.on('updated', () => {
const isDark = nativeTheme.shouldUseDarkColors;
console.log('系统主题变化:', isDark ? '深色' : '浅色');
// 通知渲染进程
BrowserWindow.getAllWindows().forEach(win => {
win.webContents.send('theme-changed', isDark);
});
});
// 获取当前主题
console.log('深色模式:', nativeTheme.shouldUseDarkColors);
console.log('高对比度:', nativeTheme.shouldUseHighContrastColors);
八、协议注册 #
8.1 自定义协议 #
javascript
// 注册自定义协议
app.setAsDefaultProtocolClient('myapp');
// 处理协议调用
app.on('open-url', (event, url) => {
event.preventDefault();
console.log('通过协议打开:', url);
// 解析 URL
const parsedUrl = new URL(url);
console.log('协议:', parsedUrl.protocol);
console.log('主机:', parsedUrl.host);
console.log('路径:', parsedUrl.pathname);
console.log('参数:', parsedUrl.searchParams);
});
// macOS 上需要在 Info.plist 中配置
// Windows 上需要在注册表中注册
8.2 深链接处理 #
javascript
// main.js
const { app } = require('electron');
// 注册协议
if (process.defaultApp) {
if (process.argv.length >= 2) {
app.setAsDefaultProtocolClient('myapp', process.execPath, [process.argv[1]]);
}
} else {
app.setAsDefaultProtocolClient('myapp');
}
// 处理深链接
function handleDeepLink(url) {
const parsedUrl = new URL(url);
switch (parsedUrl.host) {
case 'open':
const fileId = parsedUrl.searchParams.get('id');
openFile(fileId);
break;
case 'settings':
openSettings();
break;
}
}
// Windows/Linux: 从命令行参数获取
if (process.platform !== 'darwin') {
const deepLink = process.argv.find(arg => arg.startsWith('myapp://'));
if (deepLink) {
handleDeepLink(deepLink);
}
}
// macOS: 从 open-url 事件获取
app.on('open-url', (event, url) => {
event.preventDefault();
handleDeepLink(url);
});
九、命令行参数 #
9.1 获取参数 #
javascript
// 获取命令行参数
console.log('参数:', process.argv);
// 示例: electron . --enable-logging --port=3000
// process.argv = ['electron', '.', '--enable-logging', '--port=3000']
// 解析参数
const args = process.argv.slice(2);
const port = args.find(arg => arg.startsWith('--port='))?.split('=')[1] || 3000;
9.2 开发模式检测 #
javascript
// 检测是否为开发模式
const isDev = process.env.NODE_ENV === 'development' ||
!app.isPackaged;
if (isDev) {
console.log('开发模式');
mainWindow.webContents.openDevTools();
} else {
console.log('生产模式');
}
十、最佳实践 #
10.1 完整启动模板 #
javascript
const { app, BrowserWindow, dialog } = require('electron');
const path = require('path');
let mainWindow = null;
let isQuitting = false;
// 单例模式
const gotTheLock = app.requestSingleInstanceLock();
if (!gotTheLock) {
app.quit();
}
function createWindow() {
mainWindow = new BrowserWindow({
width: 800,
height: 600,
show: false,
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
nodeIntegration: false,
contextIsolation: true
}
});
mainWindow.loadFile('index.html');
mainWindow.once('ready-to-show', () => {
mainWindow.show();
});
mainWindow.on('close', (event) => {
if (!isQuitting) {
event.preventDefault();
mainWindow.hide();
}
});
mainWindow.on('closed', () => {
mainWindow = null;
});
return mainWindow;
}
// 应用准备就绪
app.whenReady().then(() => {
createWindow();
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow();
}
});
});
// 所有窗口关闭
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
});
// 即将退出
app.on('before-quit', () => {
isQuitting = true;
});
// 第二个实例
app.on('second-instance', () => {
if (mainWindow) {
if (mainWindow.isMinimized()) {
mainWindow.restore();
}
mainWindow.focus();
}
});
10.2 优雅退出 #
javascript
// 优雅退出处理
async function gracefulShutdown() {
// 1. 保存数据
await saveUserData();
// 2. 关闭连接
await closeConnections();
// 3. 清理临时文件
cleanupTempFiles();
// 4. 退出
app.exit(0);
}
// 监听退出信号
process.on('SIGTERM', gracefulShutdown);
process.on('SIGINT', gracefulShutdown);
// 应用退出前
app.on('before-quit', (event) => {
event.preventDefault();
gracefulShutdown();
});
十一、总结 #
11.1 核心要点 #
| 要点 | 说明 |
|---|---|
| ready | 应用准备就绪,创建窗口 |
| window-all-closed | 所有窗口关闭,退出应用 |
| before-quit | 应用即将退出,清理资源 |
| 单例模式 | 确保只有一个实例运行 |
| 应用路径 | 获取各种系统路径 |
11.2 下一步 #
现在你已经掌握了应用生命周期管理,接下来让我们学习 窗口管理,深入了解多窗口管理技术!
最后更新:2026-03-28