开发环境
本文使用环境node12.14.1+electron10.1.5+electron-builder22.9.1+electron-updater4.3.5;
操作过程
一、新建和启动项目
1. 直接使用官网示例,先克隆示例项目的仓库,然后进入该仓库;
# 克隆示例项目的仓库
$ git clone https://github.com/electron/electron-quick-start
# 进入这个仓库
$ cd electron-quick-start
2. 安装项目依赖,安装时候会比较慢,经常安装未成功,建议先执行“npm config set registry https://registry.npm.taobao.org/”再安装依赖;
# 安装依赖
$ npm install
3. 启动项目,可正常运行显示页面,即表示新建成功。
# 运行
$ npm start
二、打包和升级配置
1. 本文使用electron-builder方式打包和electron-updater自动升级,先安装依赖;
# 安装electron-builder
npm install electron-builder --save-dev
# 安装electron-updater
npm install electron-updater --save
2. 在package.json做如下配置;
1)“publish”用于配置升级的参数,URL为升级包地址;
2)“output”为打包的路径;
3)“nsis”为安装过程的参数,增加安装体验感;注意这里引入了icon.ico图片,记得新建文件夹build并放入相应的图片;
3. 修改主进程“main.js”代码:
1)feedUrl是升级包放置的路径地址;
2)updateHandle是更新函数,放置了更新过程的方法(官方都有详细解释)和发送信息;
3)使用template来使菜单中文化,便于使用;
// Modules to control application life and create native browser window
const { app, BrowserWindow, Menu, ipcMain } = require('electron')
const electron = require('electron')
const { autoUpdater } = require('electron-updater')
const path = require('path')
function createWindow() {
// Create the browser window.
const mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
nodeIntegration: true
}
})
// and load the index.html of the app.
mainWindow.loadFile('index.html')
// Open the DevTools.
mainWindow.webContents.openDevTools()
let feedUrl = "http://192.168.0.107/electron-update/eqs";
//检测版本更新
updateHandle(mainWindow, feedUrl);
}
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.whenReady().then(() => {
const menu = Menu.buildFromTemplate(template)
Menu.setApplicationMenu(menu) // 设置菜单部分
createWindow()
app.on('activate', function() {
// On macOS it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
})
// Quit when all windows are closed, except on macOS. There, it's common
// for applications and their menu bar to stay active until the user quits
// explicitly with Cmd + Q.
app.on('window-all-closed', function() {
if (process.platform !== 'darwin') app.quit()
})
// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.
// 更新函数
function updateHandle(window, feedUrl) {
mainWindow = window;
let message = {
error: '检查更新出错',
checking: '正在检查更新……',
updateAva: '检测到新版本,正在下载……',
updateNotAva: '现在使用的就是最新版本,不用更新',
};
//设置更新包的地址
autoUpdater.setFeedURL(feedUrl);
//监听升级失败事件
autoUpdater.on('error', function(error) {
sendUpdateMessage(mainWindow, {
cmd: 'error',
message: error
})
});
//监听开始检测更新事件
autoUpdater.on('checking-for-update', function(message) {
sendUpdateMessage(mainWindow, {
cmd: 'checking-for-update',
message: message
})
});
//监听发现可用更新事件
autoUpdater.on('update-available', function(message) {
sendUpdateMessage(mainWindow, {
cmd: 'update-available',
message: message
})
});
//监听没有可用更新事件
autoUpdater.on('update-not-available', function(message) {
sendUpdateMessage(mainWindow, {
cmd: 'update-not-available',
message: message
})
});
// 更新下载进度事件
autoUpdater.on('download-progress', function(progressObj) {
sendUpdateMessage(mainWindow, {
cmd: 'download-progress',
message: progressObj
})
});
//监听下载完成事件
autoUpdater.on('update-downloaded', function(event, releaseNotes, releaseName, releaseDate, updateUrl) {
sendUpdateMessage(mainWindow, {
cmd: 'update-downloaded',
message: {
releaseNotes,
releaseName,
releaseDate,
updateUrl
}
})
//退出并安装更新包
autoUpdater.quitAndInstall();
});
//接收渲染进程消息,开始检查更新
ipcMain.on("checkForUpdate", (e, arg) => {
//执行自动更新检查
// sendUpdateMessage(mainWindow, {cmd:'checkForUpdate',message:arg})
autoUpdater.checkForUpdates();
})
}
//给渲染进程发送消息
function sendUpdateMessage(mainWindow, text) {
mainWindow.webContents.send('message', text)
}
/**
* 注册键盘快捷键
* 其中:label: '切换开发者工具',这个可以在发布时注释掉
*/
let template = [{
label: 'Edit ( 操作 )',
submenu: [{
label: 'Copy ( 复制 )',
accelerator: 'CmdOrCtrl+C',
role: 'copy'
}, {
label: 'Paste ( 粘贴 )',
accelerator: 'CmdOrCtrl+V',
role: 'paste'
}, {
label: 'Reload ( 重新加载 )',
accelerator: 'CmdOrCtrl+R',
click: function(item, focusedWindow) {
if (focusedWindow) {
// on reload, start fresh and close any old
// open secondary windows
if (focusedWindow.id === 1) {
BrowserWindow.getAllWindows().forEach(function(win) {
if (win.id > 1) {
win.close()
}
})
}
focusedWindow.reload()
}
}
}]
},
{
label: 'Window ( 窗口 )',
role: 'window',
submenu: [{
label: 'Minimize ( 最小化 )',
accelerator: 'CmdOrCtrl+M',
role: 'minimize'
}, {
label: 'Close ( 关闭 )',
accelerator: 'CmdOrCtrl+W',
role: 'close'
}, {
label: '切换开发者工具',
accelerator: (function() {
if (process.platform === 'darwin') {
return 'Alt+Command+I'
} else {
return 'Ctrl+Shift+I'
}
})(),
click: function(item, focusedWindow) {
if (focusedWindow) {
focusedWindow.toggleDevTools()
}
}
}, {
type: 'separator'
}]
},
{
label: 'Help ( 帮助 ) ',
role: 'help',
submenu: [{
label: 'FeedBack ( 意见反馈 )',
click: function() {
electron.shell.openExternal('https://forum.iptchain.net')
}
}]
}
]
4. 修改首页“index.html” ,增加发送检测升级功能:
1)增加“sendMessage.js”,用来检测更新;该实例是打开或重新加载就检测更新,可自行根据实际情况修改检测的方式;
window.onload = function() {
let ipcRenderer = require("electron").ipcRenderer;
//接收主进程版本更新消息
ipcRenderer.on("message", (event, arg) => {
console.log(arg);
if ("update-available" == arg.cmd) {
//显示升级对话框
console.log('update-available');
} else if ("download-progress" == arg.cmd) {
//更新升级进度
console.log(arg.message.percent);
} else if ("error" == arg.cmd) {
console.log('更新失败');
}
// }
});
//20秒后开始检测新版本
let timeOut = window.setTimeout(() => {
ipcRenderer.send("checkForUpdate");
}, 20000);
clearTimeout;
}
2)“index.html”作如下修改,加入引入上面js的代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'">
<meta http-equiv="X-Content-Security-Policy" content="default-src 'self'; script-src 'self'">
<title>Hello World!</title>
</head>
<body>
<h1>Hello World2!</h1>
We are using Node.js <span id="node-version"></span>,
Chromium <span id="chrome-version"></span>,
and Electron <span id="electron-version"></span>.
<!-- You can also require other files to run in this process -->
<script src="./renderer.js"></script>
<script src="utils/sendMessage.js"></script>
</body>
</html>
三、打包程序并演示升级过程
1. 执行命令“npm run build”,第一次在build的时候会因为下载文件而超时,可根据提示的网址下载相应的文件并进行手工安装;
1)下载“electron-v10.1.3-win32-x64”时(后面升级到了10.1.5,操作一样),可根据显示的(图1)url直接下载(并下载相应的SHASUMS256.txt),然后将“SHASUMS256.txt”修改为“SHASUMS256.txt-10.1.3”,并把这两个文件拷入图2位置;
2)下载“winCodeSign-2.6.0”时,可根据显示的(图1)url直接下载,然后把文件拷入图2位置;
3)下载“nsis-3.0.4.1”时,可根据显示的(图1)url直接下载,然后把文件拷入图2位置;
2. 再次执行命令“npm run build”,等待执行完毕,在release文件下生成exe文件,然后安装“test-demo Setup 1.0.0.exe”版本;
3. 修改“packgage.json”的属性“version”为2.0.0,然后执行命令“npm run build”,生成2.0安装版本;
4. 把升级文件“latest.yml”和“test-demo Setup 2.0.0.exe”放到设置的升级路径下;
5. 每次打开程序或者点击菜单的“Reload”,过20S后都会检测是否有升级包,并根据实际情况返回信息;
6. 如果升级成功会退出程序并跳到安装新程序的窗口,一步步确定即可。