如何使用electron-builder及electron-updater给项目配置自动更新


Posted in Javascript onDecember 24, 2018

说明:

本文的自动更新功能使用的项目为 electron-vue 脚手架搭建一个默认项目。

参考的文章如下:

  • electron-vue 中文文档
  • electron-builder 文档
  • Windows 下支持自动更新的 Electron 应用脚手架
  • Electron 文档 Docs / API / autoUpdater

开始:新建一个 electron 项目

首先你得有一个需要配置自动更新功能的 electron 项目。这里我为了测试自动更新功能是否成功搭建使用的是 electron-vue 脚手架搭建的项目。

搭建过程如下:

# 安装 vue-cli 和 脚手架样板代码
npm install -g vue-cli
vue init simulatedgreg/electron-vue autoUpdataTest

# 安装依赖并运行你的程序
cd autoUpdataTest
npm install
npm run dev

程序运行后的界面如下:

如何使用electron-builder及electron-updater给项目配置自动更新

脚手架生成的文件结构:

|- autoUpdateTest
 |- .electron-vue # 压缩及运行环境的配置文件
 |- build # 
 |- icons # 图标文件
 |- ... # 打包生成的文件在此处 
 |- dist # 用 webpack 压缩项目后生成的压缩文件在此处
 |- node_modules
 |- src # 资源文件
 |- main # 主进程
 |- renderer # 渲染进程
 |- index.ejx # 入口文件
 |- static # 静态资源
 |- .babelrc
 |- .gitignore
 |- .travis
 |- appveyor.yml
 |- package-lock.json # npm 自动生成的文件
 |- package.json
 |- README.md

使用 electron-builder 最关键的配置在 package.json 里:(为了观察我们所需要的地方,把此篇文章里不需要关注的代码给删掉了。)

{
 "name": "autoupdatetest",
 "version": "0.0.0",
 "author": "wonder <xxxxxxxxx@qq.com>",
 "description": "An electron-vue project",
 "main": "./dist/electron/main.js", 
 "scripts": {
 "build": "node .electron-vue/build.js && electron-builder",
 "dev": "node .electron-vue/dev-runner.js",
 },
 "build": {
 "productName": "autoupdateteset",
 "appId": "org.simulatedgreg.electron-vue",
 "directories": {
  "output": "build"
 },
 "files": "dist/electron/**/*",
 "win": {
  "icon": "build/icons/icon.ico"
 }
 },
 "dependencies": {
 },
 "devDependencies": {
 }
}

解析:

前四行是一般的 package.json 会有的:

  • name — 项目名
  • version — 版本号
  • author — 开发人员及邮箱号
  • description — 项目描述 。

下面重点看后面的内容:electron-builder详细配置文档

  • "main": "./dist/electron/main.js" — 这里的 main 入口文件指的是用 electron-builder 打包主程序的入口文件,这里的路径是使用 webpack 压缩项目后文件输出的位置。
  • scripts — 脚本
    • "build": "node .electron-vue/build.js && electron-builder" — 生产环境,压缩打包项目。先运行 .electron-vue 文件夹下的 build.js 脚本对项目进行压缩,输出的位置在 dist 文件夹下,然后再使用配置好的 electron-builder 对 dist 文件夹下的文件进行打包生成应用的安装包。
    • "dev": "node .electron-vue/dev-runner.js" — 开发环境,可以运行我们的项目并测试。这里使用了热更新,改动代码不需要刷新即可看到应用的改变。
  • build — electron-builder 配置项
    • "productName": "autoupdateteset", — 工程项目名
    • "appId": "org.simulatedgreg.electron-vue" — 应用程序 ID。强烈建议设置显式ID。
    • directories
    • "output": "build" — 生成的安装包输出目录。
    • "files": "dist/electron/**/*" — 安装包源文件目录,支持多路径(数组)
    • "win": { "icon": "build/icons/icon.ico"} — 打包成 Windows 系统下安装包应用程序图标路径,还有别的配置项可以在详细文档中查看。

有关 electron-vue 的使用的更详细的说明请看 中文文档。

自动更新

安装依赖

自动更新功能的实现依赖 electron-builderelectron-updater

因为我们是用的electron-builder脚手架生成的项目,已经有 electron-builder 依赖了,所以只需要安装 electron-updater

# 目录 E:\GitHub\autoupdateteset
npm i electron-updater --save # 必须安装为运行依赖,否则运行会出错

配置 package.json

为了配合打包 package.json 需要给 build 新增配置项:

"build": {
 "publish": [
  {
   "provider": "generic",
   "url": "http://127.0.0.1:5500/" #这里是我本地开的服务器的地址
  }
 ],
 ...
}

主进程(参考:electron 中文文档)

主进程的入口文件是 src/main/index.js

import { 
app,   // app 模块是为了控制整个应用的生命周期设计的。
BrowserWindow, // BrowserWindow 类让你有创建一个浏览器窗口的权力。
ipcMain 
} from 'electron';

// 引入自动更新模块
const { autoUpdater } = require('electron-updater');
// 不支持 ES6 则用如下方式引入
// const autoUpdater = require("electron-updater").autoUpdater

