const { app, BrowserWindow, session, dialog, ipcMain } = require('electron') const { autoUpdater } = require('electron-updater') const path = require('path') const Store = require('electron-store') const store = new Store() // 同步 IPC:供 preload 读写持久化数据 ipcMain.on('store-get-sync', (event, key) => { event.returnValue = store.get(key) }) ipcMain.on('store-set-sync', (event, key, value) => { store.set(key, value) event.returnValue = true }) ipcMain.on('store-delete-sync', (event, key) => { store.delete(key) event.returnValue = true }) const ENV_URLS = { dev: 'http://192.168.1.14:7033', uat: 'http://nas.wjl-work.top:7034', } function getWindowUrl() { const envArg = process.argv.find(a => a.startsWith('--env=')) if (envArg) { const env = envArg.split('=')[1] return ENV_URLS[env] || ENV_URLS.dev } return ENV_URLS.dev } function getEnvName() { const url = getWindowUrl() if (url.includes('7034')) return 'uat' return 'dev' } // 在 Chromium 启动前将 HTTP 内网地址标记为安全源, // 否则 navigator.mediaDevices 在 HTTP 非 localhost 下会被置空 const insecureOrigins = Object.values(ENV_URLS).join(',') app.commandLine.appendSwitch('unsafely-treat-insecure-origin-as-secure', insecureOrigins) let mainWindow = null function createWindow() { const win = new BrowserWindow({ width: 1280, height: 800, minWidth: 960, minHeight: 600, title: 'Game Group', autoHideMenuBar: true, webPreferences: { preload: path.join(__dirname, 'preload.js'), contextIsolation: true, webSecurity: false, allowRunningInsecureContent: true, }, }) mainWindow = win const url = getWindowUrl() win.loadURL(url) // 页面标题同步 win.on('page-title-updated', (event, title) => { event.preventDefault() win.setTitle(`Game Group - ${title}`) }) win.on('closed', () => { mainWindow = null }) return win } // 自动更新配置 function setupAutoUpdater(win) { const env = getEnvName() const feedUrl = `${ENV_URLS[env]}/electron-update/` autoUpdater.setFeedURL({ provider: 'generic', url: feedUrl }) autoUpdater.autoDownload = false autoUpdater.autoInstallOnAppQuit = false autoUpdater.on('checking-for-update', () => { console.log('[updater] Checking for update at', feedUrl) }) autoUpdater.on('update-available', (info) => { console.log('[updater] Update available:', info.version) if (win && !win.isDestroyed()) { win.webContents.send('update-available', info) dialog.showMessageBox(win, { type: 'info', title: '发现新版本', message: `发现新版本 ${info.version},是否立即下载更新?`, buttons: ['立即下载', '稍后再说'], defaultId: 0, cancelId: 1, }).then(({ response }) => { if (response === 0) { autoUpdater.downloadUpdate().catch((err) => { console.error('[updater] Download failed:', err.message) }) } }) } }) autoUpdater.on('update-not-available', () => { console.log('[updater] No update available') }) autoUpdater.on('error', (err) => { console.error('[updater] Error:', err.message) if (win && !win.isDestroyed()) { win.webContents.send('update-error', err.message) } }) autoUpdater.on('download-progress', (progress) => { console.log(`[updater] Download progress: ${progress.percent.toFixed(1)}%`) if (win && !win.isDestroyed()) { win.webContents.send('download-progress', progress) } }) autoUpdater.on('update-downloaded', (info) => { console.log('[updater] Update downloaded:', info.version) if (win && !win.isDestroyed()) { win.webContents.send('update-downloaded', info) dialog.showMessageBox(win, { type: 'info', title: '更新就绪', message: `新版本 ${info.version} 已下载完成,是否立即重启安装?`, buttons: ['立即重启', '稍后'], defaultId: 0, }).then(({ response }) => { if (response === 0) { autoUpdater.quitAndInstall() } }) } }) // 手动触发检查更新(供前端调用) ipcMain.on('check-for-updates', () => { autoUpdater.checkForUpdates().catch((err) => { console.error('[updater] Manual check failed:', err.message) }) }) ipcMain.on('quit-and-install', () => { autoUpdater.quitAndInstall() }) // 启动后延迟 5 秒检查更新(等窗口稳定后再检查) setTimeout(() => { autoUpdater.checkForUpdates().catch((err) => { console.error('[updater] Initial check failed:', err.message) }) }, 5000) } app.whenReady().then(() => { // 自动批准麦克风/摄像头权限请求,无需用户手动确认 session.defaultSession.setPermissionRequestHandler((_webContents, permission, callback) => { if (permission === 'media' || permission === 'microphone' || permission === 'camera') { callback(true) } else { callback(false) } }) // 绕过权限检查,确保 mediaDevices 可用 session.defaultSession.setPermissionCheckHandler((_webContents, permission) => { if (permission === 'media' || permission === 'microphone' || permission === 'camera') { return true } return false }) const win = createWindow() setupAutoUpdater(win) }) app.on('window-all-closed', () => { app.quit() })