Electron入门

525 阅读14分钟

介绍:Electron 是一个使用 JavaScript、HTML 和 CSS 构建桌面应用程序的框架。通过将Chromium和Node.js嵌入到其二进制文件中,Electron 允许您维护一个 JavaScript 代码库并创建可在 Windows、macOS 和 Linux 上运行的跨平台应用程序

一.基础文档

1.新建项目

1).# 安装 vue-cli 和 脚手架样板代码

npm install -g @vue/cli

vue init simulatedgreg/electron-vue my-project

各种选项可以根据实际需要选择

 

2).打开编译器终端,cd进项目文件夹

安装依赖npm install

并运行程序 npm run dev

:运行程序可能会报错Error: Electron failed to install correctly, please delete node_modules/electron and try installing again,提示删除electron重新下载,可能会不好使,应该是npm的问题,可以用cnpm淘宝镜像安装electron来解决问题。

1.首先删除electron

2.安装配置cnpm

npm install -g cnpm --registry=registry.npm.taobao.org

3.使用cnpm安装electron,用法与npm类似。

cnpm install --save electron

4.确认是否安装成功

electron -v

安装成功后再次npm run dev 程序就跑起来了

 



electron中Unable to install vue-devtools的解决方法

 

由于网络的问题,electron运行的时候加载vue-devtools失败。 Unable to install vue-devtools 。从日志里看retry了四次都timeout了。

 

先  npm install vue-devtools --save-dev

 

然后 把ready事件里面注释掉5行,再加上一行手动加载的。

 

最终src/main/index.dev.js里面修改后的内容如下(所有内容):

 

/* eslint-disable */

 

// Install electron-debug with devtron

require('electron-debug')({ showDevTools: true })

import {  BrowserWindow } from 'electron';

// Install vue-devtools

require('electron').app.on('ready', () => {

  let installExtension = require('electron-devtools-installer')

  // installExtension.default(installExtension.VUEJS_DEVTOOLS)

  //   .then(() => {})

  //  .catch(err => {

  //     console.log('Unable to install vue-devtools: \n', err)

  //   })

BrowserWindow.addDevToolsExtension('node_modules/vue-devtools/vender')  //手动加载vue-devtools,前提是 npm install vue-devtools --save-dev

  

})

 

// Require main process to boot app

require('./index')


Npm  run dev 后报错 [8492:0407/121603.977907:ERROR:CONSOLE(7830)] "Extension server error: Object not found: " , source : chrome-devtools://devtools/bundled/shell.js (7830) 的解决方法

 

可以在index.dev.js文件中

  • require('electron-debug')({ showDevTools: true });
  • require('electron-debug')();

 

报错 Starting inspector on 127.0.0.1:5858 failed: address already in use

端口被占用

找到.electron-vue文件夹下dev-runner.js文件,修改如下

var args = [

  // '--inspect=5858',

  '--inspect=58588',

  path.join(__dirname, '../dist/electron/main.js')

]


2. 项目目录

单一的 package.json 设置

electron-packager 和 electron-builder 现在完全支持单一的 package.json 设置。

 

dependencies

这些依赖项将会被包含在你最终产品的应用程序中。所以,如果你的应用程序需要某个模块才能运行,那么请在此安装!

 

devDependencies

这些依赖项不会被包含在你最终产品的应用程序中。在这里,你可以安装专门用于开发的模块,如构建脚本、webpack 加载器等等。

 

安装原生 NPM 模块

我们需要确保我们本地的 npm 模块是针对 electron 来构建的。为了做到这一点,我们可以使用 electron-rebuild,但是为了使事情变得更简单,我们强烈建议使用electron-builder 作为你的构建工具,因为它会为你处理很多任务。

 

关于 main 进程

在开发过程中,你可能会注意到 src/main/index.dev.js。该文件专门用于开发以及安装开发工具。原则上,该文件不应该被修改,但是可以被用来扩展你的开发需求。在构建的过程中,webpack 将介入其中并创建一个的捆绑,以 src/main/index.js 作为该捆绑的入口文件。

 

文件树

注意: 某些文件或文件夹可能会根据在 vue-cli 脚手架中所选设置的不同而有所不同。

my-project

├─ .electron-vue

│  └─ <build/development>.js files

├─ build

│  └─ icons/

├─ dist

│  ├─ electron/

│  └─ web/

├─ node_modules/

├─ src

│  ├─ main

│  │  ├─ index.dev.js

│  │  └─ index.js

│  ├─ renderer