const feedUrl = `http://127.0.0.1:5500/win32`; // 更新包位置


/**
 * Set `__static` path to static files in production
 * https://simulatedgreg.gitbooks.io/electron-vue/content/en/using-static-assets.html
 */
if (process.env.NODE_ENV !== 'development') {
 global.__static = require('path').join(__dirname, '/static').replace(/\\/g, '\\\\');
}

let mainWindow, webContents;
const winURL = process.env.NODE_ENV === 'development' ?
 `http://localhost:9080` :
 `file://${__dirname}/index.html`;

function createWindow() {
 /**
  * Initial window options
  */
 mainWindow = new BrowserWindow({
  height: 563,
  useContentSize: true,
  width: 1000
 });

 mainWindow.loadURL(winURL);

 webContents = mainWindow.webContents;

 mainWindow.on('closed', () => {
  mainWindow = null;
 });
}

// 主进程监听渲染进程传来的信息
ipcMain.on('update', (e, arg) => {
 console.log("update");
 checkForUpdates();
});

let checkForUpdates = () => {
 // 配置安装包远端服务器
 autoUpdater.setFeedURL(feedUrl);

 // 下面是自动更新的整个生命周期所发生的事件
 autoUpdater.on('error', function(message) {
  sendUpdateMessage('error', message);
 });
 autoUpdater.on('checking-for-update', function(message) {
  sendUpdateMessage('checking-for-update', message);
 });
 autoUpdater.on('update-available', function(message) {
  sendUpdateMessage('update-available', message);
 });
 autoUpdater.on('update-not-available', function(message) {
  sendUpdateMessage('update-not-available', message);
 });

 // 更新下载进度事件
 autoUpdater.on('download-progress', function(progressObj) {
  sendUpdateMessage('downloadProgress', progressObj);
 });
 // 更新下载完成事件
 autoUpdater.on('update-downloaded', function(event, releaseNotes, releaseName, releaseDate, updateUrl, quitAndUpdate) {
  sendUpdateMessage('isUpdateNow');
  ipcMain.on('updateNow', (e, arg) => {
   autoUpdater.quitAndInstall();
  });
 });

 //执行自动更新检查
 autoUpdater.checkForUpdates();
};

// 主进程主动发送消息给渲染进程函数
function sendUpdateMessage(message, data) {
 console.log({ message, data });
 webContents.send('message', { message, data });
}

app.on('ready', () => {
 createWindow();
});

app.on('window-all-closed', () => {
 if (process.platform !== 'darwin') {
  app.quit();
 }
});

app.on('activate', () => {
 if (mainWindow === null) {
  createWindow();
 }
});

渲染进程

渲染进程的入口文件是 src/renderer/index.js

这里我们主要修改 App.vue,将原来的内容全删掉并使更新的整个周期在界面上打印出来。

<template>
 <div id="app">
  <!-- <router-view></router-view> -->
  <button @click="autoUpdate()">获取更新</button>
  <ol id="content">
   <li>生命周期过程展示</li>
  </ol>
 </div>
</template>

<script>
// import { ipcRenderer } from 'electron';
const { ipcRenderer } = require('electron');
export default {
 name: 'my-project1',
 mounted() {
  var _ol = document.getElementById("content");
  ipcRenderer.on('message',(event,{message,data}) => {
   let _li = document.createElement("li");
   _li.innerHTML = message + " <br>data:" + JSON.stringify(data) +"<hr>";
   _ol.appendChild(_li);
   if (message === 'isUpdateNow') {
    if (confirm('是否现在更新?')) {
     ipcRenderer.send('updateNow');
    }
   }
  });
 },
 methods: {
 autoUpdate() {
  ipcRenderer.send('update');
 }
 }
};
</script>

<style>
/* CSS */
</style>

显示的界面如下:

如何使用electron-builder及electron-updater给项目配置自动更新

自动更新过程简单介绍

1.将 webpack.json 里的版本号先改为 0.0.1,然后npm run build生成一个版本为0.0.1的安装包。

如何使用electron-builder及electron-updater给项目配置自动更新 

如何使用electron-builder及electron-updater给项目配置自动更新

注意上面一步会生成一个latest.yml文件,autoUpdate 实际上通过检查该文件中安装包版本号与当前应用版本号对比来进行更新判断的。

latest.yml文件内容如下:

如何使用electron-builder及electron-updater给项目配置自动更新

2.然后将上一步生成的安装包放在本地开启的服务器文件夹下,对应你在主程序入口文件中配置的服务器位置。

如何使用electron-builder及electron-updater给项目配置自动更新

3.将 package.json 中的版本号改回0.0.0,再npm run build一遍,运行 build 文件夹下的 exe 安装包,就将软件安装在你电脑里面了。点击安装完成后桌面上的快捷方式,再次点击上面的获取更新的按钮就可以看到显示在界面的自动更新生命周期了。(但这里因为会给你直接自动更新,所以会一闪而过,你可以在 autoUpdate 的各个生命周期事件里设置主进程与渲染进程通信,则可以一步一步观察到整个自动更新的生命周期了。)

通过测试总结 autoUpdate 生命周期图

