Windows下支持自动更新的Electron应用脚手架的方法


Posted in Javascript onDecember 24, 2018

前言

之前写过一篇关于 Windows 下通过 Electron 自带的 autoUpdater 实现应用自动更新的文章,很多小伙伴私信问我要具体实现代码,不过因为之前一直很忙(还有懒...)。

这两周正好周末比较空,除了在 github 上搭建了一个脚手架,还顺便把实现优化了一波,下面将会带着大家从零开始详细介绍实现过程,对小白也很友好的教程哦。

从零开始

进入你的工作目录,比如 d/workspace

# 目录 d/workspace
mkdir electron-demo # 新建文件夹 electron-demo
cd electron-demo # 进入文件夹 electron-demo
npm init # 初始化 npm,一路回车即可
npm i electron --save-dev # 安装 electron 依赖
touch main.js # 新建文件 main.js
touch index.html # 新建文件 index.html

现在你的文件结构如下:

|- electron-demo
 |- main.js # 空文件
 |- index.html # 空文件
 |- package.json
 |- package-lock.json # npm 自动生成的文件
 |- node_modules

确保 package.json 的name,version,description这三个字段都不为空,main 字段的取值为 main.js 。

{
 "name": "electron-demo",
 "version": "0.0.1",
 "description": "electron-demo",
 "main": "main.js"
}

主进程和渲染进程

Electron 应用分为主进程和渲染进程。渲染进程是直接与用户产生交互的进程,也就是我们看到的一个个窗口页面,而主进程主要负责控制应用的生命周期,负责各个渲染进程的通信等。

我们的主进程代码写在 main.js 中,所以首先在你心爱的代码编辑中打开 main.js,输入如下代码:

const path = require('path');
const url = require('url');
const {
  app,
  BrowserWindow
} = require('electron');

app.on('ready', () => {
  let win = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      devTools: true
    }
  });

  win.loadURL(
    url.format({
      pathname: path.join(__dirname, 'index.html'),
      protocol: 'file:',
      slashes: true
    })
  );
});

app.on('window-all-closed', () => app.quit());

再打开 index.html,输入如下代码:

<!DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8">
  <title>Hello World!</title>
</head>

<body>
  <h1>Hello World!</h1>
</body>

</html>

之后执行

# 目录 d/workspace/electron-demo
node_modules/.bin/electron .

不出意外的话你会看到一个弹出框,像这样:

Windows下支持自动更新的Electron应用脚手架的方法 

我们也可以把 node_modules/.bin/electron . 保存成 npm 脚本,方便以后调用。打开 package.json,添加如下内容:

"scripts": {
  "start": "electron ."
 }

以后只需要调用 npm start 即可。

到这里,我们已经有了一个最简单的 Electron 应用,如果你对继续开发应用本身更感兴趣的话,请移步Electron 官方文档,因为接下来我们会专注在怎么让这个应用实现自动更新。

自动更新

安装依赖

自动更新功能的实现依赖 electron-builder 和 electron-updater,所以我们需要先安装这两个依赖。

# 目录 d/workspace/electron-demo
npm i electron-builder --save-dev # 必须安装为开发依赖,否则打包会出错
npm i electron-updater --save # 必须安装为运行依赖,否则运行会出错

配置 package.json

为了配合打包 package.json 需要新增字段 build:

"build": {
  "appId": "com.xxx.app",
  "publish": [
   {
    "provider": "generic",
    "url": "http://127.0.0.1:8080"
   }
  ]
 },

同样为了执行方便,我们需要添加一个 npm 脚本,打开 package.json,添加如下内容:

"scripts": {
  "start": "electron .",
  "build": "electron-builder -w"
 }

以后只需要调用 npm run build 即可。

主进程和渲染进程

打开main.js,编辑后内容如下:

const path = require('path');
const url = require('url');
const {
  app,
  BrowserWindow,
  ipcMain 
} = require('electron');
const { autoUpdater } = require('electron-updater');
const feedUrl = `http://127.0.0.1:8080/${process.platform}`;

let webContents;

let createWindow = () => {
  let win = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      devTools: true
    }
  });

  webContents = win.webContents;

  win.loadURL(
    url.format({
      pathname: path.join(__dirname, 'src/index.html'),
      protocol: 'file:',
      slashes: true
    })
  );

  webContents.openDevTools();
};

let sendUpdateMessage = (message, data) => {
  webContents.send('message', { message, data });
};

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) {
    ipcMain.on('updateNow', (e, arg) => {
      //some code here to handle event
      autoUpdater.quitAndInstall();
    })
    sendUpdateMessage('isUpdateNow');
  });

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

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

  setTimeout(checkForUpdates, 1000);
});

app.on('window-all-closed', () => app.quit());

index.html:

<!DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8">
  <title>Hello World!</title>
</head>

<body>
  <h1>Hello World!</h1>
  <script>
    const { ipcRenderer } = require('electron');

    ipcRenderer.on('message', (event, { message, data }) => {
      console.log(message, data);
      switch (message) {
        case 'isUpdateNow':
          if (confirm('现在更新?')) {
            ipcRenderer.send('updateNow');
          }
          break;
        default:
          document.querySelector('h1').innerHTML = message;
          break;
      }
    });
  </script>
</body>

</html>

打包

npm run build

第一次运行会比较慢,运行结束后会在当前目录下新增一个 dist 文件夹,dist 的目录结构如下:

|- dist
 |- win-unpacked
 |- electron-autoupdate-scaffold Setup.exe
 |- electron-autoupdate-scaffold Setup.exe.blockmap
 |- electron-builder-effective-config.yaml
 |- latest.yml

