前言
对于一个 URL 来说,其实就是指定了一个协议(protocol
),然后让系统用对应的应用去打开它。如 myapp://openapp?name=1&pwd=2
,系统会去找到已经注册了 myapp
这个协议的应用,然后把 URL 当做参数传过去。
这样我们就可以在浏览器中通过一个 <a>
标签简单地唤起应用了。
1 | <a href="myapp://openapp?name=1&pwd=2">打开应用</a> |
单实例运行
首先,每次打开一个协议 URL,系统都会启动一个新的应用。这就需要应用自己去判断,把 URL 当做参数传给已有的应用,还是自己直接处理。
Electron 提供了一个简单的方法,来获取一个锁,只有第一个调用的实例才能获取成功,后面的其他实例则把参数传过去,然后退出就可以了。
1 | const { app } = require('electron'); |
注册协议
我们期望通过协议来启动应用,所以要先注册一个协议到系统中,调用 API 即可:
1 | const PROTOCOL = 'myapp'; |
这里的 args
是预定义的参数,对 macOS 没有作用,但是在 Windows 上却是必不可少的。
在 Windows 上启动一个协议URL时,实际上是用如下参数启动了我们的应用:
1 | ${process.execPath} ${...args} myapp://... |
需要注意的是,在开发阶段,我们是通过 electron .
或者 electron path/to/script.js
来启动的应用,所以 process.argv[1]
是我们的脚本路径,传给系统时,这个参数也不能少,否则启动的就是一个纯粹的 Electron 壳,而不是我们的应用了。这时,这个参数就要通过这里的 args
一起注册到系统中了。
根据这个帖子,我们可以在预定义的参数最后加一个
--
,来阻止其他参数直接被 Electron 处理。
获取参数
第二个实例运行的时候,自己就退出了,那么第一个实例如何能获取到启动第二个实例的参数呢?这里 macOS 和 Windows 上的行为是不一致的,需要分别处理。
1 | // 如果打开协议时,没有其他实例,则当前实例当做主实例,处理参数 |
Windows 下 argv
的处理有一个需要注意的地方,就是开发阶段要跳过前两个参数(execPath
和当前启动脚本):
1 | function handleArgv(argv) { |
完整的协议链接跟HTTP链接类似,如下:
myapp://openapp?name=1&pwd=2
但大部分情况下,我们可能只需要最后的 key-value 参数就可以了,所以可以省略成:
myapp://?name=1&pwd=2
链接可以通过全局对象 URL
来解析:
1 | function handleUrl(urlStr) { |
完整代码如下:
1 | const path = require('path'); |
收到协议打开页面
1 | let autologindata = null; |
首页面设置
1 | const isDevelopment = !app.isPackaged; |
这样设置的原因是
收到协议传输数据的时候页面还没创建,所以用外部变量保存接收的值,当窗口打开后再做处理
登录页面监听值
1 | autologin_event() { |
与单实例结合
我的程序是单实例的,如果打开第二个实例的时候,我这边的处理是显示第一个实例的窗口,
第一个实例正在打开的窗口可能是其他窗口,而协议的传参我只在登录处理了,所以这里就忽略了第二个实例的传参处理。
main.js
1 | const gotTheLock = app.requestSingleInstanceLock(); |
这里面删除了
1 | // Windows 第二个实例触发 |
login.vue
登录页面这样处理
页面加载事件
1 | mounted() { |
方法
1 | methods: { |