Electron伪协议参数获取
上一期我们介绍了如何设置伪协议,并通过伪协议链接拉起客户端,其实伪协议还有很多场景的,比如百度网盘或者迅雷,点击网页上的链接进行下载,或者点击链接拉起客户端后打开某个页面,其实这都是可以用伪协议链接实现的,链接中的参数就和网页的参数没啥区别,本期就介绍如何获取伪协议链接中的参数。
实现目标
- 软件关闭时通过伪协议拉起软件获取该伪协议链接。
- 软件启动时通过伪协议拉起软件获取该伪协议链接。
- 通过伪协议传入一个图片链接和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地址:链接
你好我想问下,前端调用伪协议后,能获得伪协议的返回值吗,或者说能想http那样吗