使用 JavaScript、HTML 和 CSS 创建桌面APP Electron框架
Electron: https://www.electronjs.org/docs
electron-builder:打包工具
项目github地址:
https://github.com/electron/electron
https://github.com/electron/electron-quick-start
Electron是一个使用 JavaScript、HTML 和 CSS 构建桌面应用程序的框架。 嵌入 Chromium 和 Node.js 到 二进制的 Electron 允许您保持一个 JavaScript 代码代码库并创建 在Windows上运行的跨平台应用 macOS和Linux——不需要本地开发 经验。
electron 桌面开发工具 与用户操作系统和node的集成方法文档
https://www.electronjs.org/zh/docs/latest/tutorial/examples
一些开发经验:
创建 BrowserWindow 窗口
const {app, BrowserWindow} = require('electron')
let remoteURL, debug
debug = !app.isPackaged
if (debug) {
remoteURL = 'https://www.xxx.com/notifyDeskApp/login.html';
//忽略证书的检测
app.commandLine.appendSwitch('ignore-certificate-errors')
} else {
remoteURL = 'https://www.xxx.com/notifyDeskApp/login.html';
}
let trayIcon = path.join(__dirname, "icon", "notify-logo.ico");
let mainWindow, logined, quit
function createWindow () {
// Create the browser window.
mainWindow = new BrowserWindow({
width: 400,
height: 300,
fullscreenable: false,
maximizable: false,
icon: trayIcon,
webPreferences: {
preload: path.join(__dirname, 'preload.js')
}
})
mainWindow.setAppDetails({
appIconPath: trayIcon,
})
// and load the index.html of the app.
mainWindow.loadURL(remoteURL)
// mainWindow.loadFile('index.html')
mainWindow.on('minimize',(e)=>{
if (logined) {
mainWindow.hide();
}
})
mainWindow.on('close',(e)=>{
if (logined && !quit) {
e.preventDefault()
mainWindow.hide();
} else {
app.quit()
}
})
}
app.whenReady().then(() => {
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()
})
})显示隐藏窗口
mainWindow.hide();
mainWindow.restore()渲染进程与主进程通信
创建窗口的时候配置 preload.js, main.js
mainWindow = new BrowserWindow({
width: 400,
height: 300,
fullscreenable: false,
maximizable: false,
icon: trayIcon,
webPreferences: {
preload: path.join(__dirname, 'preload.js')
}
})窗口渲染页面与preload通过window事件,来传递事件消息
窗口加载的网页中的js事件
//客户端登录事件:字段名称说明是否可选类型默认值detail表示该事件中需要被传递的数据,在 EventListener 获取。可选Anynullbubbles表示该事件是否冒泡。可选Booleanfalsecancelable表示该事件能否被取消。可选Booleanfalse
let eventInit = {bubbles: false, cancelable: false, detail: {token: token, trueName: trueName}}
let loginedEvent = new CustomEvent('logined', eventInit)
window.dispatchEvent(loginedEvent)preload.js
const {ipcRenderer} = require('electron');
window.addEventListener('logined', (e) => {
ipcRenderer.send('logined', e.detail);
})
window.addEventListener('logout', (e) => {
ipcRenderer.send('logout', e.detail);
})
window.addEventListener('open-url', (e) => {
ipcRenderer.send('open-url', e.detail);
})
window.addEventListener('exit', (e) => {
ipcRenderer.send('exit', e.detail);
})main.js
const {app,shell} = require('electron')
ipcMain.on('logined', (e, data) => {
logined = true
mainWindow.hide();
})
ipcMain.on('open-url', (e, data) => {
console.log(data)
shell.openExternal(data.url);
})
ipcMain.on('logout', (e, data) => {
logined = false
mainWindow.restore()
})
ipcMain.on('exit', (e, data) => {
logined = false
quit = true
app.quit()
})托盘
const {app, BrowserWindow, Menu, Tray , ipcMain, shell} = require('electron')
let tray = null
const showMainWindow = (menuItem, browserWindow, event) => {
if (mainWindow) {
mainWindow.restore()
mainWindow.show()
mainWindow.focus()
}
}
const appExit = (menuItem, browserWindow, event) => {
quit = true
app.quit()
}
const openDevTools = (menuItem, browserWindow, event) => {
// Open the DevTools.
if (mainWindow) mainWindow.webContents.openDevTools({ mode: 'detach' })
}
let firstrun = process.argv[1] == '--squirrel-firstrun'
const setAutoOpen = function () {
let autoOpenSet = app.getLoginItemSettings()
let option = {
openAtLogin: !autoOpenSet.openAtLogin, // Boolean 在登录时启动应用
openAsHidden: !autoOpenSet.openAsHidden, // Boolean (可选) mac 表示以隐藏的方式启动应用。~~~~
}
if (!debug) app.setLoginItemSettings(option)
tray.displayBalloon({iconType: 'info', title: '操作提示', content: '开机自启动: ' + (option.openAtLogin ? '已开启' : '已关闭')})
}
app.whenReady().then(() => {
//托盘
tray = new Tray(trayIcon)
const contextMenu = Menu.buildFromTemplate([
{ label: '显示主窗口', type: 'normal', click: showMainWindow },
{ label: '开机自启动', type: 'normal', click: setAutoOpen, visible: !debug },
{ label: '调试窗口', type: 'normal', click: openDevTools, visible: debug },
{ label: '退出客户端', type: 'normal', click: appExit },
])
tray.setToolTip(app.name)
tray.setContextMenu(contextMenu)
})开机自启动
app.setLoginItemSettings({
openAtLogin: true, // Boolean 在登录时启动应用
openAsHidden: true, // Boolean (可选) mac 表示以隐藏的方式启动应用。~~~~
})开发与正式环境判断: 打包后 app.isPackaged 为 true
debug = !app.isPackaged使用系统默认的浏览器打开一个网页,而不是客户端新开一个窗口
const {shell} = require('electron')
shell.openExternal(data.url);只允许开一个程序
const gotTheLock = app.requestSingleInstanceLock()
if (!gotTheLock) {
return app.quit()
}修改桌面通知时的程序标题
app.setAppUserModelId('myapp name')electron-builder:配置参考 (electron-vue, package.json)
{
...
"build": { // electron-builder配置
"productName":"xxxx",//项目名 这也是生成的exe文件的前缀名
"appId": "xxxxx",//包名
"copyright":"xxxx",//版权 信息
"compression": "store", // "store" | "normal"| "maximum" 打包压缩情况(store 相对较快),store 39749kb, maximum 39186kb
"directories": {
"output": "build" // 输出文件夹
},
"asar": false, // asar打包
"extraResources": { // 拷贝dll等静态文件到指定位置
"from": "./app-update.yml",
"to": "./b.txt"
},
"win": {
"icon": "xxx/icon.ico"//图标路径,
"extraResources": { // 拷贝dll等静态文件到指定位置(用于某个系统配置)
"from": "./app-update.yml",
"to": "./b.txt"
}
},
"nsis": {
"oneClick": false, // 一键安装
"guid": "xxxx", //注册表名字,不推荐修改
"perMachine": true, // 是否开启安装时权限限制(此电脑或当前用户)
"allowElevation": true, // 允许请求提升。 如果为false,则用户必须使用提升的权限重新启动安装程序。
"allowToChangeInstallationDirectory": true, // 允许修改安装目录
"installerIcon": "./build/icons/aaa.ico", // 安装图标
"uninstallerIcon": "./build/icons/bbb.ico", //卸载图标
"installerHeaderIcon": "./build/icons/aaa.ico", // 安装时头部图标
"createDesktopShortcut": true, // 创建桌面图标
"createStartMenuShortcut": true, // 创建开始菜单图标
"shortcutName": "xxxx" // 图标名称
}
}
...
}