electron-builder+electron-updater实现应用自动更新过程

autoUpdater:使应用程序能够自动更新
ipcMain:用于从主进程到渲染进程的异步通信。
ipcRenderer:用于从渲染器进程到主进程的异步通信。
更多api在electron官网(中文)

介绍

接上篇electron将vue项目打包成桌面应用继续介绍一下在electron-builder打包基础下怎么使用electron-updater实现应用自动监测版本以及更新的。主要包括:

  • electron应用自动更新、主线程与渲染线程之间通信
  • 本地临时服务器搭建
  • 过程中的常见问题
electron应用自动更新具体实现流程图
electron应用自动更新过程.png
electron应用自动更新具体实现步骤

1.添加 electron-updater 包模块依赖

npm install electron-updater --save

2.在package.json文件增加 publish 配置,打包时可生成latest.yml,用于自动更新的配置信息latest.yml文件是打包过程生成的文件,为避免自动更新出错,打包后禁止对latest.yml文件做任何修改!
publish中url是安装包和latest.yml的服务器地址。这里我是配置的在本地临时搭建的服务期地址,下面我会介绍。

"build": {
    "appId": "com.electron.app",
    "copyright": "Copyright ***",
    "productName": "Electron",
    "publish": [
      {
        "provider": "generic",
        "url": "http://192.168.100.***:8000/"  //放置安装包和latest.yml的服务器地址
      }
    ],
    "files": [
      "!dist/**/*"
    ],
    "mac": {
      "icon": "build/icon.png", // 应用程序图标
      "category": "public.app-category.productivity",
      "artifactName": "${productName}_${version}.${ext}", // 应用程序包名
      "target": [
        "dmg",
        "zip"
      ]
    },
    "win": {
      "icon": "build/icon.png",
      "artifactName": "${productName}_${version}.${ext}",
      "verifyUpdateCodeSignature": false,
      "target": [
        {
          "target": "nsis",
          "arch": [
            "ia32"
          ]
        }
      ]
    },
    "nsis": { 
      "oneClick": false, // 是否一键安装
      "createDesktopShortcut": "always", // 是否添加桌面快捷方式
      "allowToChangeInstallationDirectory": true,// 允许修改安装目录
    },
    "extends": null
  }

build中可以适当增加nsis配置,可以优化用户体验,比如是否允许用户一键安装、自定义安装位置、是否添加桌面快捷方式、安装完成是否立即启动、配置安装图标等等。更多详细参数配置可参见官方文档 nsis配置

3.在主进程main.js文件中引入 electron-updater,ipcMain添加自动更新检测、事件监听、

const { app, BrowserWindow, ipcMain } = require('electron') // ipcMain 主线程
const { autoUpdater } = require('electron-updater')
const uploadUrl = 'http://192.168.100.***:8000/Desktop/download/' // 安装包helatest.yml所在服务器地址
// 检测更新,在你想要检查更新的时候执行,renderer事件触发后的操作自行编写
function updateHandle () {
  let message = {
    error: {status: -1, msg: '检测更新查询异常'},
    checking: {status: 0, msg: '正在检查更新...'},
    updateAva: {status: 1, msg: '检测到新版本,正在下载,请稍后'},
    updateNotAva: {status: 2, msg: '您现在使用的版本为最新版本,无需更新!'},
  }
let versionInfo = ''
  autoUpdater.setFeedURL(uploadUrl)
// 检测更新查询异常
  autoUpdater.on('error', function (error) {
    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) {
    mainWindow.webContents.send('downloadProgress', progressObj)
  })
 // 包下载成功时触发
  autoUpdater.on('update-downloaded', function (event, releaseNotes, releaseName, releaseDate, updateUrl, quitAndUpdate) {
 // 收到renderer进程确认更新
    ipcMain.on('updateNow', (e, arg) => {
      console.log('开始更新')
      autoUpdater.quitAndInstall() // 包下载完成后,重启当前的应用并且安装更新
    })
 // 主进程向renderer进程发送是否确认更新
    mainWindow.webContents.send('isUpdateNow', versionInfo)
  })

ipcMain.on('checkForUpdate', () => {
    // 收到renderer进程的检查通知后,执行自动更新检查
    // autoUpdater.checkForUpdates()
    let checkInfo = autoUpdater.checkForUpdates()
    checkInfo.then(function (data) {
      versionInfo = data.versionInfo // 获取更新包版本等信息
    })
  })
}

// 通过main进程发送事件给renderer进程,提示更新信息
function sendUpdateMessage (text) {
  mainWindow.webContents.send('message', text)
}

在主进程createWindow中需要调用一下updateHandle()

function createWindow () {
  updateHandle()
}

