# 单实例问题最终修复说明 ## 问题描述 编译后的 exe 文件可以打开多个实例,无法实现单实例启动。 ## 问题原因分析 1. **应用标识符不一致**:package.json 中的 name 和 electron-builder 配置中的 appId 不一致 2. **单实例检查逻辑过于复杂**:使用了自定义的锁文件管理,而不是直接使用 Electron 内置的单实例机制 3. **多个进程残留**:之前的实例异常退出时,进程没有正确清理,导致锁文件失效 ## 修复内容 ### 1. 统一应用标识符 - **package.json**: `name` 改为 `dify-market-manager-gui` - **electron-builder.yml**: `appId` 改为 `com.huashiai.dify-market-manager-gui` - **主进程**: `setAppUserModelId` 设置为 `com.huashiai.dify-market-manager-gui` ### 2. 简化单实例实现 参考标准 Electron 单实例实现,使用 `app.requestSingleInstanceLock()` 方法: ```javascript /** * 单应用启动实现 * 请求单一实例锁, * 如果该方法返回`false`, * 则表示已经有一个实例在运行, * 可以通过`app.quit()`方法退出当前实例。 */ const gotTheLock = app.requestSingleInstanceLock() if (!gotTheLock) { logger.info('检测到已有实例运行,退出当前实例') app.quit() } else { logger.info('这是第一个实例,继续启动') // 监听第二个实例被运行时 app.on('second-instance', (event, commandLine, workingDirectory) => { logger.info('检测到第二个实例启动,激活现有实例') // 当有第二个实例被运行时,激活之前的实例并将焦点置于其窗口 const windows = BrowserWindow.getAllWindows() if (windows.length > 0) { const mainWindow = windows[0] if (mainWindow.isMinimized()) { mainWindow.restore() } mainWindow.show() mainWindow.focus() } }) } ``` ### 3. 清理残留进程和锁文件 - 创建了 `kill-processes.js` 脚本来终止所有相关进程 - 创建了 `cleanup-lock-files.js` 脚本来清理所有锁文件 - 终止了 11 个残留的应用进程 ### 4. 简化单实例管理器 - 移除了复杂的锁文件管理逻辑 - 直接使用 Electron 内置的单实例机制 - 保留锁文件作为备份,但不依赖它进行单实例检查 ## 修复后的功能特点 ### 标准单实例行为 1. **首次启动**:应用正常启动,显示主窗口 2. **重复启动**:检测到已有实例,自动退出新实例,激活现有实例窗口 3. **窗口激活**:如果现有窗口最小化,自动恢复并聚焦 ### 跨平台兼容 - Windows: 使用系统级的单实例锁 - macOS: 使用系统级的单实例锁 - Linux: 使用系统级的单实例锁 ### 异常处理 - 应用崩溃时自动清理锁文件 - 监听各种退出信号确保清理 - 提供手动清理功能 ## 使用方法 ### 开发环境测试 ```bash # 启动第一个实例 npm run dev # 尝试启动第二个实例(应该被阻止) npm run dev ``` ### 生产环境测试 ```bash # 构建应用 npm run build:win # 安装并运行 # 尝试多次点击 exe 文件,应该只能启动一个实例 ``` ### 清理工具 ```bash # 清理锁文件 node cleanup-lock-files.js # 终止所有相关进程 node kill-processes.js ``` ## 验证修复效果 ### 1. 正常启动 ``` [时间] 这是第一个实例,继续启动 [时间] 应用已准备就绪,开始初始化... ``` ### 2. 重复启动 ``` [时间] 检测到已有实例运行,退出当前实例 ``` ### 3. 第二个实例启动 ``` [时间] 检测到第二个实例启动,激活现有实例 ``` ## 相关文件 - `src/main/index.js` - 主进程启动文件(已更新单实例逻辑) - `src/main/utils/singleInstance.js` - 简化的单实例管理器 - `package.json` - 应用配置(已更新名称) - `electron-builder.yml` - 构建配置(已更新 appId) - `cleanup-lock-files.js` - 锁文件清理脚本 - `kill-processes.js` - 进程终止脚本 - `test-single-instance-simple.js` - 简单测试脚本 ## 注意事项 ### 1. 应用标识符 - 确保所有配置文件中的应用标识符一致 - 修改标识符后需要重新构建应用 ### 2. 开发环境 - 开发时如果遇到单实例问题,使用清理脚本 - 查看日志文件了解详细情况 ### 3. 生产环境 - 确保应用正常退出时能清理资源 - 监控应用的单实例行为 ## 总结 通过统一应用标识符、简化单实例实现逻辑、清理残留进程,成功解决了编译后可以打开多个实例的问题。现在应用严格按照单实例模式运行,符合桌面应用的标准行为。