Electron - alandrade21/docsCompartilhados GitHub Wiki

Documento com registros úteis para desenvolvimento na plataforma electron.

  1. Pós Instalação
  2. Electron com Angular
  3. Comandos para Compilar e Rodar
  4. Problemas
  5. Package.json
  6. Processos
  7. BrowserWindow
  8. IPC
    1. Comunicação do Renderer para o Main
    2. Comunicação do Main para o Renderer
  9. Unsafe Content
  10. Dialogs
    1. Criação:
    2. Pegar referência da janela no renderer
    3. Message Dialogs
    4. Open File Dialog
    5. Save File Dialog
  11. Menu
    1. Normal
    2. Separator
    3. Submenu
    4. Check
    5. Radio
    6. Accelerators
    7. Criação e uso
    8. Menu de contexto
  12. Dicas de Estilização
  13. Shell

Pós Instalação

A partir do electron 5, após rodar o npm install, vai em node_modules/electron/dist e localiza o arquivo chrome-sandbox. Roda os seguintes comandos:

sudo chown root:root chrome-sandbox
sudo chmod 4755 chrome-sandbox

Sem isso o electron não roda. Se rodar sem isso, vai dar o seguinte erro:

[18371:0715/222931.349917:FATAL:setuid_sandbox_host.cc(157)] The SUID sandbox helper binary was found, but is not configured correctly. Rather than run without sandboxing I'm aborting now. You need to make sure that /home/andre/Desenv/templates/angular-electron-sqlite-alandrade21/node_modules/electron/dist/chrome-sandbox is owned by root and has mode 4755.

Electron com Angular

No index html coloca ./ como base href, ao invés de /.

Instala o electron no projeto

npm install electron --save-dev

Cria o arquivo main.js na raiz do projeto. Qdo for carregar o index.html usa:

const mainWindow = new BrowserWindow({});
 mainWindow.loadURL(`file://${__dirname}/dist/<nome do projeto>/index.html`);

Para mais detalhes, veja o meu projeto angular-electron-boilerplate.

Comandos para Compilar e Rodar

No arquivo package.json:

  • Cria uma entrada "main": "main.js" logo abaixo de "version".

  • Na seção de scripts cria dois scripts:

"electron": "electron ."
"electron-build": "ng build && electron ."

Para mais detalhes, veja o meu projeto angular-electron-boilerplate.

Problemas

Com Angular 6, referenciando o electron dentro do angular, acontece um problema que não é possível referenciar as bibliotecas nativas do node. A solução:

  • Em index.html, coloque o seguinte código:
<script>
  var electron = require('electron');
</script>

Package.json

Package,json tem 3 elementos obrigatórios: name (sem espaços), version e main (caminho para main.js relativo ao package.json).

Processos

O processo principal (Main Process) é o que carrega o electron e dispara a janela principal.

O processo de renderer (Renderer Process) é criado para cada janela aberta (browser window), e é responsável por rodar o app web embarcado no electron.

BrowserWindow

Propriedades para criação:

{ width: ,
  height: ,
  minWidth: ,
  minHeight: ,
  maxWidth: ,
  maxHeight: ,   // --> (todos acima aceitam números ou porcentagens)
  resizeable: ,
  movable: ,
  minimizable: ,
  closable: ,
  focusable: ,
  fullscreenable: , // --> (todos booleanos, alguns não são implementados em linux)
  icon: path.join(_dirname, 'myapp.png'),
  title: 'My Title',
  fullscreen: false,
  frame: true,      // --> (frame false apaga a moldura da janela, com os botões de controle)
  backgroundColor: '#eeeeee'}

Eventos win.on(' ', () => {}): closed, maximize, minimize, resize, move, show, hide.

win.on('ready-to-show', () => {
  win.show();
});  // --> Esse código é comum para evitar o flicker de janelas que demoram demais pra carregar.

Métodos win. (): show, hide, focus, close.

IPC

Comunicação do Renderer para o Main

No Renderer Process

electron.ipcRenderer.send('print-hello', 'John Doe');

No Main Process

electron.ipcMain.on('print-hello', (event, argument) => {
  console.log(`hello, $argument}!`);
});

Comunicação do Main para o Renderer

No Main Process

win.webContents.send('print-hello', 'John Doe');

No Renderer Process

electron.ipcRenderer.on('print-hello', (event, argument) => {
  console.log(`hello, $argument}!`);
});

Unsafe Content

Toda vez que tiver que carregar uma página externa num app electron, considere essa página externa um unsafe content.

No objeto de criação da janela onde será aberto o unsafe content, adicione o seguinte:

