# 单实例问题最终修复说明

## 问题描述
编译后的 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. 生产环境
- 确保应用正常退出时能清理资源
- 监控应用的单实例行为

## 总结
通过统一应用标识符、简化单实例实现逻辑、清理残留进程，成功解决了编译后可以打开多个实例的问题。现在应用严格按照单实例模式运行，符合桌面应用的标准行为。 