浏览器调用本地exe(应用程序)及传参(Windows & Mac)

在这里插入图片描述


在我们使用应用时,我们经常涉及到应用通过浏览器打开本地应用,比如百度网盘、腾讯会议等等,这种浏览器打开本地app的方式,十分高大上。但你知道实现方式吗?

其实,在Windows、Mac、Linux等系统中实现的方法都是「注册应用程序协议」,比如说在Windows,只需在注册表中写入应用程序启动信息,在浏览器调用程序时,会先去注册表中查询应用信息,然后调用启动信息,即可实现协议与执行程序的关联。

一、Windows&Mac自定义URL Scheme

1、Windows 注册自定义 URL Scheme

第一步:新建 .reg 文件,内容格式如下

Windows Registry Editor Version 5.00
[HKEY_CLASSES_ROOT\MYSCHEME]
"URL Protocol"="E:\\APP\\app.exe"
@="MYSCHEME.Protocol"
[HKEY_CLASSES_ROOT\MYSCHEME\DefaultIcon]
@="E:\\APP\\app.exe,1"
[HKEY_CLASSES_ROOT\MYSCHEME\shell]
[HKEY_CLASSES_ROOT\MYSCHEME\shell\open]
[HKEY_CLASSES_ROOT\MYSCHEME\shell\open\command]
@="\"E:\\APP\\app.exe\" --login-settings \"%1\""

上面的注册表信息,将告诉系统我们要注册一个自定义的URL Scheme,修改完成后,双击文件即可将信息写入注册表中。

  • MYSCHEME: 自定义 URL Scheme 名称,此名称用于浏览器调用应用的唯一标识
  • E:\APP\app.exe:APP的绝对路径
  • –login-settings “%1"”: 应用启动时 传递的参数 %1为占位符

第二步:HTML文件用于浏览器启动

此时我们可以写一个HTML文件,在文件中根据自己的情况修改 a标签

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>浏览器启动本地应用</title>
</head>
<body>
    <a href="MYSCHEME://?token=fjasfjasndfnas">打开你的应用程序</a>
</body>
</html>

保存后,在浏览器打开此HTML文件,点击超链接,将会唤起 E:\APP\app.exe\ 并将参数–login-settings 「–login-settings=MYSCHEME://?token=fjasfjasndfnas」传递给应用程序。
此时,浏览器弹出弹窗提示用户是否启动本地应用程序,当用户选择启动后,则会将参数拼接至启动命令行中,启动程序。

E:\APP\app.exe --login-settings=“MYSCHEME://?token=fjasfjasndfnas”

2、macOS 注册自定义 URL Scheme

macOS 下与 Windows 在自定义 URL 的实现上有差异,MAC中的方法简单一些,仅需要修改 Info.plist文件即可:
Info.plist 文件位置: 应用程序名称右键 —> 显示包内容 —> contents —> Info.plist 建议使用sublime打开文件

<key>CFBundleURLTypes</key>
	<array>
		<dict>
			<key>CFBundleURLSchemes</key>
			<array>
				<string>MYSCHEME</string>
			</array>
			<key>CFBundleURLName</key>
			<string>com.tencent.wemeet</string>
		</dict>
	</array>

其中 MYSCHEME 为自动注册到系统中的自定义 URL Scheme,当在 macOS 下通过浏览器访问 MYSCHEME:// 的地址时,浏览器将弹出弹窗提示用户是否启动本地应用程序。「注意:如果不提示的话,建议重新打包应用程序,重新生成info.plist文件
注意:CFBundleURLName中的string为反DNS, 如果想知道其他字段设置:请移步官方文档
在这里插入图片描述
在这里插入图片描述
测试Mac的网页使用Windows的HTML即可,格式一致。

二、应用程序传参:

1、在Windows中

可在程序中使用 argparse.ArgumentParser() 方法设置参数
在这里插入图片描述
对传入的参数进行处理:

# 使用到urlparse模块对url进行解析
options, argv_rest = parser.parse_known_args(argv[1:])
if options.login_settings:
    parsed_result = urlparse(options.login_settings).query  
    result = {k: v[0] for k, v in parse_qs(parsed_result).items()}
    if result.get('token'):
        print("设置Token:", result['token'])