4.新建preload.js预处理文件,定义ipcRenderer,在main进程中添加preload配置项
preload.js: preload环境可以使用Node API,又能访问DOM、BOM的特殊环境,即使在dom文档还未形成之前

window.ipcRenderer = require('electron').ipcRenderer

main.js // 注意这是主渲染进程不是vue的main入口文件

const path = require('path')
let windowConfig = {
  width: 1000,
  height: 800,
  webPreferences: {
    nodeIntegration: false, // 使用了预加载之后,即使nodeIntegration为false,也可以使用Node API访问到ipcRenderer
    preload: path.join(__dirname, 'preload.js'),
  },
}

5.在renderer进程引入ipcRenderer,触发自动更新,并添加自动更新事件的监听,监听从主进程传过来的更新事件
我这里在app.vue里面进行监听:

import isElectron from 'is-electron'
mounted () {
    let vm = this
    if (isElectron()) {
      vm.ipcRenderer = window.ipcRenderer
      vm.ipcRenderer.on('message', (event, data) => {
        console.log('message', data.msg)
      })
      vm.ipcRenderer.on('downloadProgress', (event, progressObj) => {
        console.log('downloadProgress', progressObj)
        // 可自定义下载渲染效果
      })
      vm.ipcRenderer.on('isUpdateNow', (event, versionInfo) => {
          // 自定义选择效果,效果自行编写
        vm.confirm({
          title: '提示',
          content: '检测到新版本' + versionInfo.version + ',是否立即升级?',
          ok: '确定',
          cancel: '取消',
          onOk () {
            vm.ipcRenderer.send('updateNow')
          },
          onCancel (tx) {
          },
        })
      })
      vm.autoUpdate() // electron应用启动后主动触发检查更新函数
    }
  },
  beforeDestroy () {
    // 移除ipcRenderer所有事件
    if (isElectron()) {
      this.ipcRenderer.removeAllListeners()
    }
  },
  methods: {
    autoUpdate () { // 用来触发更新函数
      this.ipcRenderer.send('checkForUpdate')
    },
  },

这里加了一个is-electron,来判断是否在electron应用环境下,避免本地运行报错
添加依赖命令:npm install --save is-electron
另外在组件销毁时要及时移除ipcRenderer上的事件,避免重复监听.

6.打包
执行electron-builder进行打包,
windows下会生成安装包exe和latest.yml等文件,执行exe安装软件;
Mac下会生成安装包dmg、zip和latest-mac.yml文件,执行dmg安装软件。

windows.png

Mac.png

需要注意的一点是:mac上不签名也可以打包成功,安装的时候还要更改电脑权限,但是涉及到自动更新、发布到 app store等功能则不能用。所以说MAC包一定要添加代码签名,参考地址:code-signing

7.更新
先修改package.json中的version属性,先放一个高版本:修改 version: “1.7.0”
执行electron-builder打包,将资源包 上传到main主进程中的设置的uploadUrl地址下
Windows放置对应的exe、latest.yml文件
MAC下放置对应的dmg、zip、latest-mac.yml文件
再修改成低版本version: “1.0.0” 再次执行electron-builder打包,这里以windows为例(mac也是可以做到的,但是他需要代码签名才有效果),将低版本的exe程序安装并且运行之后,可以看到在应用启动后中触发更新检查,electron-updater自动会通过设置的uploadUrl下的.yml文件检查更新。效果如下:

包资源文件.png

低版本安装.png

检测版本.png

确定升级之后再次打开应用:

已是最新版本.png
本地临时服务器搭建

为了方便测试应用更新的效果,我使用python临时搭建了一个本地服务器作为应用资源的包的放置。(因为是本地服务器,监听不到下载进度,如需要看效果可以请在同一局域网的人帮忙测试一下即可)
python下载:参考地址
我是mac,本地是装的python是2.7版本,根据版本在终端输入:

python2.x: python -m SimpleHTTPServer
python3.x: python -m http.server
默认端口号是8000,也可以自定义端口。比如1896
python2.x: python -m SimpleHTTPServer 1896
python3.x: python -m http.server 1896
访问地址: http://主机ip:端口号/

在实现自动监测版本以及更新的过程中遇到的问题:

renderer进程使用require引入electron 报错:fs.existsSync is not a function或者Uncaught ReferenceError: require is not defined
renderer进程使用require报错:Uncaught ReferenceError: window.require is not a function

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
禁止转载,如需转载请通过简信或评论联系作者。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,378评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,356评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,702评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,259评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,263评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,036评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,349评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,979评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,469评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,938评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,059评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,703评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,257评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,262评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,485评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,501评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,792评论 2 345

推荐阅读更多精彩内容