共计 4608 个字符,预计需要花费 12 分钟才能阅读完成。
上一期咱们介绍了如何设置伪协定,并通过伪协定链接拉起客户端,其实伪协定还有很多场景的,比方百度网盘或者迅雷,点击网页上的链接进行下载,或者点击链接拉起客户端后关上某个页面,其实这都是能够用伪协定链接实现的,链接中的参数就和网页的参数没啥区别,本期就介绍如何获取伪协定链接中的参数。
实现目标
- 软件敞开时通过伪协定拉起软件获取该伪协定链接。
- 软件启动时通过伪协定拉起软件获取该伪协定链接。
- 通过伪协定传入一个图片链接和 router path 门路,跳转该门路,并下载图片本地加载显示。
伪协定获取差别
上一章咱们介绍了伪协定是怎么启动客户端的,即:
- Windows 是通过注册表写入伪协定,调用利用启动 exe 和
%1
启动客户端的。 - Mac 是通过软件包中的
info.plist
文件设置启动客户端的。
这两者的启动形式不同,故获取形式也是不同的,咱们来看一下通过伪协定的启动流程吧:
Windows 伪协定启解决
- 首先软件处于敞开状态的话,咱们在浏览器上关上伪协定链接,会注册表下来找对应的伪协定,启动 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]
- 软件处于开启状态的话,咱们能够通过 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 伪协定链接就是 urlStr
app.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 地址:链接