main.js 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. const { app, BrowserWindow, Menu } = require('electron')
  2. const path = require('path')
  3. const isDev = process.env.NODE_ENV === 'development'
  4. // 保持对窗口对象的全局引用,避免被垃圾回收
  5. let mainWindow
  6. function createWindow() {
  7. // 创建浏览器窗口
  8. mainWindow = new BrowserWindow({
  9. width: 600,
  10. height: 800,
  11. minWidth: 100,
  12. minHeight: 300,
  13. webPreferences: {
  14. nodeIntegration: false,
  15. contextIsolation: true,
  16. webSecurity: false, // 禁用webSecurity以允许跨域请求
  17. allowRunningInsecureContent: true, // 允许不安全内容
  18. enableRemoteModule: false, // 禁用远程模块,提高安全性
  19. webgl: true,
  20. images: true
  21. },
  22. icon: path.join(__dirname, '../../dist/build/h5/static/pc.png'), // 应用图标
  23. show: false // 先隐藏窗口,等加载完成再显示
  24. })
  25. // 设置Content Security Policy
  26. mainWindow.webContents.session.webRequest.onHeadersReceived((details, callback) => {
  27. callback({
  28. responseHeaders: {
  29. ...details.responseHeaders,
  30. 'Content-Security-Policy': [
  31. "default-src * 'unsafe-inline' 'unsafe-eval' data: blob:; " +
  32. "script-src * 'unsafe-inline' 'unsafe-eval'; " +
  33. "connect-src * 'unsafe-inline'; " +
  34. "img-src * data: blob: 'unsafe-inline'; " +
  35. "frame-src *; " +
  36. "style-src * 'unsafe-inline'; " +
  37. "font-src * data:; " +
  38. "media-src *"
  39. ]
  40. }
  41. })
  42. })
  43. // 加载应用
  44. if (isDev) {
  45. // 开发环境:加载本地H5开发服务器
  46. mainWindow.loadURL('http://localhost:9090')
  47. // 打开开发者工具
  48. mainWindow.webContents.openDevTools()
  49. } else {
  50. // 生产环境:加载打包后的文件
  51. const fs = require('fs')
  52. let indexPath
  53. // 尝试多种可能的路径
  54. const possiblePaths = [
  55. // 打包后路径1:resources/app/dist/build/h5
  56. process.resourcesPath ? path.join(process.resourcesPath, 'app', 'dist', 'build', 'h5', 'index.html') : null,
  57. // 打包后路径2:resources/app
  58. process.resourcesPath ? path.join(process.resourcesPath, 'app', 'index.html') : null,
  59. // 打包后路径3:直接位于应用目录
  60. path.join(__dirname, '..', 'dist', 'build', 'h5', 'index.html'),
  61. // 开发环境路径
  62. path.join(__dirname, '..', '..', 'dist', 'build', 'h5', 'index.html'),
  63. // 备用路径
  64. path.join(__dirname, 'dist', 'build', 'h5', 'index.html')
  65. ].filter(Boolean)
  66. // 查找存在的文件
  67. for (const testPath of possiblePaths) {
  68. console.log('Testing path:', testPath)
  69. if (fs.existsSync(testPath)) {
  70. indexPath = testPath
  71. console.log('Found index file at:', indexPath)
  72. break
  73. }
  74. }
  75. if (indexPath && fs.existsSync(indexPath)) {
  76. // 使用 loadFile 方法加载文件
  77. mainWindow.loadFile(indexPath)
  78. console.log('Successfully loaded index file from:', indexPath)
  79. } else {
  80. console.error('Index file not found in any of the following paths:')
  81. possiblePaths.forEach(p => console.error(' -', p))
  82. // 显示详细的错误信息
  83. const errorHtml = `
  84. <html>
  85. <head><title>应用加载失败</title></head>
  86. <body style="font-family: Arial, sans-serif; padding: 20px;">
  87. <h1>应用文件加载失败</h1>
  88. <p>无法找到 index.html 文件,请检查以下路径:</p>
  89. <ul>
  90. ${possiblePaths.map(p => `<li>${p}</li>`).join('')}
  91. </ul>
  92. <p>请重新安装应用或联系技术支持。</p>
  93. </body>
  94. </html>
  95. `
  96. mainWindow.loadURL(`data:text/html,${encodeURIComponent(errorHtml)}`)
  97. }
  98. }
  99. // 窗口准备好后显示
  100. mainWindow.once('ready-to-show', () => {
  101. mainWindow.show()
  102. })
  103. // 窗口关闭时触发
  104. mainWindow.on('closed', () => {
  105. mainWindow = null
  106. })
  107. // 设置菜单(可选)
  108. const template = [
  109. {
  110. label: '文件',
  111. submenu: [
  112. {
  113. label: '退出',
  114. accelerator: process.platform === 'darwin' ? 'Cmd+Q' : 'Ctrl+Q',
  115. click() {
  116. app.quit()
  117. }
  118. }
  119. ]
  120. },
  121. {
  122. label: '视图',
  123. submenu: [
  124. { role: 'reload', label: '重新加载' },
  125. { role: 'forceReload', label: '强制重新加载' },
  126. { role: 'toggleDevTools', label: '开发者工具' },
  127. { type: 'separator' },
  128. { role: 'resetZoom', label: '实际大小' },
  129. { role: 'zoomIn', label: '放大' },
  130. { role: 'zoomOut', label: '缩小' },
  131. { type: 'separator' },
  132. { role: 'togglefullscreen', label: '切换全屏' }
  133. ]
  134. }
  135. ]
  136. const menu = Menu.buildFromTemplate(template)
  137. Menu.setApplicationMenu(menu)
  138. }
  139. // Electron 初始化完成时触发
  140. app.whenReady().then(createWindow)
  141. // 所有窗口关闭时退出应用(macOS除外)
  142. app.on('window-all-closed', () => {
  143. if (process.platform !== 'darwin') {
  144. app.quit()
  145. }
  146. })
  147. // macOS 应用激活时重新创建窗口
  148. app.on('activate', () => {
  149. if (BrowserWindow.getAllWindows().length === 0) {
  150. createWindow()
  151. }
  152. })
  153. // 安全设置:阻止新窗口创建
  154. app.on('web-contents-created', (event, contents) => {
  155. contents.on('new-window', (event, navigationUrl) => {
  156. event.preventDefault()
  157. // 在默认浏览器中打开外部链接
  158. require('electron').shell.openExternal(navigationUrl)
  159. })
  160. })