上一期咱们介绍了如何设置伪协定,并通过伪协定链接拉起客户端,其实伪协定还有很多场景的,比方百度网盘或者迅雷,点击网页上的链接进行下载,或者点击链接拉起客户端后关上某个页面,其实这都是能够用伪协定链接实现的,链接中的参数就和网页的参数没啥区别,本期就介绍如何获取伪协定链接中的参数。

实现目标

  1. 软件敞开时通过伪协定拉起软件获取该伪协定链接。
  2. 软件启动时通过伪协定拉起软件获取该伪协定链接。
  3. 通过伪协定传入一个图片链接和router path门路,跳转该门路,并下载图片本地加载显示。

伪协定获取差别

上一章咱们介绍了伪协定是怎么启动客户端的,即:

  1. Windows是通过注册表写入伪协定,调用利用启动exe和%1启动客户端的。
  2. Mac是通过软件包中的info.plist文件设置启动客户端的。

这两者的启动形式不同,故获取形式也是不同的,咱们来看一下通过伪协定的启动流程吧:

Windows伪协定启解决

  1. 首先软件处于敞开状态的话,咱们在浏览器上关上伪协定链接,会注册表下来找对应的伪协定,启动exe并传入伪协定链接(%1),也就是咱们实际上关上的是xxx.exe vue-cli-electron://xxxx
    此时能够间接通过process.argv来获取这个伪协定链接,之前说了process.argv这个是数组,外面是Electron的启动参数,如果咱们是通过伪协定拉起软件的话,数组最初一项就是咱们的伪协定链接
