electron-updater使用指南
基础
检测是否最新版
autoUpdater.checkForUpdates()
下载最新版
autoUpdater.downloadUpdate()
项目使用
update.js
javascript
const { ipcMain } = require('electron')
const { autoUpdater } = require('electron-updater')
const path = require("path")
// 更新地址,该地址下放的是安装包和latest.yml
const updateURL = 'https://jkcgy.obs.cn-south-1.myhuaweicloud.com/desktop/'
const message = {
error: '软件更新异常,请重试',
checking: '正在检查更新',
updateAva: '检测到新版本,准备下载',
updateDown: '软件下载中,请耐心等待',
updateSet: '下载完成,准备安装',
updateNotAva: '已经是最新版本',
}
//软件版本更新
ipcMain.handle('on-soft-update', (e) => {
autoUpdater.checkForUpdates()
})
ipcMain.on("updateDesktop", () => {
console.log("checkForUpdates");
autoUpdater.checkForUpdates()
// console.log("downloadUpdate");
})
ipcMain.on("updateDesktopping", () => {
autoUpdater.downloadUpdate()
})
// 检测更新,在你想要检查更新的时候执行,renderer事件触发后的操作自行编写
function handleUpdate(mainWindow, callback) {
// 设置是否自动下载,默认是true,当点击检测到新版本时,会自动下载安装包,所以设置为false
autoUpdater.autoDownload = false
// 如果安装包下载好了,当应用退出后是否自动安装更新
autoUpdater.autoInstallOnAppQuit = false
if (process.env.NODE_ENV == "development") {
autoUpdater.updateConfigPath = path.join(__dirname, "../../aaa/app-update.yml");
}
// 设置版本更新服务器地址
autoUpdater.setFeedURL(updateURL)
// 更新发生错误时触发
autoUpdater.on('error', function () {
console.log(" 更新发生错误时触发",);
sendUpdateMessage(message.error, "error")
})
// 开始检查更新事件
autoUpdater.on('checking-for-update', function () {
console.log(" 开始检查更新事件",);
sendUpdateMessage(message.checking, "checking")
})
// 没有可更新版本
autoUpdater.on('update-not-available', function (info) {
console.log(" 开始检查更新事件",);
sendUpdateMessage(message.updateNotAva, "updateNotAva")
})
// 发现可更新版本
autoUpdater.on('update-available', function (info) {
console.log(" 发现可更新版本",);
// autoUpdater.downloadUpdate()
sendUpdateMessage(message.updateAva, "updateAva")
})
// 更新下载进度事件
autoUpdater.on('download-progress', function (progressObj) {
console.log(" 更新下载进度事件",);
sendUpdateMessage(message.updateDown, "updateDown")
mainWindow.webContents.send('on-soft-download', progressObj.percent)
})
// 下载监听
autoUpdater.on(
'update-downloaded',
function (event, releaseNotes, releaseName, releaseDate, updateUrl, quitAndUpdate) {
mainWindow.webContents.send('on-soft-download', 100)
sendUpdateMessage(message.updateSet, "updateSet")
//3秒后更新
setTimeout(() => {
autoUpdater.quitAndInstall()
}, 3000)
}
)
// 向渲染进程发送消息
function sendUpdateMessage(text, type) {
mainWindow.webContents.send('on-soft-message', text, type)
}
}
module.exports = {
handleUpdate,
}
然后再 main.js 调用即可
javascript
mainWindow.on('ready-to-show', () => {
mainWindow.show();
updater.handleUpdate(mainWindow)
if (!ipc) ipc = new IPC(mainWindow);
mainWindow.openDevTools();
// if(!callWindowIpc) callWindowIpc = new CallWindowIpc(mainInstance);
});
main.js 所有代码
javascript
const { app, BrowserWindow, ipcMain, globalShortcut, Tray, Menu } = require('electron');
const Store = require('electron-store');
const CaptureView = require('./electron-captureview/main/captureview').default;
const path = require('path');
const url = require('url');
const TimMain = require('im_electron_sdk/dist/main');
const { SDK_APP_ID, GET_FILE_INFO_CALLBACK, SCREENSHOTMAC } = require('./const/const');
const IPC = require('./ipc');
const CallWindowIpc = require('./callWindowIpc');
const child_process = require('child_process')
const fs = require('fs')
const updater= require("./update")
const store = new Store();
Store.initRenderer();
const { autoUpdater } = require('electron-updater')
process.env['ELECTRON_DISABLE_SECURITY_WARNINGS'] = 'true';
let callWindowIpc;
let ipc;
let mainInstance;
let catchedSdkAppId;
const settingConfig = store.get('setting-config');
const sdkappid = catchedSdkAppId = settingConfig?.sdkappId ?? SDK_APP_ID;
let tray = null // 在外面创建tray变量,防止被自动删除,导致图标自动消失
const initTimMain = (appid) => {
mainInstance = new TimMain({
sdkappid: Number(appid)
});
}
initTimMain(sdkappid);
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
ipcMain.handle('re-create-main-instance', async (event, newSdkAppid) => {
console.log("************ re-create-main-instance", newSdkAppid)
mainInstance.setSDKAPPID(newSdkAppid)
return
})
// This allows TypeScript to pick up the magic constant that's auto-generated by Forge's Webpack
// plugin that tells the Electron app where to look for the Webpack-bundled app code (depending on
// whether you're running in development or production).
// declare const MAIN_WINDOW_WEBPACK_ENTRY: string;
// Handle creating/removing shortcuts on Windows when installing/uninstalling.
// app.on('window-all-closed', function () {
// if (process.platform !== 'darwin') app.quit()
// })
const createWindow = () => {
// Create the browser window.
const mainWindow = new BrowserWindow({
height: 628,
width: 975,
minWidth: 975,
minHeight: 628,
// show:false,
icon: path.resolve(__dirname, "../../icon/logo.png"),
frame: false,
webPreferences: {
webSecurity: true,
nodeIntegration: true,
nodeIntegrationInWorker: true,
enableRemoteModule: true,
contextIsolation: false,
}
});
mainInstance.enable(mainWindow.webContents)
global.WIN = mainWindow;
mainWindow.on('ready-to-show', () => {
mainWindow.show();
updater.handleUpdate(mainWindow)
if (!ipc) ipc = new IPC(mainWindow);
mainWindow.openDevTools();
// if(!callWindowIpc) callWindowIpc = new CallWindowIpc(mainInstance);
});
mainWindow.on('close', (e) => {
// mainWindow.webContents.send('updateHistoryMessage');
// setTimeout(() => {
// app.exit();
// }, 30);
e.preventDefault(); // 阻止退出程序
mainWindow.setSkipTaskbar(true) // 取消任务栏显示
mainWindow.hide(); // 隐藏主程序窗口
});
console.log('======process env======', process.env?.NODE_ENV);
if (process.env?.NODE_ENV?.trim() === 'development') {
mainWindow.loadURL(`http://localhost:3000`);
mainWindow.webContents.openDevTools();
} else {
mainWindow.loadURL(
url.format({
pathname: path.join(__dirname, '../../bundle/index.html'),
protocol: 'file:',
slashes: true
})
);
}
// 创建任务栏图标
tray = new Tray(path.join(__dirname, "../../icon/logo.png"))
// 自定义托盘图标的内容菜单
const contextMenu = Menu.buildFromTemplate([
{
// 点击退出菜单退出程序
label: '退出', click: function () {
mainWindow.webContents.send('updateHistoryMessage');
setTimeout(() => {
app.exit();
}, 30);
// mainWindow.destroy()
}
}
])
tray.setToolTip('君凯智管') // 设置鼠标指针在托盘图标上悬停时显示的文本
tray.setContextMenu(contextMenu) // 设置图标的内容菜单
// 点击托盘图标,显示主窗口
tray.on("click", () => {
mainWindow.show();
mainWindow.setSkipTaskbar(false) // 取消任务栏显示
})
// const capture = new CaptureView({
// devTools: false,
// Mosaic: false,
// Text: false,
// // onShow: () => {
// // console.log('start screenshot');
// // },
// onClose: () => {
// const png = clipboard.readImage().toBitmap();
// const fileExample = new File([png], 'xxx.png', { type: 'image/jpeg' });
// console.log('结束截图', fileExample);
// },
// onShowByShortCut: () => {
// console.log('shortcut key to start screenshot')
// }
// });
// capture.setMultiScreen(true);
// capture.updateShortCutKey('shift+option+c');
globalShortcut.register('Shift+CommandOrControl+C', function () {
console.log("i am shortcut~~~~~~~~~");
const newdate = new Date();
const date = newdate.toISOString().replaceAll(":", "");
// console.log(date.toISOString());
if (process.platform == "darwin") {
let ex = "screencapture -i ~/desktop/screenshot" + date + ".png"
child_process.exec(`screencapture -i ~/desktop/screenshot` + date + `.png`, (error, stdout, stderr) => {
if (!error) {
var _img = fs.readFileSync(process.env.HOME + "/desktop/screenshot" + date + ".png");
// console.log(_img);
mainWindow.webContents.send(GET_FILE_INFO_CALLBACK, {
triggerType: SCREENSHOTMAC,
data: { _img: _img, date }
})
}
});
} else {
let url = path.resolve(__dirname, "../Snipaste-2.8.2-Beta-x64/Snipaste.exe");
let command = url + " snip -o C:\\Users\\Public\\Desktop\\screenshot" + date + ".png";
// console.log(command);
var id = setInterval(dealFile, 300);
child_process.exec(command, async (error, stdout, stderr) => {
if (!error) {
console.log("done capture");
}
})
function dealFile() {
try {
var _img = fs.readFileSync("C:\\Users\\Public\\Desktop\\screenshot" + date + ".png");
clearInterval(id);
console.log("file exists");
console.log(_img);
event.reply(GET_FILE_INFO_CALLBACK, {
triggerType: SCREENSHOTMAC,
data: { _img: _img, date }
})
} catch (err) {
if (err.code == 'ENOENT') {
// console.log("file doesn't exist yet")
} else {
throw err;
}
}
}
}
})
// mainWindow.loadURL(`http://localhost:3000`);
// mainWindow.webContents.openDevTools();
};
// 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.on('ready', createWindow);
Object.defineProperty(app, 'isPackaged', {
get() {
return true;
}
});
// 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', () => {
console.log('all-window-closed');
if (process.platform !== 'darwin') {
app.exit();
}
});
app.on('activate', () => {
// On OS X 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();
}
});
// 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 import them here.
常见错误指南
Electron更新报错-Skip checkForUpdates because application is not packed and dev update config is not forced
原因是在本地启动的不是安装导致的,在根中配置即可
javascript
const { app, BrowserWindow, ipcMain, globalShortcut, Tray, Menu } = require('electron');
Object.defineProperty(app, 'isPackaged', {
get() {
return true;
}
});
Electron更新报错-
必须设置这个内容
javascript
"publish": [
{
"provider": "generic",
"channel": "latest",
"url": "https://jkcgy.obs.cn-south-1.myhuaweicloud.com/desktop/%E5%90%9B%E5%87%AF%E6%99%BA%E7%AE%A1%20Setup%200.0.2.exe"
}
],
Electron更新报错-UnhandledPromiseRejectionWarning: Error: ENOENT: no such file or directory, open '****\app-update.yml'
找不到app-update.yml 文件,可以去打包路径中的 dist\win-unpacked\resources 复制,然后通过修改 autoUpdater.updateConfigPath 路径
该路径是自定义的路径,自己在 dist\win-unpacked\resources 复制的
javascript
const { autoUpdater } = require('electron-updater')
autoUpdater.updateConfigPath = path.join(__dirname, "../../aaa/app-update.yml");
Electron更新报错-找不到latest.yml 文件
找不到latest.yml文件 可以去dist复制
这里跟配置的 autoUpdater.setFeedURL 路径有关系
javascript
const { autoUpdater } = require('electron-updater')
const updateURL = 'https://jkcgy.obs.cn-south-1.myhuaweicloud.com/desktop/'
// 设置版本更新服务器地址
autoUpdater.setFeedURL(updateURL)