Electron-vue开发实战3——跨平台的一些兼容措施

前言

前段时间,我用electron-vue开发了一款跨平台(目前支持Mac和Windows)的免费开源的图床上传应用——PicGo,在开发过程当中踩了很多的坑,不只来自应用的业务逻辑自己,也来自electron自己。在开发这个应用过程当中,我学了很多的东西。由于我也是从0开始学习electron,因此不少经历应该也能给初学、想学electron开发的同窗们一些启发和指示。故而写一份Electron的开发实战经历,用最贴近实际工程项目开发的角度来阐述。但愿能帮助到你们。html

预计将会从几篇系列文章或方面来展开:前端

  1. electron-vue入门
  2. Main进程和Renderer进程的简单开发
  3. 引入基于Lodash的JSON database——lowdb
  4. 跨平台的一些兼容措施
  5. 经过CI发布以及更新的方式
  6. ...(想到再写)

说明

PicGo是采用electron-vue开发的,因此若是你会vue,那么跟着一块儿来学习将会比较快。若是你的技术栈是其余的诸如reactangular,那么纯按照本教程虽然在render端(能够理解为页面)的构建可能学习到的东西很少,不过在main端(electron的主进程)应该仍是能学习到相应的知识的。vue

若是以前的文章没阅读的朋友能够先从以前的文章跟着看。react

跨平台的重要性

虽然electron在大多数状况下的跨平台措施已经帮咱们作得很好了。不过须要注意的是,不一样平台必然存在细节上的差别。咱们在书写跨平台应用的时候,若是只在本身书写平台下测试经过的话是不足以说明咱们的应用是健壮的。(固然若是你只想提供给某个平台那另当别论)因此针对不一样的发布平台,就须要作一些兼容性措施。linux

就我本身的感觉而言,macOS平台支持的特性相对比较多,而这里面又不少是独有的,因此不少能在macOS上实现的功能却不必定能在windows上实现。因此对于windows用户而言,在保证总体应用的可用性的状况下,就有可能要相应地作一些妥协和牺牲。不过在windows上的一些操做习惯也能够反过来服务于macOS平台。这点我会在下面给出一个例子详细说明。git

留意不一样平台的独有功能

在开发electron应用的时候,不少时候咱们只注意去查找api名,却容易忽视这个api可以使用的平台。在官方文档里,对于一些独占的api,大多都会有标识标出:github

不过须要注意的是一些未有平台标识的api里的配置项,也有多是某个平台的独占:web

平时开发的过程当中,用到文档的地方仍是须要细细留心,避免后续没必要要的麻烦。windows

跨平台措施入门

上面讲了这么多,该到实例的时候了。在electron应用中,一般来讲renderer进程的东西不须要作太多的跨平台措施——毕竟不论是哪一个平台,都是跑在Chrome里的页面。因此大多数状况下,这个方面的工做会放在main进程里。不过也有例外:api

title-bar的操做区处理

下面是PicGo的windows版:

下面是PicGo的macOS版:

能够发现除了颜色有些区别以外,顶部的title-bar操做栏也有些区别。macOS的程序窗口习惯将窗口的缩放、关闭按钮放在窗口的左上角。而windows程序则相反,它们喜欢放在窗口的右上角。因此为了迎合用户的操做习惯,咱们在开发electron程序的时候也应该注意到这一点。

固然,若是是经过普通的BrowserWindow建立的窗口,那么将会自动拥有常见的macOS、windows的顶部栏,以及默认的样式。

我在这里想说的是若是想要更加美观的界面,一般咱们喜欢「沉浸式」的顶部栏。对于macOS而言,沉浸式的顶部栏就是将顶部栏的三个操做按钮直接「嵌入」窗口主题的左上角。而对于windows而言,只能删去顶部的三个操做按钮,本身用前端的方式来实现了。因此这个地方两个平台的差别性就出来了。

main进程里建立该窗口的时候,主要代码以下:

const createSettingWindow = () => {
  const options = {
    height: 450,
    width: 800,
    show: false, // 当window建立的时候不用打开
    center: true,
    fullscreenable: false,
    resizable: false,
    title: 'PicGo',
    vibrancy: 'ultra-dark', // 窗口模糊的样式
    transparent: true,
    titleBarStyle: 'hidden', // title-bar的样式——隐藏顶部栏的横条,把操做按钮嵌入窗口
    webPreferences: {
      backgroundThrottling: false
    }
  }
  if (process.platform === 'win32') { // 若是平台是win32,也即windows
    options.show = true // 当window建立的时候打开
    options.frame = false // 建立一个frameless窗口,详情:https://electronjs.org/docs/api/frameless-window
    options.backgroundColor = '#3f3c37'
  }
  settingWindow = new BrowserWindow(options)

  settingWindow.loadURL(settingWinURL)

  settingWindow.on('closed', () => {
    settingWindow = null
  })
}
复制代码