new electron.BrowserWindow({
  webPreferences: {
    nodeIntegration: false,  // (Essa opção não permite ao código carregado na janela acessar o node, ou seja, a browser window vai funcionar como um browser normal.)
    javascript: false // (Essa opção desliga o suporte ao js na nova janela. Essa opção pode ser deixada ligada.)
  }
});

Dialogs

4 tipos: Open file, Save file, Message, Error.

Criação:

No Main:

electron.dialog.showErrorBox('oops!', 'Somethig Happened!');

No Renderer

electron.remote.dialog.showErrorBox('oops!', 'Somethig Happened!');

Pegar referência da janela no renderer

electron.remote.getCurrentWindow();
electron.remote.BrowserWindow.getAllWindows();
electron.remote.BrowserWindow.getFocusedWindow();

Message Dialogs

const currentWindow = electron.remote.getCurrentWindow();
electron.remote.dialog.showMessageBox( currentWindow, {
  type: 'warning', // or none, info, error, question
  title: '',
  message: '',
  detail: '',
  icon: path.join(__dirname, 'danger.png'),
  buttons: ['OK', 'Cancel'],
  defaultId: 0, // Id do default button
  cancelId: 1,  // Id do cancel button
  checkboxLabel: 'Don\'t warn me about this again',
  checkboxChecked: false
}, (response, checkboxChecked) => {
  if (response === 0) console.log('User clicked OK');
  if (checkboxChecked) console.log('Checkbox checked');
});

Open File Dialog

const currentWindow = electron.remote.getCurrentWindow();
electron.remote.dialog.showOpenDialog(currentWindow, {
  title: '',
  buttonLabel: 'Load File',
  filters: [
    {name: "Pictures", extensions: ["png", "jpg", "gif"]},
    {name: "All Files", extensions: ["*"]}
  ],
  properties: ['openFile', 'openDirectory', 'multiSelections']
}, (selectedFiles) => {
  selectedFiles.forEach((selectedFile) => {
    console.log(selectedFile);
  });
});

Save File Dialog

const currentWindow = electron.remote.getCurrentWindow();
electron.remote.dialog.showSaveDialog(currentWindow, {
  title: '',
  buttonLabel: 'OK',
  filters: [
    {name: "Pictures", extensions: ["png", "jpg", "gif"]}
  ]
}, (filePath) => {
  console.log(filePath);
});

Menu

Tipos de itens de menu: normal, separator, submenu, checkbox, radio.

Normal

{
  type: 'normal',
  label: '',
  accelerator: 'CommandOrControl+Shift+A',
  enabled: true,
  visible: true,
  click: () => {}
}

Separator

{ type: 'separator' }

Submenu

{
  label: '',
  type: 'submenu',
  submenu: [
    { type: 'normal', label: ''}
    { type: 'checkbox', label: '', checked: true}
    ...
  ]
}

Check

{
  type: 'checkbox',
  label: '',
  enabled: true,
  visible: true,
  checked: true,
  click: (item) => {
    if(item.checked) {
    } else {
    }
  }
}

Radio

[
  {type: 'radio', label: ''},
  {type: 'radio', label: '', checked: true},
  ...
]

Accelerators

Mods: Command, Control, CommandOrControl, Alt, Option, AltGr, Shift, Super.

Keys: Space, Tab, Backspace, Delete, Insert, Enter, Up, Down, Left, Right, Escape.

Criação e uso

const myMenu = electron.Menu.buildFromTemplate([{...}, {...}, ...]);
electron.Menu.setApplicationMenu(myMenu);

Faz isso só depois de app ready.

Menu de contexto

const myMenu = electron.Menu.buildFromTemplate([{...}, {...}, ...]);
window.addEventListener('contextmenu', () => {
  myMenu.popup(electron.remote.getCurrentWindow());
});

Dicas de Estilização

  • Button Outlines: Tira com css

    button:focus {
      outline: none !important;
    }
  • User selections: Tira com css no elemento que não quer deixar selecionar

    user-select: none;

    Por exemplo, numa sidebar:

    #sidebar {
      ...
      user-select: none;
    }
  • Browser zoom: Limita no index.html, cria uma seção de script e coloca:

    <script>
      const electron = require('electron');
      electron.webFrame.setZoomLevelLimits(1, 1);
    </script>

Shell

const result = electron.shell.openExternal('');

Retorna um booleano. Recebe um endereço web, um arquivo via file://, ou um e-mail mailto:.

const result = electron.shell.openFile('');

Recebe o path para o arquivo. Não precisa colocar file://.

const result = electron.shell.showItemInFolder('');

Recebe o path para o arquivo.

const result = electron.shell.moveItemToTrash('');

Recebe o path para o arquivo.

⚠️ **GitHub.com Fallback** ⚠️