default_app.ts 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. import { app, dialog, BrowserWindow, shell, ipcMain } from 'electron';
  2. import * as path from 'path';
  3. import * as url from 'url';
  4. let mainWindow: BrowserWindow | null = null;
  5. // Quit when all windows are closed.
  6. app.on('window-all-closed', () => {
  7. app.quit();
  8. });
  9. function decorateURL (url: string) {
  10. // safely add `?utm_source=default_app
  11. const parsedUrl = new URL(url);
  12. parsedUrl.searchParams.append('utm_source', 'default_app');
  13. return parsedUrl.toString();
  14. }
  15. // Find the shortest path to the electron binary
  16. const absoluteElectronPath = process.execPath;
  17. const relativeElectronPath = path.relative(process.cwd(), absoluteElectronPath);
  18. const electronPath = absoluteElectronPath.length < relativeElectronPath.length
  19. ? absoluteElectronPath
  20. : relativeElectronPath;
  21. const indexPath = path.resolve(app.getAppPath(), 'index.html');
  22. function isTrustedSender (webContents: Electron.WebContents) {
  23. if (webContents !== (mainWindow && mainWindow.webContents)) {
  24. return false;
  25. }
  26. try {
  27. return url.fileURLToPath(webContents.getURL()) === indexPath;
  28. } catch {
  29. return false;
  30. }
  31. }
  32. ipcMain.handle('bootstrap', (event) => {
  33. return isTrustedSender(event.sender) ? electronPath : null;
  34. });
  35. async function createWindow (backgroundColor?: string) {
  36. await app.whenReady();
  37. const options: Electron.BrowserWindowConstructorOptions = {
  38. width: 960,
  39. height: 620,
  40. autoHideMenuBar: true,
  41. backgroundColor,
  42. webPreferences: {
  43. preload: path.resolve(__dirname, 'preload.js'),
  44. contextIsolation: true,
  45. sandbox: true,
  46. enableRemoteModule: false
  47. },
  48. useContentSize: true,
  49. show: false
  50. };
  51. if (process.platform === 'linux') {
  52. options.icon = path.join(__dirname, 'icon.png');
  53. }
  54. mainWindow = new BrowserWindow(options);
  55. mainWindow.on('ready-to-show', () => mainWindow!.show());
  56. mainWindow.webContents.on('new-window', (event, url) => {
  57. event.preventDefault();
  58. shell.openExternal(decorateURL(url));
  59. });
  60. mainWindow.webContents.session.setPermissionRequestHandler((webContents, permission, done) => {
  61. const parsedUrl = new URL(webContents.getURL());
  62. const options: Electron.MessageBoxOptions = {
  63. title: 'Permission Request',
  64. message: `Allow '${parsedUrl.origin}' to access '${permission}'?`,
  65. buttons: ['OK', 'Cancel'],
  66. cancelId: 1
  67. };
  68. dialog.showMessageBox(mainWindow!, options).then(({ response }) => {
  69. done(response === 0);
  70. });
  71. });
  72. return mainWindow;
  73. }
  74. export const loadURL = async (appUrl: string) => {
  75. mainWindow = await createWindow();
  76. mainWindow.loadURL(appUrl);
  77. mainWindow.focus();
  78. };
  79. export const loadFile = async (appPath: string) => {
  80. mainWindow = await createWindow(appPath === 'index.html' ? '#2f3241' : undefined);
  81. mainWindow.loadFile(appPath);
  82. mainWindow.focus();
  83. };