│  │  ├─ components/

│  │  ├─ router/

│  │  ├─ store/

│  │  ├─ App.vue

│  │  └─ main.js

│  └─ index.ejs

├─ static/

├─ test

│  ├─ e2e

│  │  ├─ specs/

│  │  ├─ index.js

│  │  └─ utils.js

│  ├─ unit

│  │  ├─ specs/

│  │  ├─ index.js

│  │  └─ karma.config.js

│  └─ .eslintrc

├─ .babelrc

├─ .eslintignore

├─ .eslintrc.js

├─ .gitignore

├─ package.json

└─ README.md


产品构建****

app.asar

├─ dist

│  └─ electron

│     ├─ static/

│     ├─ index.html

│     ├─ main.js

│     └─ renderer.js

├─ node_modules/

└─ package.json

可以说,几乎所有的东西都在最终的产品构建中被删除。在分发 electron 应用程序时,这几乎是强制性的,因为你不希望用户下载拥有庞大文件的臃肿的软件。

 

3.项目配置单

electron的相关配置和vue共用一个文件vue.config.js,注意,这个文件如果不存在,需要自己新建一个。下面是配置所在位置

module.exports = {

    pluginOptions: {

        electronBuilder: {

            builderOptions: {

             // 用户自己的构建配置放在这里

                // 在这里的配置将会和默认配置合并,然后传递给electron-builder

            }

        }

    }

}

 

通用配置

下面的配置是通用的,对所有的平台打包产物都有用,更多详细信息可以查看 Electron Builder Configuration Options

 

module.exports = {

    pluginOptions: {

        electronBuilder: {

            builderOptions: {

                // 在这里的配置将会和默认配置合并,然后传递给electron-builder

         appId: 'com.example.vue-electron', // 项目唯一标识

         productName: 'Vue-Electron', // 打包产物的前缀

         copyright: 'Copyright © year author,//可用使用{author}', // 可用使用{}引用package.json里面配置项,配置项不存在会报错

         directories: {

         output: 'dist' // 打包产物的位置

         }

        }

        }

    }

}

 

Mac平台的配置

module.exports = {

    pluginOptions: {

        electronBuilder: {

            builderOptions: {

                // 在这里的配置将会和默认配置合并,然后传递给electron-builder

                appId: 'com.example.vue-electron', // 项目唯一标识

                productName: 'Vue-Electron', // 打包产物的前缀

                copyright: 'Copyright © year author,//可用使用{author}', // 可用使用{}引用package.json里面配置项,配置项不存在会报错

                directories: {

                    output: 'dist' // 打包产物的位置

                },

                // ------- Mac 相关配置

                mac: {

                    icon: 'build/icons/icon.icns', // 应用图标

                    category: 'public.app-category.utilities', // 应用类型

                    target: ['dmg'] // 打包的目标类型(默认是dmg和zip),支持很多类型,具体看文档

                }

            }

        }

    }

}

图标需要Mac平台特点的图标文件,category是应用的类型,target为打包产物类型

Win平台的配置

module.exports = {

    pluginOptions: {

        electronBuilder: {

            builderOptions: {

                // 在这里的配置将会和默认配置合并,然后传递给electron-builder

                appId: 'com.example.vue-electron', // 项目唯一标识

                productName: 'Vue-Electron', // 打包产物的前缀

                copyright: 'Copyright © year author,//可用使用{author}', // 可用使用{}引用package.json里面配置项,配置项不存在会报错

                directories: {

                    output: 'dist' // 打包产物的位置

                }

                // ------- windows 相关配置

                win: {

                    icon: 'build/icons/icon.ico', // 应用图标

                    target: ['nsis'] // 打包的目标类型,支持很多类型

                },

                nsis: {

                    "oneClick": false,

                    "perMachine": true,

                    "allowToChangeInstallationDirectory": true // 允许修改安装目录

                }

            }

        }

    }

}

nsis配置可参考www.electron.build/configurati…

Linux平台的配置

module.exports = {

    pluginOptions: {

        electronBuilder: {

            builderOptions: {

                // 在这里的配置将会和默认配置合并,然后传递给electron-builder

                appId: 'com.example.vue-electron', // 项目唯一标识

                productName: 'Vue-Electron', // 打包产物的前缀

                copyright: 'Copyright © year author,//可用使用{author}', // 可用使用{}引用package.json里面配置项,配置项不存在会报错

                directories: {

                    output: 'dist' // 打包产物的位置

                }

                // ------- linux 相关配置

                linux: {

                    icon: "build/icons", // 包含各种尺寸图标的文件夹

                    target: [

                        "AppImage",

                        "deb",

                        "rpm"

                    ],

                    category: "Utility",

                }

            }

        }

    }

}****

