唤醒 Electron 应用
2025年1月14日大约 2 分钟
唤醒 Electron 应用
原理
PC 网页唤醒桌面端应用,主要是使用系统提供的 API 注册一个自定义的协议,这个协议会添加到系统协议列表中,
浏览器或者其他应用打开这个协议链接时会去系统协议列表中查询,如果找到了对应的协议,就会唤起协议的默认处理程序。
注册协议
Electron 提供了自定义协议的 API: setAsDefaultProtocolClient
官方文档解释
app.setAsDefaultProtocolClient(protocol[, path, args])
protocol
:string
- 协议的名称,不带://
。 例如,如果你希望应用处理electron://
链接,请以electron 为参数调用此方法。path
:string
(可选) Windows - Electron 可执行文件路径。 默认为process.execPath
args
:string[]
(可选) Windows - 传递给可执行文件的参数。 默认为空数组。
返回 boolean
- 是否调用成功。
在注册自定义协议之前,需要先判断是否已经注册过,防止重复注册,Electron 提供了 API: isDefaultProtocolClient。
官方文档解释
app.isDefaultProtocolClient(protocol[, path, args])
protocol
:string
- 协议的名称,不带://
。path
:string
(可选) Windows - Electron 可执行文件路径。 默认为process.execPath
args
:string[]
(可选) Windows - 传递给可执行文件的参数。 默认为空数组。
返回 boolean
- 当前可执行程序是否是协议 (也就是URI scheme) 的默认处理程序。
protocol = 'software';
if (!electronApp.isDefaultProtocolClient(protocol)) {
electronApp.setAsDefaultProtocolClient(protocol);
}
获取自定义参数
Windows 自定义参数通过 process.argv
获取,process.argv
是字符串数组,第一个参数是可执行文件路径,第二个参数是协议链接,后面的参数是协议链接中的参数。
MacOS 和 Linux 不支持 process.argv
,所以需要使用 app.on('open-url')
来获取自定义参数。
this.handleArgv(process.argv);
app.on('second-instance', (event, argv) => {
if (process.platform === 'win32') {
this.handleArgv(argv)
}
})
app.on('open-url', (event, urlStr) => {
this.handleUrl(urlStr)
})
/**
* 参数处理
*/
function handleArgv(argv) {
const offset = app.isPackaged ? 1 : 2;
const url = argv.find((arg, i) => i >= offset && arg.startsWith(this.protocol));
this.handleUrl(url)
}
/**
* url解析
*/
function handleUrl(awakeUrlStr) {
if (!awakeUrlStr || awakeUrlStr.length === 0) {
return
}
const {hostname, pathname, search} = new URL(awakeUrlStr);
let awakeUrlInfo = {
urlStr: awakeUrlStr,
urlHost: hostname,
urlPath: pathname,
urlParams: search && search.slice(1),
}
this.awakeUrlInfo = awakeUrlInfo
}
最终代码
electron\index.js
const {app} = require('electron');
const awaken = require('./awaken');
// 获取单实例锁
const gotTheLock = app.requestSingleInstanceLock();
if (!gotTheLock) {
// 如果获取失败,说明已经有实例在运行了,直接退出
app.quit();
}
awaken.create();
awaken.js
const {app, protocol} = require('electron');
/**
* 唤醒插件
* @class
*/
class Awaken {
// 唤醒url信息
awakeUrlInfo;
constructor() {
this.protocol = 'software';
}
/**
* 创建
*/
create() {
if (!electronApp.isDefaultProtocolClient(this.protocol)) {
electronApp.setAsDefaultProtocolClient(this.protocol);
}
this.handleArgv(process.argv);
app.on('second-instance', (event, argv) => {
if (process.platform === 'win32') {
this.handleArgv(argv)
}
})
app.on('open-url', (event, urlStr) => {
this.handleUrl(urlStr)
})
}
/**
* 参数处理
*/
handleArgv(argv) {
const offset = app.isPackaged ? 1 : 2;
const url = argv.find((arg, i) => i >= offset && arg.startsWith(this.protocol));
this.handleUrl(url)
}
/**
* url解析
*/
handleUrl(awakeUrlStr) {
if (!awakeUrlStr || awakeUrlStr.length === 0) {
return
}
const {hostname, pathname, search} = new URL(awakeUrlStr);
let awakeUrlInfo = {
urlStr: awakeUrlStr,
urlHost: hostname,
urlPath: pathname,
urlParams: search && search.slice(1),
}
this.awakeUrlInfo = awakeUrlInfo
}
/**
* 获取url参数
*/
getUrlParams() {
if (!this.awakeUrlInfo || !this.awakeUrlInfo.urlParams) {
return null
}
return this.awakeUrlInfo.urlParams
}
}
Awaken.toString = () => '[class Awaken]';
module.exports = Awaken;