| 1 | import { app, BrowserWindow, shell, ipcMain, nativeTheme } from 'electron'; |
| 2 | import { fileURLToPath } from 'node:url'; |
| 3 | import path from 'node:path'; |
| 4 | import os from 'node:os'; |
| 5 | import { update } from './update'; |
| 6 | import { SystemTray } from '../tray/systemTray'; |
| 7 | import { views } from './views'; |
| 8 | import App from './app'; |
| 9 | import { getAssetPath } from '../util/index'; |
| 10 | import windowOperate from '../util/windowOperate'; |
| 11 | import { logger } from '../global/log'; |
| 12 | import { SplashWindow } from './splash'; |
| 13 | import dotenv from 'dotenv'; |
| 14 | import KwaiPubListener from './plat/platforms/Kwai/KwaiPubListener'; |
| 15 | import { registerContextMenuListener } from '@electron-uikit/contextmenu'; |
| 16 | import { dialog } from 'electron'; |
| 17 | |
| 18 | const platform = process.platform; |
| 19 | dotenv.config(); |
| 20 | |
| 21 | const __dirname = path.dirname(fileURLToPath(import.meta.url)); |
| 22 | |
| 23 | process.env.APP_ROOT = path.join(__dirname, '../..'); |
| 24 | |
| 25 | export const MAIN_DIST = path.join(process.env.APP_ROOT, 'dist-electron'); |
| 26 | export const RENDERER_DIST = path.join(process.env.APP_ROOT, 'dist'); |
| 27 | export const VITE_DEV_SERVER_URL = process.env.VITE_DEV_SERVER_URL; |
| 28 | |
| 29 | dialog.showErrorBox = (title, content) => { |
| 30 | console.error(`Error: ${title}\n${content}`); |
| 31 | }; |
| 32 | |
| 33 | process.env.VITE_PUBLIC = VITE_DEV_SERVER_URL |
| 34 | ? path.join(process.env.APP_ROOT, 'public') |
| 35 | : RENDERER_DIST; |
| 36 | |
| 37 | // Disable GPU Acceleration for Windows 7 |
| 38 | if (os.release().startsWith('6.1')) app.disableHardwareAcceleration(); |
| 39 | // Set application name for Windows 10+ notifications |
| 40 | if (process.platform === 'win32') app.setAppUserModelId(app.getName()); |
| 41 | |
| 42 | // 单例锁 |
| 43 | // if (!app.requestSingleInstanceLock()) { |
| 44 | // app.quit(); |
| 45 | // process.exit(0); |
| 46 | // } |
| 47 | |
| 48 | let win: BrowserWindow | null = null; |
| 49 | let splashWindow: SplashWindow | null = null; |
| 50 | const preload = path.join(__dirname, '../preload/index.mjs'); |
| 51 | const indexHtml = path.join(RENDERER_DIST, 'index.html'); |
| 52 | |
| 53 | async function createWindow() { |
| 54 | // 创建启动窗口 |
| 55 | splashWindow = new SplashWindow(); |
| 56 | splashWindow.create(); |
| 57 | |
| 58 | // 等待一会儿确保启动窗口显示 |
| 59 | await new Promise((resolve) => setTimeout(resolve, 500)); |
| 60 | |
| 61 | // 创建主窗口但先不显示 |
| 62 | win = new BrowserWindow({ |
| 63 | title: '哎哟赚AiToEarn', |
| 64 | icon: path.join(getAssetPath('favicon.ico')), |
| 65 | width: 2350, |
| 66 | height: 1280, |
| 67 | minWidth: 1280, |
| 68 | minHeight: 800, |
| 69 | titleBarStyle: 'hidden', |
| 70 | show: false, |
| 71 | titleBarOverlay: |
| 72 | platform === 'win32' |
| 73 | ? undefined |
| 74 | : { |
| 75 | color: 'rgba(0,0,0,0)', |
| 76 | height: 64, |
| 77 | symbolColor: '#595959', |
| 78 | }, |
| 79 | webPreferences: { |
| 80 | preload, |
| 81 | webviewTag: true, |
| 82 | webSecurity: true, |
| 83 | nodeIntegration: false, |
| 84 | contextIsolation: true, |
| 85 | }, |
| 86 | }); |
| 87 | |
| 88 | // 强制使用非黑暗模式 |
| 89 | nativeTheme.themeSource = 'light'; |
| 90 | |
| 91 | try { |
| 92 | const tray = new SystemTray(win); |
| 93 | tray.create(); |
| 94 | } catch (error) { |
| 95 | logger.error('系统托盘启动失败', error); |
| 96 | } |
| 97 | |
| 98 | // 等待主窗口加载完成 |
| 99 | if (VITE_DEV_SERVER_URL) { |
| 100 | await win.loadURL(VITE_DEV_SERVER_URL); |
| 101 | } else { |
| 102 | await win.loadFile(indexHtml); |
| 103 | } |
| 104 | |
| 105 | // 延长启动窗口显示时间 |
| 106 | KwaiPubListener.start(); |
| 107 | setTimeout(() => { |
| 108 | if (splashWindow) { |
| 109 | win?.show(); |
| 110 | // 在主窗口显示后再打开开发者工具 |
| 111 | // win?.webContents.openDevTools({ mode: 'right' }); |
| 112 | |
| 113 | if (process.env.NODE_ENV === 'development') { |
| 114 | win?.webContents.openDevTools({ mode: 'right' }); |
| 115 | } |
| 116 | |
| 117 | // if (VITE_DEV_SERVER_URL) { |
| 118 | // win?.webContents.openDevTools({ mode: 'bottom' }); |
| 119 | // } |
| 120 | setTimeout(() => { |
| 121 | if (splashWindow) { |
| 122 | splashWindow.close(); |
| 123 | splashWindow = null; |
| 124 | } |
| 125 | }, 100); |
| 126 | } |
| 127 | }, 500); |
| 128 | |
| 129 | // 隐藏菜单栏 |
| 130 | win.setMenu(null); |
| 131 | |
| 132 | // Test actively push message to the Electron-Renderer |
| 133 | win.webContents.on('did-finish-load', () => { |
| 134 | win?.webContents.send('main-process-message', new Date().toLocaleString()); |
| 135 | }); |
| 136 | |
| 137 | // Make all links open with the browser, not with the application |
| 138 | win.webContents.setWindowOpenHandler(({ url }) => { |
| 139 | if (url.startsWith('https:')) shell.openExternal(url); |
| 140 | return { action: 'deny' }; |
| 141 | }); |
| 142 | |
| 143 | return win; |
| 144 | } |
| 145 | |
| 146 | app.whenReady().then(async () => { |
| 147 | try { |
| 148 | registerContextMenuListener(); |
| 149 | |
| 150 | // 创建应用实例,挂载功能 |
| 151 | new App(); |
| 152 | |
| 153 | // 创建窗口 |
| 154 | const bWin = await createWindow(); |
| 155 | |
| 156 | // 挂载其他功能 |
| 157 | update(bWin); |
| 158 | views(bWin); |
| 159 | windowOperate.init(bWin); |
| 160 | } catch (error) { |
| 161 | logger.error('Failed to start application:', error); |
| 162 | app.quit(); |
| 163 | } |
| 164 | }); |
| 165 | |
| 166 | /** |
| 167 | * Quit when all windows are closed, except on macOS. There, it's common |
| 168 | */ |
| 169 | app.on('window-all-closed', () => { |
| 170 | win = null; |
| 171 | if (process.platform !== 'darwin') app.quit(); |
| 172 | }); |
| 173 | |
| 174 | // 处理第二个实例 |
| 175 | app.on('second-instance', () => { |
| 176 | if (win) { |
| 177 | // Focus on the main window if the user tried to open another |
| 178 | if (win.isMinimized()) win.restore(); |
| 179 | win.focus(); |
| 180 | } |
| 181 | }); |
| 182 | |
| 183 | // 处理激活 |
| 184 | app.on('activate', () => { |
| 185 | const allWindows = BrowserWindow.getAllWindows(); |
| 186 | if (allWindows.length) { |
| 187 | allWindows[0].focus(); |
| 188 | } else { |
| 189 | createWindow(); |
| 190 | } |
| 191 | }); |
| 192 | |
| 193 | // 打开新窗口 |
| 194 | ipcMain.handle('open-win', (_, arg) => { |
| 195 | const childWindow = new BrowserWindow({ |
| 196 | webPreferences: { |
| 197 | preload, |
| 198 | nodeIntegration: true, |
| 199 | contextIsolation: false, |
| 200 | }, |
| 201 | }); |
| 202 | |
| 203 | if (VITE_DEV_SERVER_URL) { |
| 204 | childWindow.loadURL(`${VITE_DEV_SERVER_URL}#${arg}`); |
| 205 | } else { |
| 206 | childWindow.loadFile(indexHtml, { hash: arg }); |
| 207 | } |
| 208 | }); |
| 209 |