main.js 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. const { app, BrowserWindow, ipcMain, net, shell } = require('electron');
  2. const path = require('path');
  3. const url = require('url');
  4. const fs = require('fs');
  5. const { spawn } = require('child_process'); // 用于启动子进程
  6. let win = null;
  7. // 创建窗口
  8. const createWindow = () => {
  9. win = new BrowserWindow({
  10. // width: 1200,
  11. // height: 800,
  12. show: false, // 是否显示窗口
  13. autoHideMenuBar: true, // 隐藏菜单栏
  14. webPreferences: {
  15. nodeIntegration: true, // 是否集成 Node.js
  16. // enableRemoteModule: true, // 是否启用 remote 模块
  17. webSecurity: false, // 是否禁用同源策略
  18. preload: path.join(__dirname, 'preload.js'), // 预加载脚本
  19. },
  20. });
  21. win.loadURL(
  22. url.format({
  23. pathname: path.join(__dirname, './dist', 'index.html'),
  24. protocol: 'file:',
  25. slashes: true, // true: file://, false: file:
  26. hash: '/login', // /image_change 图片切换页
  27. }),
  28. );
  29. win.once('ready-to-show', () => {
  30. win.maximize();
  31. win.show();
  32. });
  33. // 拦截当前窗口的导航,防止外部链接在应用内打开
  34. win.webContents.on('will-navigate', (event, url) => {
  35. if (url.startsWith('http://') || url.startsWith('https://')) {
  36. event.preventDefault();
  37. shell.openExternal(url);
  38. }
  39. });
  40. };
  41. // 当 Electron 完成初始化并准备创建浏览器窗口时调用此方法
  42. app.whenReady().then(() => {
  43. createWindow();
  44. app.on('activate', () => {
  45. if (BrowserWindow.getAllWindows().length === 0) {
  46. createWindow();
  47. }
  48. });
  49. });
  50. // 检查更新
  51. ipcMain.handle('check-update', async () => {
  52. const apiUrl = 'https://your-api.com/api/app/latest'; // <-- 替换为真实接口
  53. const currentVersion = app.getVersion();
  54. return new Promise((resolve, reject) => {
  55. const req = net.request(apiUrl);
  56. let body = '';
  57. req.on('response', (res) => {
  58. res.on('data', (chunk) => (body += chunk));
  59. res.on('end', () => {
  60. try {
  61. const latest = JSON.parse(body);
  62. const update = latest.version && latest.version !== currentVersion;
  63. resolve({ update, latest, currentVersion });
  64. } catch (e) {
  65. reject(e);
  66. }
  67. });
  68. });
  69. req.on('error', (err) => reject(err));
  70. req.end();
  71. });
  72. });
  73. // 下载更新(渲染进程发起),主进程负责流式保存并推送进度
  74. ipcMain.on('download-update', (event, downloadUrl) => {
  75. const win = BrowserWindow.getAllWindows()[0];
  76. const filename = path.basename(downloadUrl).split('?')[0] || `update-${Date.now()}.exe`;
  77. const tmpPath = path.join(app.getPath('temp'), filename);
  78. const fileStream = fs.createWriteStream(tmpPath);
  79. const req = net.request(downloadUrl);
  80. let received = 0;
  81. let total = 0;
  82. req.on('response', (res) => {
  83. total = parseInt(res.headers['content-length'] || res.headers['Content-Length'] || '0');
  84. res.on('data', (chunk) => {
  85. received += chunk.length;
  86. fileStream.write(chunk);
  87. win.webContents.send('update-download-progress', { received, total });
  88. });
  89. res.on('end', () => {
  90. fileStream.end();
  91. win.webContents.send('update-downloaded', { path: tmpPath });
  92. });
  93. });
  94. req.on('error', (err) => {
  95. win.webContents.send('update-error', { message: err.message || String(err) });
  96. });
  97. req.end();
  98. });
  99. // 安装更新(渲染进程确认安装时调用)
  100. ipcMain.on('install-update', (event, filePath) => {
  101. if (!fs.existsSync(filePath)) {
  102. event.sender.send('update-error', { message: '安装文件不存在' });
  103. return;
  104. }
  105. if (process.platform === 'win32') {
  106. // Windows:直接执行安装程序(根据你的安装包参数添加静默/等待参数)
  107. try {
  108. spawn(filePath, [], { detached: true, stdio: 'ignore' }).unref();
  109. app.quit();
  110. } catch (e) {
  111. event.sender.send('update-error', { message: e.message });
  112. }
  113. } else if (process.platform === 'darwin') {
  114. // macOS:打开 dmg 或者打开 .pkg
  115. shell.openPath(filePath).then(() => app.quit());
  116. } else {
  117. // linux:按照需要实现
  118. shell.openPath(filePath).then(() => app.quit());
  119. }
  120. });
  121. // 当所有窗口都已关闭时退出
  122. app.on('window-all-closed', () => {
  123. if (process.platform !== 'darwin') {
  124. app.quit();
  125. }
  126. });
  127. app.on('activate', () => {
  128. if (BrowserWindow.getAllWindows().length === 0) {
  129. createWindow();
  130. }
  131. });