linux相关配置见www.electron.build/configurati…


图标的生成

项目添加electron-icon-builder依赖

npm i electron-icon-builder -D

然后再package.json里面scripts中添加如下脚本:

"electron:icon": "electron-icon-builder --input=./static/icon.png --output=build --flatten"

 

需要将名字为icon.png,大小为256*256的原始图标文件放置在static文件夹内,当然static也可以是其他目录然后执行如下命令,就可以生成所有平台的图标了.

npm run electron:icon

 

 

BrowserWindow的常用配置

文件位置src/main/index.js

function createWindow() {

mainWindow = new BrowserWindow({    //创建接口

width: Integer -窗口宽度,单位像素. 默认是 800

        height: Integer - 窗口高度,单位像素. 默认是 600.

        x: Integer - 窗口相对于屏幕的左偏移位置.默认居中.

        y: Integer - 窗口相对于屏幕的顶部偏移位置.默认居中.

        useContentSize:Boolean - width和 height使用web网页size, 这意味着实际窗口的size应该包括窗口框架的size,稍微会大一点,默认为 false

        center:Boolean - 窗口屏幕居中.

        minWidth:Integer - 窗口最小宽度,默认为 0

        minHeight:Integer - 窗口最小高度,默认为 0

        maxWidth:Integer - 窗口最大宽度,默认无限制.

        maxHeight:Integer - 窗口最大高度,默认无限制.

        resizable:Boolean - 是否可以改变窗口size,默认为 true

        movable:Boolean - 窗口是否可以拖动. 在 Linux 上无效. 默认为 true

        minimizable:Boolean - 窗口是否可以最小化. 在 Linux 上无效. 默认为 true

        maximizable:Boolean - 窗口是否可以最大化. 在 Linux 上无效. 默认为 true

        closable:Boolean - 窗口是否可以关闭. 在 Linux 上无效. 默认为 true

        alwaysOnTop:Boolean - 窗口是否总是显示在其他窗口之前. 在    Linux 上无效. 默认为 false

        fullscreen:Boolean - 窗口是否可以全屏幕. 当明确设置值为 false,全屏化按钮将会隐藏,在 macOS 将禁用. 默认 false

        fullscreenable:Boolean - 在 macOS 上,全屏化按钮是否可用,默认为 true

        skipTaskbar:Boolean - 是否在任务栏中显示窗口. 默认是false

        kiosk:Boolean - kiosk 方式. 默认为 false

        title:String - 窗口默认title. 默认 "Electron"

        icon:NativeImage - 窗口图标, 如果不设置,窗口将使用可用的默认图标.

        show:Boolean - 窗口创建的时候是否显示. 默认为 true

        frame:Boolean - 指定 false来创建一个 Frameless Window. 默认为 true

        acceptFirstMouse:Boolean - 是否允许单击web view来激活窗口 . 默认为 false

        disableAutoHideCursor:Boolean - 当 typing 时是否隐藏鼠标.默认 false

        autoHideMenuBar:Boolean - 除非点击 Alt,否则隐藏菜单栏.默认为 false

        enableLargerThanScreen:Boolean - 是否允许改变窗口大小大于屏幕. 默认是 false

        backgroundColor:String -窗口的 background color 值为十六进制,如 #66CD00(支持透明度). 默认为在 Linux 和 Windows 上为 #000(黑色) , Mac上为 #FFF(或透明).

        hasShadow:Boolean - 窗口是否有阴影. 只在 macOS 上有效. 默认为 true

        darkTheme:Boolean - 为窗口使用 dark 主题, 只在一些拥有 GTK+3 桌面环境上有效. 默认为 false

        transparent:Boolean - 窗口 透明. 默认为 false

        type:String - 窗口type, 默认普通窗口.

        titleBarStyle:String - 窗口标题栏样式.

        webPreferences:Object - 设置界面特性.

    });

    mainWindow.loadURL(winURL);     //加载窗口url,来自renderer进程的页面

    app.on("ready", createWindow);   //app准备好时创建窗口

    

    可根据需求设置以上属性。

 

 

二.常用api

1.主进程api

  1. shell 通过url的方式对文件进行操作

  2. screen 屏幕大小鼠标位置

  3. clipborad 剪切板文本文件

  4. crashReporter崩溃报告可以发送崩溃报告(需要外部服务支持)

  5. nativeImage所有与图片有关的模块

  6. ipcRender 渲染进程模块可以监听ipc信道中的事件以及接受ipc信道中的信息可用于与主进程(ipcMain)通信也可以和其他渲染进程通过webContents实例的send方法利用 id标志通信

7.desktopCapturer用来捕获桌面的声音视频,类似于录屏软件

8.remote 渲染进程想要拿到主进程的模块,例如菜单,提示框对象,只要是可枚举的就可以获取

9.webFrame 控制如何显示与渲染网页,例如网页的缩放,安全策略

10.app 控制应用的生命周期

11.BrowserWindow 创建控制浏览器窗口

12.webContents 是BrowserWindow的一个实例属性,用于渲染和控制网页

13.ipcMain 发送与接收ipc消息的一个模块(同步通信方式有坑,不要使用,在win7环境会导致页面渲染卡死)

14.dialog 可以用来打开和保存文件以及提示框功能

  1. Menu 可以创建鼠标右键菜单以及应用菜单以及通知栏小图标里面的菜单

  2. net 是Electron自带的一个http请求库

  3. protocol 可以注册协议,例如 file

  4. session 管理浏览器会话在webContents实例下可以拿到单层页面的session

  5. Tray 系统托盘可以添加通知栏区域的图标可以设置右键列表和点击事件(即win右下角那部分)

  6. systemPerferences可以获取当前计算机的偏好设置

  7. globalShortcut可以用来定义键盘的快捷键

  8. contentTracing用来跟踪收集数据的模块可以用来查看性能瓶颈

  9. powerSaveBlocker阻止系统进入睡眠模式

  10. powerMonitor监听电源状态更改的模块

  11. autoUpdater自动更新

2 . 渲染进程api

1. Electron desktopCapturer 模块:desktopCapturer 模块可用来获取可用资源,这个资源可通过 getUserMedia 捕获得到。

2. Electron ipcRenderer 模块:ipcRenderer 模块是一个 EventEmitter 类的实例。它提供了有限的方法,可以从渲染进程向主进程发送同步或异步消息。也可以收到主进程的响应。

3. Electron remote 模块:remote 模块提供了一种在渲染进程(网页)和主进程之间进行进程间通讯(IPC)的简便途径。Electron中, 与GUI相关的模块(如 dialog, menu 等)只存在于主进程,而不在渲染进程中 。为了能从渲染进程中使用它们,需要用ipc模块来给主进程发送进程间消息。使用 remote 模块,可以调用主进程对象的方法,而无需显式地发送进程间消息,这类似于 Java 的 RMI。

4. Electron webFrame 模块:web-frame 模块允许你自定义如何渲染当前网页。

5.ipcMain和ipcRenderer :实现父子组件间的通信,ipcMain是在main进程里面使用,ipcRenderer是在renderer进程里面使用

 

三.调试方法

1.控制台的打开方式:f12

2.各类资源查找

Electron-vue文档:simulatedgreg.gitbooks.io/electron-vu…

Electronjs官方文档:

www.electronjs.org/zh/docs/lat…

3.页面调试

需调试位置打debugger

 

四.打包


1 .代码混淆


bytenode可以将你的JavaScript代码编程成V8字节码,这可以有效的保护你的源码

npm install --save bytenode

在根目录下添加一个bytenode.js的文件

文件内容:

'use strict';

const fs = require('fs');

const path = require('path');

const bytenode = require('bytenode');

const v8 = require('v8');

v8.setFlagsFromString('--no-lazy');

try {

  (async function () {

    try {

      await bytenode.compileFile({

        filename: pathName,

        electron: true,  // electron的项目这个参数一定要加上

        compileAsModule: true

      }, ${pathName}c);

      // 将原来的js文件里面的内容替换成下面的内容

      fs.writeFileSync(pathName, 'require("bytenode");require("./main.jsc");', 'utf8');

    } catch (e) {

      console.error(run_bytenode_err: ${e});

    }

  }());

} catch (e) {

  console.error(run_bytenode_err: ${e});

}

 

写好脚本文件以后需要在package.json文件里面去添加脚本

 "scripts": {

    "build": "xxxxxxxxxxxxxxxxx", // 假设这是你的webpack打包代码的脚本

    "bytenode": "node ./bytenode.js", // 添加bytenode的脚本 执行之前写好的js文件

    "electron-build": "xxxxxxxxxxxxxxxxx" // 假设这是你的electron打包的脚本

        "pack": "npm run pack:main && npm run pack:renderer&& npm run bytenode" ,// 在这里加上bytenode的脚本

  },

出现eslint报错import

Babel的安装:

npm install -g babel-cli // -g 表示全局安装到 nodejs 下的目录

将 Babel 的转换插件安装到项目的目录中:

npm install babel-preset-es2015 --save

执行手动转换命令:

babel es6.js --out-file es5.js --presets es2015

2 .打包

采用了electron-builder来打包

全局安装electron-builder打包工具:npm install -g electron-builder@23.0.2

2、在项目根目录下的package.json文件中配置打包相关信息:

 

 

图中圈住部分是在windows下打包的配置,ia32代表生成的exe文件是32位的,因为64位电脑可运行32和64位的exe文件,所以直接打包32位就可以了,

打包后的输出文件是放到了build目录下,因为配置了

"directories": {

  "output": "build"

},

然后进行npm run pack编译

最后执行

electron-builder -m //mac

electron-builder -w//windows

 

Mac:

 

Windows:

 

五.原生electron与electron-vue的关系

Electron 是一个使用 JavaScript、HTML 和 CSS 构建桌面应用程序的框架。通过将Chromium和Node.js嵌入到其二进制文件中,Electron 允许您维护一个 JavaScript 代码库并创建可在 Windows、macOS 和 Linux 上运行的跨平台应用程序——无需原生开发经验。

electron-vue 是一个基于 vue 来构造 electron 应用程序的样板代码,类似于vue-cli。该项目的目的,是为了要避免使用 vue 手动建立起 electron 应用程序。electron-vue 充分利用 vue-cli 作为脚手架工具,加上拥有 vue-loader 的 webpack、electron-packager 或是 electron-builder,以及一些最常用的插件,如vue-router、vuex 等等。

 

Electron-vue可以直接使用electron的api,可以直接在main.js中按需引入

 

六.项目更新

安装插件

npm install electron-updater --save

复制代码配置publish

vue.config.js文件,builder配置内添加publish,如下:

 

配置publish项,是为了打包后生成latest.yml文件,该文件是用于判断版本升级的。是打包过程中生成的,为避免自动升级报错,生成后禁止修改文件内容,若文件有误,需要重新打包生成。

注意,这里有个坑,如果服务器更新地址经常变动,这里的url建议不填写,在主进程获取到url后,通过api重新设置。

latest.yml文件记录了版本号、更新包的路径、包大小、日期等。

 

主进程代码

electron-updater插件的代码必须在主进程执行

import { autoUpdater } from 'electron-updater'

// 检测更新,在你想要检查更新的时候执行,renderer事件触发后的操作自行编写

function updateHandle (updateConfig) {

  let message = {

    error: 'update error',

    checking: 'updating...',

    updateAva: 'fetch new version and downloading...',

    updateNotAva: 'do not to update'

  }

  // 设置服务器更新地址

  autoUpdater.setFeedURL({

    provider: 'generic',

    url: updateConfig.download

  })

  autoUpdater.on('error', function () {

    sendUpdateMessage(message.error)

  })

  autoUpdater.on('checking-for-update', function () {

    sendUpdateMessage(message.checking)

  })

  // 版本检测结束,准备更新

  autoUpdater.on('update-available', function (info) {

    sendUpdateMessage(message.updateAva)

  })

  autoUpdater.on('update-not-available', function (info) {

    sendUpdateMessage(message.updateNotAva)

  })

  // 更新下载进度事件

  autoUpdater.on('download-progress', function (progressObj) {

    console.log('下载进度百分比>>>', progressObj.percent)

  })

  // 下载完成

  autoUpdater.on('update-downloaded', function (event, releaseNotes, releaseName, releaseDate, updateUrl, quitAndUpdate) {

    // 退出且重新安装  

    autoUpdater.quitAndInstall()

  })

  ipcMain.on('checkForUpdate', () => {

    // 执行自动更新检查

    autoUpdater.checkForUpdates()

  })

  // 通过main进程发送事件给renderer进程,提示更新信息

  function sendUpdateMessage (text) {

mainWindow.webContents.send('message', text)

  }

}

export default updateHandle

 

渲染进程代码

// ####### 请保证updateHandle方法在主进程已经调用过一遍,事件监听都存在

// 检测更新

ipcRenderer.send('checkForUpdate')

读取进度条组件

主进程向渲染进程页面发送进度数据,展示当前更新进度