需求:开发桌面端一体机应用:先把架构搭好就会事半功倍。
新建项目
vue create demo
安装electron
yarn add electron //可以省略 安装electron-builder时会自动安装
添加打包工具
vue add electron-builder
安装后src下会生成background.js文件
package.json也会生成对应的命令
并把background.js作为入口文件
"electron:build": "vue-cli-service electron:build", "electron:serve": "vue-cli-service electron:serve",
打包时遇到的error ERR_ELECTRON_BUILDER_CANNOT_EXECUTE
解决方法
1、
下载 与当前elecron本版一致的 win32-x64 然后放到 参考路径 : C:\Users\Admin/AppData\Local\electron\Cache
2 、
下载 对应的 winCodeSign 解压后 放到 C:\User\Admin/AppData\Local\electron-builder\Cache 没有 winCodeSign 文件夹 自己新建
3、
下载对应的 nsis 和 对应的 nsis-resources 放到 C:\User\Admin/AppData\Local\electron-builder\Cache/nsis 下面
注:
复制错误提示里面的链接下载
比如下面的错 :复制https://github.com/electron/electron/releases/download/v20.0.0/electron-v20.0.0-win32-x64.zip进行下载 然后执行上面1的步骤
即可解决。
PS:这里要注意的是可能有版本相关的问题(我有两个项目,两个项目下载的版本不一样。一个13.6.9一个20)
background.js
'use strict'
import {
app,
protocol,
BrowserWindow,
Menu
} from 'electron'
import {
createProtocol
} from 'vue-cli-plugin-electron-builder/lib'
import installExtension, {
VUEJS_DEVTOOLS
} from 'electron-devtools-installer'
const isDevelopment = process.env.NODE_ENV !== 'production'
// Scheme must be registered before the app is ready
protocol.registerSchemesAsPrivileged([{
scheme: 'app',
privileges: {
secure: true,
standard: true,
supportFetchAPI: true //解决引入外部js时打包后报错Fetch API cannot load app://.ZwCloud2DSDK/ZwWasmJs.wasm.
URL
scheme
is not supported.
}
}])
async function createWindow() {
// Create the browser window.
Menu.setApplicationMenu(null) //隐藏菜单栏
const win = new BrowserWindow({
// width: 1900, //最大宽高 不设置则自适应
// height: 1600,
//fullscreen: true,//默认全屏
show: false,
webPreferences: {
nodeIntegration: process.env.ELECTRON_NODE_INTEGRATION,
contextIsolation: !process.env.ELECTRON_NODE_INTEGRATION
}
})
win.maximize();//窗口最大化
win.show();
// win.webContents.openDevTools()
if (process.env.WEBPACK_DEV_SERVER_URL) {
// Load the url of the dev server if in development mode
await win.loadURL(process.env.WEBPACK_DEV_SERVER_URL)
if (!process.env.IS_TEST) win.webContents.openDevTools() //调试工具
} else {
createProtocol('app')
// Load the index.html when not in development
win.loadURL('app://./index.html')
}
}
// Quit when all windows are closed.
app.on('window-all-closed', () => {
// On macOS it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q
if (process.platform !== 'darwin') {
app.quit()
}
})
//点击关闭
app.on('quit', () => {
app.quit()
})
app.on('activate', () => {
// 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()
})
// 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', async () => {
if (isDevelopment && !process.env.IS_TEST) {
// Install Vue Devtools
try {
await installExtension(VUEJS_DEVTOOLS)
} catch (e) {
console.error('Vue Devtools failed to install:', e.toString())
}
}
createWindow()
})
// Exit cleanly on request from parent process in development mode.
if (isDevelopment) {
if (process.platform === 'win32') {
process.on('message', (data) => {
if (data === 'graceful-exit') {
app.quit()
}
})
} else {
process.on('SIGTERM', () => {
app.quit()
})
}
}
运行 electron:serve 命令就可以启动成功了。
打包运行 electron:build命令
更多配置参考 electron官方文档
自动更新 electron-updater
1、安装依赖 yarn add electron-updater
2、自定义更新的文件 handleUpdate.js
注: 打包完会生成一个latest.yml文件,把这个文件和生成的.exe文件放在服务器上,会自动检测版本
import {
autoUpdater
} from 'electron-updater'
import {
ipcMain,dialog
} from 'electron'
let mainWindow = null;
export function handleUpdate(window, feedUrl) {
mainWindow = window;
let message = {
error: '检查更新出错',
checking: '正在检查更新……',
updateAva: '检测到新版本,正在下载……',
updateNotAva: '现在使用的就是最新版本,不用更新',
};
`autoUpdater.autoDownload = false;` //取消自动下载
//设置更新包的地址
autoUpdater.setFeedURL(feedUrl);
//监听升级失败事件
autoUpdater.on('error', function(error) {
sendUpdateMessage({
cmd: 'error',
message: error
})
});
//监听开始检测更新事件
autoUpdater.on('checking-for-update', function(message) {
sendUpdateMessage({
cmd: 'checking-for-update',
message: message
})
});
//监听发现可用更新事件
autoUpdater.on('update-available', function(message) {
sendUpdateMessage({
cmd: 'update-available',
message: message
})
//新加内容
/** `const options = {
type: 'info',
buttons: ['确定', '取消'],
title: '更新提示',
message: '发现有新版本,是否更新?',
cancelId: 1
}
dialog.showMessageBox(options).then(res => {
if (res.response === 0) {
sendUpdateMessage({
cmd: 'confimUpdate',
message: message
})
autoUpdater.downloadUpdate()
} else {
return;
}
})`*/
});
//监听没有可用更新事件
autoUpdater.on('update-not-available', function(message) {
sendUpdateMessage({
cmd: 'update-not-available',
message: message
})
});
// 更新下载进度事件
autoUpdater.on('download-progress', function(progressObj) {
sendUpdateMessage({
cmd: 'download-progress',
message: progressObj
})
});
//监听下载完成事件
autoUpdater.on('update-downloaded', function(event, releaseNotes, releaseName, releaseDate, updateUrl) {
sendUpdateMessage({
cmd: 'update-downloaded',
message: {
releaseNotes,
releaseName,
releaseDate,
updateUrl
}
})
//退出并安装更新包
//autoUpdater.quitAndInstall();
});
//新增
ipcMain.on("quit-install", (e, arg) => {
autoUpdater.quitAndInstall();
})
//接收渲染进程消息,开始检查更新
ipcMain.on("checkForUpdate", (e, arg) => {
//执行自动更新检查
// sendUpdateMessage({cmd:'checkForUpdate',message:arg})
autoUpdater.checkForUpdates();
})
}
//给渲染进程发送消息
function sendUpdateMessage(text) {
mainWindow.webContents.send('message', text)
}
3、在主进程文件background.js里面引用 handleUpdate.js
`const {
handleUpdate
} = require('./handleUpdate.js') //根据自己路径引入 我是跟background.js同级放的`
if (process.env.WEBPACK_DEV_SERVER_URL) {
await win.loadURL(process.env.WEBPACK_DEV_SERVER_URL)
if (!process.env.IS_TEST) win.webContents.openDevTools() //调试工具
} else {
createProtocol('app')
win.loadURL('app://./index.html')
}
`//检查更新
handleUpdate(win, ".exe文件存放路径")`
在app.vue里面渲染更新进度样式
<template>
<div id="app">
<MainPage></MainPage>
//2023/3/21 根据user要求改为静默式更新 只提示用户安装即可
<!-- <el-dialog title="正在更新新版本,请稍候..." :visible.sync="dialogVisible" width="50%"
:close-on-click-modal="closeOnClickModal" :close-on-press-escape="closeOnPressEscape"
:show-close="showClose" center>
<div style="width:100%;height:50vh;line-height:50vh;text-align:center">
<el-progress :stroke-width="26" :percentage="percentage" :width="strokeWidth" :show-text="true"
type="circle"></el-progress>
</div>
</el-dialog>-->
</div>
</template>
<script>
let ipcRenderer = require("electron").ipcRenderer;
import MainPage from './views/MainPage.vue'
export default {
components: {
MainPage
},
data() {
return {
dialogVisible: false,
closeOnClickModal: false,
closeOnPressEscape: false,
showClose: false,
percentage: 0,
strokeWidth: 400,
timer:0
}
},
created() {
},
unmounted() {
clearInterval(this.timer)
},
mounted() {
let _this = this;
//新增
this.timer = setInterval(() => {
setTimeout(() => {
ipcRenderer.send("checkForUpdate");
}, 1)
}, 60000 * 60 * 2)
//接收主进程版本更新消息
ipcRenderer.on("message", (event, arg) => {
//新增内容
/**`if ("confimUpdate" == arg.cmd) {
_this.dialogVisible = true;
} else if ("download-progress" == arg.cmd) {
console.log(arg.message.percent);
let percent = Math.round(parseFloat(arg.message.percent));
_this.percentage = percent;
} else if ("error" == arg.cmd) {
_this.dialogVisible = false;
_this.$message("更新失败");
}`*/
//2023/03/21改为如下
if ("update-downloaded" == arg.cmd) {
_this.$alert('新版本已经下载完成', '提示信息', {
confirmButtonText: '立即安装',
callback: (action) => {
ipcRenderer.send("quit-install")
}
});
}
});
}
}
</script>
效果图(没有了,不是这个效果了)
新的效果:
自定义安装路径
打包安装默认是直接装在c盘的
新建vue.config.js
module.exports = {
pluginOptions: {
electronBuilder: {
nodeIntegration: true,
builderOptions: {
nsis: {
allowToChangeInstallationDirectory: true, //自定义安装路径
oneClick: false,
},
win: {
publish: [{
provider: "generic",
url: "存放exe文件路径" //更新包地址
}],
},
productName: 'xxx' //项目名
}
},
}
}
ps: 百度时 网上好多资料都是说直接在package.json的build里面
直接加上
nsis: {
allowToChangeInstallationDirectory: true, //自定义安装路径
oneClick: false,
},这并不适用于我的项目,所以新建了vue.config.js。
我这里是更新 所以直接跳过了自定义安装路径的那一步,第一次安装可以自己选择路径。
修改 项目打包安装图标
1、安装依赖 生成图标
yarn add electron-icon-builder
2、在package.json的script中添加命令
"electron:generate-icons": "electron-icon-builder --input=./public/icon.png --output=build --flatten"
3、运行 yarn electron:generate-icons 后会生成一个build文件夹(先要放一张icon.png)
4、删除dist_electron文件夹 重新运行打包命令即可
yarn electron:build
5、图标已更改
笔记是后面写了 没有对比图 本来默认的是electron的图标
最后放一下完整的background.js文件
'use strict'
import {
app,
protocol,
BrowserWindow,
Menu
} from 'electron'
import {
createProtocol
} from 'vue-cli-plugin-electron-builder/lib'
import installExtension, {
VUEJS_DEVTOOLS
} from 'electron-devtools-installer'
const {
handleUpdate
} = require('./handleUpdate.js') //根据自己路径引入
const isDevelopment = process.env.NODE_ENV !== 'production'
const path = require('path')
// Scheme must be registered before the app is ready
protocol.registerSchemesAsPrivileged([{
scheme: 'app',
privileges: {
secure: true,
standard: true
}
}])
async function createWindow() {
// Create the browser window.
Menu.setApplicationMenu(null) //隐藏菜单栏
const win = new BrowserWindow({
// width: 1900, //最大宽高 不设置则自适应
// height: 1600,
//fullscreen: true,//默认全屏
show: false,
icon: path.join(__static, "../public/favicon.ico"), //标题图标
webPreferences: {
nodeIntegration: process.env.ELECTRON_NODE_INTEGRATION,
contextIsolation: !process.env.ELECTRON_NODE_INTEGRATION
}
})
win.maximize();//默认打开窗口最大化
win.show();
// win.webContents.openDevTools()
if (process.env.WEBPACK_DEV_SERVER_URL) {
// Load the url of the dev server if in development mode
await win.loadURL(process.env.WEBPACK_DEV_SERVER_URL)
if (!process.env.IS_TEST) win.webContents.openDevTools() //调试工具
} else {
createProtocol('app')
// Load the index.html when not in development
win.loadURL('app://./index.html')
}
//检查更新
handleUpdate(win, ".exe文件存放路径 和vue.config.js文件里的一致")
}
// Quit when all windows are closed.
app.on('window-all-closed', () => {
// On macOS it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q
if (process.platform !== 'darwin') {
app.quit()
}
})
app.on('quit', () => {
app.quit()
})
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
app.on('ready', async () => {
if (isDevelopment && !process.env.IS_TEST) {
// Install Vue Devtools
try {
await installExtension(VUEJS_DEVTOOLS)
} catch (e) {
console.error('Vue Devtools failed to install:', e.toString())
}
}
createWindow()
})
// Exit cleanly on request from parent process in development mode.
if (isDevelopment) {
if (process.platform === 'win32') {
process.on('message', (data) => {
if (data === 'graceful-exit') {
app.quit()
}
})
} else {
process.on('SIGTERM', () => {
app.quit()
})
}
}
项目总体目录结构
安装依赖卡的解决办法:npm config set electron_mirror https://npm.taobao.org/mirrors/electron/
后来搞了个入门案例 但是没有做更新 实现方式 electron+vite+vue3+pinia 跟上面有出入 不太影响 适合新人学习使用
项目下载