process.argv:[  xxx.exe,  .....,  vue-cli-electron://xxxx]

那么此时伪协定为process.argv[process.argv.length - 1]

  1. 软件处于开启状态的话,咱们能够通过app的second-instance事件来获取这个argv,second-instance当第二个实例被执行并且调用app.requestSingleInstanceLock()时触发的,解释一下就是咱们的软件正在运行,伪协定触发关上exe,咱们主过程中调用了app.requestSingleInstanceLock()的话,second-instance就会触发,直观体现为伪协定关上软件,触发second-instance事件,咱们能够在这个外面拿到argv。
import { app } from 'electron'import global from '../config/global'const gotTheLock = app.requestSingleInstanceLock()export default function() {  // 点击图标启动时检测窗口是否存在,存在则关上  if (!gotTheLock) {    app.quit()  } else {    app.on('second-instance', (event, argv) => {      console.log(argv[argv.length - 1])      const win = global.sharedObject.win      if (win) {        if (win.isMinimized()) win.restore()        if (win.isVisible()) {          win.focus()        } else {          win.show()          win.setSkipTaskbar(false)        }      }    })  }}

Mac伪协定解决

Mac软件的启动就没啥参数可带的了,所以process.argv这个货色没啥用,那么如何获取呢,看看官网形容链接:

在 macOS 上, 当用户尝试在 Finder 中关上您的应用程序的第二个实例时, 零碎会通过收回 open-file 和 open-url 事件来主动强制执行单个实例,。 然而当用户在命令行中启动应用程序时, 零碎的单实例机制将被绕过, 您必须手动调用此办法来确保单实例。

故咱们能够通过open-url来获取咱们的伪协定链接,注:Mac零碎无论软件启动或没启动都是通过open-url来拿取的

app.on('open-url', (_event, urlStr) => {  console.log(urlStr)})

具体实现

winSingle

import { app } from 'electron'import global from '../config/global'const gotTheLock = app.requestSingleInstanceLock()export default function() {  // 点击图标启动时检测窗口是否存在,存在则关上  if (!gotTheLock) {    app.quit()  } else {    // 这里是软件在启动时,伪协定关上触发的    app.on('second-instance', (event, argv) => {      console.log(argv)      const win = global.sharedObject.win      // 间接把伪协定链接发送给渲染过程      win.webContents.send('renderer-scheme', argv[argv.length - 1])      if (win) {        if (win.isMinimized()) win.restore()        if (win.isVisible()) {          win.focus()        } else {          win.show()          win.setSkipTaskbar(false)        }      }    })  }}

主过程

import winSingle from './services/winSingle'winSingle()app.isReady() ? onAppReady() : app.on('ready', onAppReady)async function onAppReady() {  if (!process.env.WEBPACK_DEV_SERVER_URL) {    createProtocol('app')  }  // 这里怎么解决看集体爱好,你能够启动时就依据scheme关上对应的窗口,或者是在窗口加载实现后发个告诉给渲染过程,渲染过程进行重定向。  // if (process.argv.length > (app.isPackaged ? 1 : 2)) {  //   const scheme = process.argv[process.argv.length - 1]  //   解决scheme省略  //   initWindow('#xxxpath')  // } else {  //   initWindow('')  // }  initWindow('')  // 这里的逻辑是win敞开通过伪协定拉起软件,因为咱们要告诉渲染过程,所以得在渲染过程加载结束后告诉  win.webContents.once('did-finish-load', () => {    // 间接关上软件的话开发环境的启动参数为2,安装包为1,大于这个数的话阐明是通过伪协定拉起软件的    if (process.argv.length > (app.isPackaged ? 1 : 2)) {      // 咱们这里被动触发'second-instance',传入process.argv,在那边对立解决了      app.emit('second-instance', null, process.argv)    }  })}// mac伪协定链接就是urlStrapp.on('open-url', (_event, urlStr) => {  console.log(urlStr)  if (win) {    // 这里是mac软件关上时应用伪协定关上软件    win.webContents.send('renderer-scheme', urlStr)    if (win.isMinimized()) win.restore()    if (win.isVisible()) {      win.focus()    } else {      win.show()      win.setSkipTaskbar(false)    }  } else {    // 这里是mac软件敞开时应用伪协定关上软件,如果你两头process.argv没有扭转能够这样写,会持续走下面win的did-finish-load的流程    // 如果有扭转的话老老实实写个did-finish-load进行win.webContents.send('renderer-scheme', urlStr)推送    process.argv.push(urlStr)  }})

我这里是主过程获取到伪协定链接,而后发告诉给渲染过程的,一些不懂的中央请看下面正文解释,简略说一下就是:

  • open-url里解决Mac的伪协定,依据win的值来辨别软件是处于开启还是敞开。
  • ready里拿到伪协定的是软件处于敞开状态的,second-instance里软件是启动状态。
  • Mac软件敞开状态启动的话,argv里只有启动门路一项,不会走argv.length > 1这边的逻辑的,然而open-url会比ready先触发,咱们能够在这个外面进行手动argv.push(伪协定链接)让其走Win软件敞开启动的逻辑。

渲染过程解决

这里咱们应用的伪协定链接为vue-cli-electron:///file/localFile?image=https://xuxinblog.oss-cn-qingdao.aliyuncs.com/blog/2021/07/01/1.jpg,拿到的也是这个残缺链接,咱们解决一下这个链接,跳转到/file/localFile,并下载query参数外面的image图片地址。下载及显示逻辑用之前的加载本地文件的逻辑。

App.vue
onMounted(() => {  window.ipcRenderer.on('renderer-scheme', (_event, data) => {    console.log(data)    const urlObj = new URL(data)    const query = {}    urlObj.search.slice(1).split('&').forEach(s => {      const item = s.split('=')      query[item[0]] = item[1]    })    router.replace({      path: urlObj.pathname.slice(2),      query    })  })})onUnmounted(() => {  window.ipcRenderer.removeAllListeners('renderer-scheme')})
localFile.vue
onMounted(() => {  const localImage = LgetItem('localImage')  if (route.query.image) {    download(route.query.image)  } else {    if (localImage) {      state.image = localImage    }  }})

好了,接下来应用浏览器关上vue-cli-electron:///file/localFile?image=https://xuxinblog.oss-cn-qingdao.aliyuncs.com/blog/2021/07/01/1.jpg试试,看看拉起软件后是否跳转到本地文件的路由,且显示的是伪协定中image的图片。

本系列更新只有利用周末和下班时间整顿,比拟多的内容的话更新会比较慢,心愿能对你有所帮忙,请多多star或点赞珍藏反对一下

本文地址:https://xuxin123.com/electron/url-scheme-query

本文github地址:链接