主要的工具是经过process.platform来判断不一样的平台。当前可能的值有:

  • 'aix'
  • 'darwin'
  • 'freebsd'
  • 'linux'
  • 'openbsd'
  • 'sunos'
  • 'win32'

在这里咱们基本上只须要关心darwin(macOS)、win32(windows)、linux(Linux)这三个平台便可。注意,因为electron的对于renderer进程的加持,在renderer进程里也能直接使用process.platform来判断当前的操做系统。这是一个很方便的特性。

针对windows平台,因为采用了frameless-window,因此咱们须要手动「绘制」顶部的缩放和关闭按钮,并配上相应的事件来模拟真实的按钮。

<div class="fake-title-bar">
  PicGo - {{ version }}
  <div class="handle-bar" v-if="process.platform === 'win32'"><!-- 若是是windows平台 -->
    <i class="el-icon-minus" @click="minimizeWindow"></i>
    <i class="el-icon-close" @click="closeWindow"></i>
  </div>
</div>
复制代码

相应的事件以下:

minimizeWindow () {
  const window = BrowserWindow.getFocusedWindow()
  window.minimize()
},
closeWindow () {
  const window = BrowserWindow.getFocusedWindow()
  window.close()
},
复制代码

简单来讲就是调用了BrowserWindow的方法来获取当前激活的窗口,而后再对这个窗口进行缩小或关闭的操做。其实也不难对吧!

任务栏图标交互

针对不一样的平台,我对PicGo的任务栏图标交互也有所区别。对于macOS而言,点击顶部菜单栏的时候会弹出一个小窗口:

因为macOS的顶部栏图标能够接受拖拽事件,因此就针对macOS的顶部栏制做了顶部栏图标对应的小窗口。让大部分操做不通过主窗口也能实现。而对于windows而言,没有顶部栏,取而代之的是位于底部栏的右侧的任务栏,一般点击任务栏里的图标就会把应用的主窗口调出来。因此为了迎合不一样平台的操做习惯,我对于这个地方也作了相应的兼容性适配:

tray.on('click', () => { // 不论是顶部栏的图标仍是任务栏的图标都是Tray组件生成的
  if (process.platform === 'darwin') { // 若是是macOS平台
    let img = clipboard.readImage()
    let obj = []
    if (!img.isEmpty()) {
      // 从剪贴板来的图片默认转为png
      const imgUrl = 'data:image/png;base64,' + Buffer.from(img.toPNG(), 'binary').toString('base64')
      obj.push({
        width: img.getSize().width,
        height: img.getSize().height,
        imgUrl
      })
    }
    toggleWindow() // 打开小窗口
    setTimeout(() => {
      window.webContents.send('clipboardFiles', obj)
    }, 0)
  } else {
    window.hide()
    if (settingWindow === null) { // 若是主窗口未建立
      createSettingWindow() // 建立
      settingWindow.show() // 并打开
    } else {
      settingWindow.show() // 若是已存在,打开
      settingWindow.focus() // 并激活
    }
  }
})
复制代码

窗口关闭与应用退出

在windows平台上,一般咱们把应用的窗口都关了以后也就默认把这个应用给退出了。而若是在macOS系统上却不是这样。咱们把应用的窗口关闭了,可是并不是彻底退出这个应用。因此为了实现这个操做习惯,咱们也能够增长一个状况判断:

app.on('window-all-closed', () => { // 当窗口都被关闭了
  if (process.platform !== 'darwin') { // 若是不是macOS
    app.quit() // 应用退出
  }
})
复制代码

总结

本文简要地讲述了electron应用在跨平台开发的时候的一些注意事项。可能不少人会以为奇怪我为啥把这个章节单独拎出来说。不少时候咱们只关注于应用的开发过程,把应用的功能实现是不少状况下的「终极」目标。然而真实状况是,应用的功能实现只是「基本」目标。一个应用要给用户使用的话必然不只要考虑到应用的功能,还必须考虑用户的使用习惯。要站在用户的角度来作应用。而不是作自嗨型的应用。因此这篇文章也但愿可以帮助想要开发electron应用的你。

本文不少都是我在开发PicGo的时候碰到的问题、踩的坑。也许文中简单的几句话背后就是我无数次的查阅和调试。但愿这篇文章可以给你的electron-vue开发带来一些启发。文中相关的代码,你均可以在PicGo的项目仓库里找到,欢迎star~若是本文可以给你带来帮助,那么将是我最开心的地方。若是喜欢,欢迎关注个人博客以及本系列文章的后续进展。

注:文中的图片除未特意说明以外均属于我我的做品,须要转载请私信

相关文章
相关标签/搜索