参数设置的具体方法,可参考:https://blog.csdn.net/qq_42571592/article/details/122179398

2、在Mac中

MacOS下相对比较简单,其中 Qt 的方式非常简单,只需要响应应用的 QFileOpen 事件即可实现此功能,代码如下。

Qt实现方法

bool FileOpenEventFilter::eventFilter(QObject* obj, QEvent* event)
{
    if (event->type() == QEvent::FileOpen)
    {
        QFileOpenEvent* fileEvent = static_cast<QFileOpenEvent*>(event);
        if (!fileEvent->url().isEmpty())
        {
            m_lastUrl = fileEvent->url().toString();
            emit urlOpened(m_lastUrl);
        }
        else if (!fileEvent->file().isEmpty())
        {
            emit fileOpened(fileEvent->file());
        }

        return false;
    }
    else
    {
        // standard event processing
        return QObject::eventFilter(obj, event);
    }
}

使用pyqt5实现方法与思路:

定义槽,具体槽的使用可看文章: https://blog.csdn.net/m0_37329910/article/details/86571800

1、声明带QUrl参数的信号

from AnyQt.QtCore import QUrl, pyqtSignal as Signal
self.fileOpenRequest = Signal(QUrl)

2、定义槽函数

 def record_path(url: QUrl):
	 if url.toString().startswith("myscheme"):
	     parsed_result = urlparse(url.toString()).query
	     result = {k: v[0] for k, v in parse_qs(parsed_result).items()}
	     if result.get('token'):
	         print("设置Token:", result['token'])
	 else:
	     path = url.toLocalFile()  # 本地文件路径
	     if os.path.exists(path):  # 如果文件存在则打开
	         print("打开文件的路径为:", path)

3、将信号连接到指定槽函数

self.fileOpenRequest.connect(record_path)

4、发射信号

 def event(self, event):
	if event.type() == QEvent.FileOpen:    # 对请求进行判断
	    self.fileOpenRequest.emit(event.url())
	elif event.type() == QEvent.PolishRequest:
	    print("正常启动")
	return super().event(event)

代码截图:
在这里插入图片描述注意:目前此方法只支持Mac系统

mac传参流程及原理总结:

流程

使用浏览器启动应用时,QEvent进行监听,当event.type()为 QEvent.FileOpen时,对event进行处理。

原理:QEvent::FileOpen方法用于应用启动的两种方式:

  • 方式一:在浏览器中启动,在浏览器搜索栏输入: MYSCHEME://?token=fjasfjasndfnas,此时应用接收到的为:PyQt5.QtCore.QUrl(‘MYSCHEME://?token=fjasfjasndfnas’)
  • 方式二:以此应用程序作为默认打开文件的方式唤起。或者将要使用此应用打开的文件拖到应用的图标上,唤起应用。此时应用接收到的为:PyQt5.QtCore.QUrl(‘file://文件本地路径’)

所以,两种方式其实都是走的DNS格式,只需对这两种参数进行不同的处理,本地文件在应用中打开文件,浏览器的参数则进行处理。

三、总结下Windows和Mac的实现方法:

Windows下:

  • 在注册表中注册 URL Scheme 到系统
  • 浏览器启动程序时,参数按照占位符格式传参
  • 应用启动时接收相关参数,并对其进行处理 「使用到的设置参数方法为:argparse.ArgumentParser()」

Mac下:

  • 通过 Info.plist 将 URL Scheme 注册到系统
  • 浏览器启动程序时,参数走的是event,然后在event中,对参数进行处理「使用到的方法为:QEvent.FileOpen」

两者的区别:

  • Windows下注册表中限制了命令的传参方式,所以浏览器启动最终落实为命令行启动,传参的话,我想到的方法为使用argparse.ArgumentParser()定义参数。
  • Mac系统下,没对启动命令进行限制,所以只能通过QEvent进行监听,从而实现启动应用传参。

四、参考文章:

Qt 通过自定义 URL Scheme 给已经运行的应用传参(Windows&macOS)
PyQt5官网
Mac开发者
PyQt 5信号与槽的几种高级玩法
QT论坛

欢迎大家在评论区留言,知无不言,言无不尽。感觉不错的话,别忘了点赞收藏哦!
在这里插入图片描述

Logo

更多推荐