如何使用electron-builder及electron-updater给项目配置自动更新

更新过程展示

1、无版本更新

如何使用electron-builder及electron-updater给项目配置自动更新 

如何使用electron-builder及electron-updater给项目配置自动更新

2、有版本更新

如何使用electron-builder及electron-updater给项目配置自动更新 

点击取消后会先不更新,在应用关闭后更新:

如何使用electron-builder及electron-updater给项目配置自动更新 

点击确认后则会直接更新:

如何使用electron-builder及electron-updater给项目配置自动更新

踩过的坑

1、主进程与渲染进程通信

最开始我是直接在主进程直接运行更新

如何使用electron-builder及electron-updater给项目配置自动更新 

然后想在渲染进程中打印主进程传过来的消息,但是发现只有 isUpdateNow 事件运行时才有日志显示。

结果发现原来主进程与渲染进程之间通信必须在渲染进程已经运行的时候(即那个界面完全显示出来)才能够进行。所以我将自动更新改为界面按钮触发,这样才能检测到自动更新的整个流程。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
繁简字转换功能
Jul 19 Javascript
JQuery 常用操作代码
Mar 14 Javascript
在jQuery 1.5中使用deferred对象的代码(翻译)
Mar 10 Javascript
Chosen 基于jquery的选择框插件使用方法
May 30 Javascript
jquery获取选中的文本和值的方法
Jul 08 Javascript
JavaScript中的闭包
Feb 24 Javascript
JS实现获取当前URL和来源URL的方法
Aug 24 Javascript
javaScript canvas实现(画笔大小 颜色 橡皮的实例)
Nov 28 Javascript
JS中使用textPath实现线条上的文字
Dec 25 Javascript
使用Angular CLI快速创建Angular项目的一些基本概念和写法小结
Apr 22 Javascript
Node.js JSON模块用法实例分析
Jan 04 Javascript
javascript设计模式 ? 简单工厂模式原理与应用实例分析
Apr 09 Javascript
Vue.js组件高级特性实例详解
Dec 24 #Javascript
JavaScript模板引擎原理与用法详解
Dec 24 #Javascript
jQuery实现的简单日历组件定义与用法示例
Dec 24 #jQuery
原生js实现Flappy Bird小游戏
Dec 24 #Javascript
node错误处理与日志记录的实现
Dec 24 #Javascript
详解如何在vscode里面调试js和node.js的方法步骤
Dec 24 #Javascript
@angular前端项目代码优化之构建Api Tree的方法
Dec 24 #Javascript
You might like
PHP 和 MySQL 基础教程(四)
2006/10/09 PHP
php判断页面是否是微信打开的示例(微信打开网页)
2014/04/25 PHP
php常用数学函数汇总
2014/11/21 PHP
php结合安卓客户端实现查询交互实例
2015/05/05 PHP
PHP数据分析引擎计算余弦相似度算法示例
2017/08/08 PHP
js几个不错的函数 $$()
2006/10/09 Javascript
js 操作css实现代码
2009/06/11 Javascript
javascript的console.log()用法小结
2012/05/31 Javascript
Web跨浏览器进程通信(Web跨域)
2013/04/17 Javascript
js实现两个值相加alert出来精确到指定位
2013/09/25 Javascript
JS辨别访问浏览器判断是android还是ios系统
2014/08/19 Javascript
JavaScript生成随机字符串的方法
2015/03/19 Javascript
AngularJs Injecting Services Into Controllers详解
2016/09/02 Javascript
浅谈Javascript中的Label语句
2016/12/14 Javascript
canvas仿iwatch时钟效果
2017/03/06 Javascript
日期时间范围选择插件:daterangepicker使用总结(必看篇)
2017/09/14 Javascript
JS实现的缓冲运动效果示例
2018/04/30 Javascript
layui获取多选框中的值方法
2018/08/15 Javascript
浅谈鸿蒙 JavaScript GUI 技术栈
2020/09/17 Javascript
[07:39]第一届亚洲邀请赛回顾视频
2017/02/14 DOTA
[54:05]DOTA2-DPC中国联赛定级赛 SAG vs iG BO3第一场 1月9日
2021/03/11 DOTA
Python 探针的实现原理
2016/04/23 Python
实例详解Python装饰器与闭包
2019/07/29 Python
3种适用于Python的疯狂秘密武器及原因解析
2020/04/29 Python
美国购车网站:TrueCar
2016/10/19 全球购物
Nasty Gal英国:美国女性服饰销售网站
2021/03/02 全球购物
长曲棍球装备:Lacrosse Monkey
2020/12/02 全球购物
应聘自荐信
2013/12/14 职场文书
奠基仪式主持词
2014/03/20 职场文书
七匹狼男装广告词
2014/03/21 职场文书
经理秘书求职自荐信范文
2014/03/23 职场文书
岗位聘任书范文
2014/03/29 职场文书
铅球加油稿100字
2014/09/26 职场文书
2015年前台个人工作总结
2015/04/03 职场文书
导游词之江南周庄
2019/12/06 职场文书
nginx location 带斜杠【 / 】与不带的区别
2022/04/13 Servers