Beace Lee

Beace Blog

Written by Beace Lee who lives and works in China building useful things. You should follow him on Twitter

electron 10 问 10 答

November 09, 2018

  1. 如何利用NodeJS 子进程为 electron render 提供 API server,以及维护子进程的状态

可以通过NodeJS 内置模块 child_process spawn 文件,并且watch文件的状态。

const node = childProcess.spawn(path.join(dirPath, binariesPath), [], {
  cwd: process.cwd(),
  env: {}
});
node.stdout.on('data', data => {
  console.log(`stdout: ${data}`);
});

在 main.js 中引入 child , 保证在渲染之前子进程已经调用。

import childProcess from './child';

在electron退出时杀死进程,以免造成 API 端口的占用。

app.on('before-quit', () => {
  childProcess.kill('SIGINT');
});
  1. 如何更新时不覆盖用户的登录状态和动态生成的缓存文件

electron 更新时会将 application 中的内容覆盖,导致文件丢失。

不过 electron 提供了获取 userData 的 API, 可以根据 electron.app.getPath('userData') 获取用户存储信息的位置,在 MacOS 下为 /Users/username/Library/Application Support/appname,可以将用户信息存储和缓存问题件存储在这个位置,从而避免更新时覆盖源文件。

  1. Windows 如何进行选择目录安装,electron-builder 配置介绍

通过 electron builder 进行 electron 打包时,Windows 环境下添加如下配置

"win": {
  "target": [
    "nsis"
  ]
},
"nsis": {
  "oneClick": false,
  "allowToChangeInstallationDirectory": true
}

这样 Windows 用户在安装时会提示用户选择安装位置

  1. 如何自动更新(MacOS)

首先需要再Mac下自签发一张代码签名证书。electron-build 在打包签名时会自动匹配当前的可信证书。不同证书打包出来的应用是不可以自动更新的,包括appid不一致也会导致更新不成功。

mac下创建代码签名证书在钥匙串->证书助理中创建,并确保证书可信。创建成功后,双击证书,选择系统信任。

可以采用 electron-simple-updater/example at master · megahertz/electron-simple-updater · GitHub 进行更新配置。由于 electron builder 采用的是两个 package.json Two package.json Structure - electron-builder 的结构, 即开发依赖和应用依赖。简单理解为根目录下,应该存放打包需要的环境以及工具等依赖,在真正 app 中的依赖是最终打包到 electron 中去的。 因此需要把 electron-simple-updater 放在 ./app/package.json中,并且在package.json中添加updater的远程地址。

最终你的配置应该与下面的类似

// ./app/package.json
"updater": {
  "url": "https://update.domain.com/updates.json"
},
"dependencies": {
  "electron-simple-updater": "^1.2.4"
}

具体 updates.json 包含如下

{
  "win32-x64-prod": {
    "readme": "Second release",
    "update": "https://github.com/megahertz/electron-simple-updater/releases/download/win32-x64-prod-v0.0.2",
    "install": "https://github.com/megahertz/electron-simple-updater/releases/download/win32-x64-prod-v0.0.2/Simple.Updater.Example.Setup.0.0.2.exe",
    "version": "0.0.2"
  },
  "darwin-x64-prod": {
    "readme": "Second Release",
    "update": "https://github.com/megahertz/electron-simple-updater/releases/download/darwin-x64-prod-v0.0.2/release.json",
    "install": "https://github.com/megahertz/electron-simple-updater/releases/download/darwin-x64-prod-v0.0.2/Simple.Updater.Example-0.0.2.dmg",
    "version": "0.0.2"
  },
  "linux-x64-prod": {
    "update": "https://github.com/megahertz/electron-simple-updater/releases/download/linux-x64-prod-v0.0.2/simple-updater-example-0.0.2-x86_64.AppImage",
    "install": "https://github.com/megahertz/electron-simple-updater/releases/download/linux-x64-prod-v0.0.2/simple-updater-example-0.0.2-x86_64.AppImage",
    "version": "0.0.2"
  }
}
  1. CI如何在一个平台构建多个平台的安装包

electron 支持在一个平台打包多个平台的安装包,为了和本地开发环境保持一致,可以在ci中通过shell的方式直接在MacOS上进行打包。

  1. 如何将额外的文件打包至app/content 中

可以在开发环境下的package.json 文件中增加额外的文件,例如

"build": {
  "extraFiles": [{
    "from": "binaries/${os}",
    "to": "binaries/",
    "filter": [
      "**/*"
    ]
  }]
}

可以根据不同的操作系统附加不同的文件,例如上面的配置打包之后会在应用程序的目录下出现 binaries 包文件。

开发过程中可以通过指定环境变量的方式来使用不同文件的包。

  1. headless模式下如何自定义关闭按钮

通过 electron 中的事件进行模拟。MacOS下关闭事件并不杀死进程,与Windows和linux进行区分。

import { remote } from 'electron';
handleClose = () => {
  if (isWindows() || isLinux()) {
    remote.getCurrentWindow().close();
  } else {
    remote.getCurrentWindow().hide();
  }
};

  handleMinimize = () => {
    remote.getCurrentWindow().minimize();
  };

  handleFullscreen = () => {
    remote
      .getCurrentWindow()
      .setFullScreen(!remote.getCurrentWindow().isFullScreen());
    this.setState({
      fullscreen: remote.getCurrentWindow().isFullScreen()
    });
  };
  1. electron 图标

可以通过下面的工具将一张图片转换成多张不同尺寸的图片,并且可以导出ico、icns格式的图片。

ICON CONVERTER: Convert PNG to ICO and ICNS online - iConvert Icons

  1. 无边窗口的拖动 要使整个窗口可拖拽, 可以直接在body中添加如下样式
body {
  -webkit-app-region: drag;
}

同时需要将其中触发点击事件的元素标记为不可拖拽, 不然无法点击

.no-drag {
  -webkit-app-region: no-drag;
}

如果只想要自定义的标题栏进行拖拽,则可以使用如下样式

.titlebar {
  -webkit-user-select: none;
  -webkit-app-region: drag;
}
  1. 主进程与渲染进程的通信

以一个点击菜单为例, 点击菜单后在渲染进程监听动作并执行操作。

{
  label: '偏好设置...',
  accelerator: 'Command+,',
  click: (menuItem, currentWindow) => {
    currentWindow.webContents.send('openPreferences');
  }
},
ipcRenderer.on('getPreferences', () => {
  this.setState(prevState => ({
    isPreferencesOpen: !prevState.isPreferencesOpen
  }));
});

webContents 属于主进程,向网页发送消息,接收到后打开『偏好设置』。