标签 desk app 下的文章

Electronhttps://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" // 图标名称
    }
  }
  ...
}