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 相关文章推荐
DWR Ext 加载数据
Mar 22 Javascript
分享27款非常棒的jQuery 表单插件
Mar 28 Javascript
面向对象的Javascript之三(封装和信息隐藏)
Jan 27 Javascript
js动态设置div的值下例子
Oct 29 Javascript
node.js中的fs.unlink方法使用说明
Dec 15 Javascript
实例详解JSON数据格式及json格式数据域字符串相互转换
Jan 07 Javascript
jQuery的Each比JS原生for循环性能慢很多的原因
Jul 05 Javascript
微信小程序 绘图之饼图实现
Oct 24 Javascript
canvas学习之API整理笔记(二)
Dec 29 Javascript
javascript图片预览和上传(兼容IE)
Mar 15 Javascript
webpack v4 从dev到prd的方法
Apr 02 Javascript
js+html5 canvas实现ps钢笔抠图
Apr 28 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
长波知识介绍
2021/03/01 无线电
咖啡的植物学知识
2021/03/03 咖啡文化
PHP实现采集程序原理和简单示例代码
2007/03/18 PHP
基于jQueryUI和Corethink实现百度的搜索提示功能
2016/11/09 PHP
laravel实现简单用户权限的示例代码
2019/05/28 PHP
JQUERY 获取IFrame中对象及获取其父窗口中对象示例
2013/08/19 Javascript
基于jquery的网站幻灯片切换效果焦点图代码
2013/09/15 Javascript
jquery比较简洁的软键盘特效实现方法
2015/03/19 Javascript
jQuery选择器源码解读(五):tokenize的解析过程
2015/03/31 Javascript
AngularJS向后端ASP.NET API控制器上传文件
2016/02/03 Javascript
JS原型链 详解及示例代码
2016/09/06 Javascript
详解原生js实现offset方法
2017/06/15 Javascript
解决npm安装Electron缓慢网络超时导致失败的问题
2018/02/06 Javascript
vue debug 二种方法
2018/09/16 Javascript
使用原生JS实现滚轮翻页效果的示例代码
2020/05/31 Javascript
python链接Oracle数据库的方法
2015/06/28 Python
python 数据清洗之数据合并、转换、过滤、排序
2017/02/12 Python
用python编写第一个IDA插件的实例
2018/05/29 Python
Python3 导入上级目录中的模块实例
2019/02/16 Python
Python 使用多属性来进行排序
2019/09/01 Python
Django自定义全局403、404、500错误页面的示例代码
2020/03/08 Python
python爬虫实现获取下一页代码
2020/03/13 Python
python高阶函数map()和reduce()实例解析
2020/03/16 Python
pycharm工具连接mysql数据库失败问题
2020/04/01 Python
一个非常简单好用的Python图形界面库(PysimpleGUI)
2020/12/28 Python
html5本地存储_动力节点Java学院整理
2017/07/12 HTML / CSS
德国黑胶唱片、街头服装及运动鞋网上商店:HHV
2018/08/24 全球购物
用JAVA SOCKET编程,读服务器几个字符,再写入本地显示
2012/11/25 面试题
网络工程专业毕业生推荐信
2013/10/28 职场文书
护士毕业自我鉴定
2014/02/07 职场文书
开学典礼决心书
2014/03/11 职场文书
南京青奥会口号
2014/06/12 职场文书
cf战队宣传语
2015/07/13 职场文书
Go语言基础知识点介绍
2021/07/04 Golang
MySQL中utf8mb4排序规则示例
2021/08/02 MySQL
Python matplotlib安装以及实现简单曲线的绘制
2022/04/26 Python