main.js 5.8 KB

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