win-unpacked 下是可执行文件,但是先别着急运行,我们还缺一个后台。

自动更新后台

聪明的你一定注意到,前面代码中我们有一个:

const feedUrl = `http://127.0.0.1:8080/${process.platform}`;

所以我们现在要做的就是一个可以接受这个请求的服务。

回到你的工作目录(d/workspace)

# 目录 d/workspace
mkdir electron-server
cd electron-server
npm init
npm i koa --save
npm i koa-static --save
touch server.js

打开 server.js,输入如下内容:

// server.js
let Koa = require('koa');
let app = new Koa();
let path = require('path');

app.use(require('koa-static')(path.resolve(__dirname + '/packages')));

let server = app.listen(8080, () => {
  let { address, port } = server.address();

  console.log("应用实例,访问地址为 http://%s:%s", address, port);
});

将之前打包出来的 dist 目录下的 4 个文件(除了 win-unpacked)拷贝到这边的 packages/win32 下(新建目录 packages/win32),之后

# 目录 d/workspace/electron-server
npm start

到此为止,我们的自动更新服务就搭建完成了,现在来一波测试吧。

测试

进入 electron-demo/dist/win-unpacked 找到可执行文件,双击运行,看到打开窗口的控制台中依次输出:

checking-for-update
update-not-available

进入 electron-demo,打开 package.json,把版本号改为0.0.2,重新打包后拷贝打包文件到自动更新后台目录(d/workspace/electron-server/packages/win32)。

进入 electron-demo,打开 package.json,把版本号改为0.0.1,重新打包后再次进入 dist/win-unpacked 目录,运行 exe,看到打开窗口的控制台中依次输出:

checking-for-update
update-available

并且出现弹窗提示「现在更新?」。

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

Javascript 相关文章推荐
javascript 使用 NodeList需要注意的问题
Mar 04 Javascript
Js中获取frames中的元素示例代码
Jul 30 Javascript
JS正则验证邮箱的格式详细介绍
Nov 19 Javascript
JS比较两个时间大小的简单示例代码
Dec 20 Javascript
jquery.cookie.js使用指南
Jan 05 Javascript
javascript轻量级库createjs使用Easel实现拖拽效果
Feb 19 Javascript
jQuery数据检索中根据关键字快速定位GridView指定行的实现方法
Jun 08 Javascript
浅谈jQuery中ajaxPrefilter的应用
Aug 01 Javascript
JS中位置与大小的获取方法
Nov 22 Javascript
微信小程序 图片边框解决方法
Jan 16 Javascript
利用d3.js力导布局绘制资源拓扑图实例教程
Jan 08 Javascript
layui实现数据分页功能(ajax异步)
Jul 27 Javascript
如何使用electron-builder及electron-updater给项目配置自动更新
Dec 24 #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
You might like
php 获取select下拉列表框的值
2010/05/08 PHP
php操作SVN版本服务器类代码
2011/11/27 PHP
两级联动select刷新后其值保持不变的实现方法
2014/01/27 PHP
无需数据库在线投票调查php代码
2016/07/20 PHP
PHP实现登陆并抓取微信列表中最新一组微信消息的方法
2017/07/10 PHP
JavaScript高级程序设计阅读笔记(十六) javascript检测浏览器和操作系统-detect.js
2012/08/14 Javascript
Javscript调用iframe框架页面中函数的方法
2014/11/01 Javascript
js封装可使用的构造函数继承用法分析
2015/01/28 Javascript
jquery合并表格中相同文本的相邻单元格
2015/07/17 Javascript
JS中mouseover和mouseout多次触发问题如何解决
2016/06/06 Javascript
jQuery Easy UI中根据第一个下拉框选中的值设置第二个下拉框是否可以编辑
2016/11/29 Javascript
原生js实现中奖信息无间隙滚动效果
2017/01/18 Javascript
Node.js+ES6+dropload.js实现移动端下拉加载实例
2017/06/01 Javascript
vue.js中v-on:textInput无法执行事件问题的解决过程
2017/07/12 Javascript
JS库particles.js创建超炫背景粒子插件(附源码下载)
2017/09/13 Javascript
angular4 JavaScript内存溢出问题
2018/03/06 Javascript
vue项目前端错误收集之sentry教程详解
2019/05/27 Javascript
微信小程序在ios下Echarts图表不能滑动的问题解决
2019/07/10 Javascript
vue实现扫码功能
2020/01/17 Javascript
基于ajax及jQuery实现局部刷新过程解析
2020/09/12 jQuery
使用vant的地域控件追加全部选项
2020/11/03 Javascript
Python的迭代器和生成器
2015/07/29 Python
Python常见格式化字符串方法小结【百分号与format方法】
2016/09/18 Python
Python matplotlib图例放在外侧保存时显示不完整问题解决
2020/07/28 Python
使用PyCharm安装pytest及requests的问题
2020/07/31 Python
浅析CSS3 用text-overflow解决文字排版问题
2020/10/28 HTML / CSS
欧洲领先的火车票和大巴票预订平台:Trainline
2018/12/26 全球购物
Speedo速比涛法国官方网站:泳衣、泳镜、泳帽、泳裤
2019/07/30 全球购物
澳大利亚礼品篮网站:Macarthur Baskets
2019/10/14 全球购物
工商管理系学生的自我评价分享
2013/11/29 职场文书
付款委托书范本
2014/04/04 职场文书
篮球兴趣小组活动总结
2014/07/07 职场文书
办理房产证委托书
2014/09/18 职场文书
2015年仓库管理员工作总结
2015/04/21 职场文书
python四种出行路线规划的实现
2021/06/23 Python
MySql分区类型及创建分区的方法
2022/04/13 MySQL