URL Protocol打开应用程序并传递程序启动参数(WindowsMac)

Posted chyshx

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了URL Protocol打开应用程序并传递程序启动参数(WindowsMac)相关的知识,希望对你有一定的参考价值。

------------恢复内容开始------------

url protocol技术能够使得应用程序可以通过一个自定义协议的url link启动。

以下所描述的操作,均基于实用QT框架开发跨平台的应用时遇到的问题及解决办法。

一.windows下:

1.可以在软件安装或者软件第一次本地运行的时候写注册表项。举个通过bat文件注册表例子:

技术图片

 

 大概解释一下,这个脚本的功能是通过生成一个临时的atsexam.reg注册表文件,然后通过regedit进行注册。

在程序安装的时候可以执行这个脚本,将程序的一些关键信息写入注册表,可以看到该程序启动时可以带一个参数(%1)。

后续就是在主程序int main(int agrc,char* argv[])中获取这个参数,并根据参数做处理了。

二.Mac 下:

1.如果不需要传递参数的话,比较简单,直接打开生成的app包(右键,查看包内容,打开Contents),编辑Info.plist文件,增加Url types项,给Url types的Item0增加一个URL Scheme节点,并赋予自定义的协议值。关于增加这个节点可以通过Xcode,也可以直接编辑info.plist文件,这个文件是个xml格式文件,但是每个节点的标签记起来比较繁琐,没有通过XCode来的快。

2.如果需要传递参数的话,比较复杂,没办法像Windows下,通过注册表中启动程序路径后面增加一个 %1,就可以把通过url启动时的url传递给应用程序处理。但通过查阅网上的资料,知道的大概有三种办法:

a) 原生开发:

  因为不是专门搞Mac开发的,所以不懂,但把链接放在这,可以参考:https://stackoverflow.com/questions/6561661/url-scheme-qt-and-mac/6699518#6699518

b)使用QT的eventfilter:

  QT的eventfilter,顾名思义就是事件过滤器。可以接受来自系统的事件,当一个与app相关的链接被打开时,会触发一个FileOPen类型的事件,所以可以通过过滤这个事件来获取传递给app的参数了,对于通过url protocol打开应用程序时,这个url就会被传递给app。然后再程序中就可以处理了。

  eventfilter的用法大致如下:

  1)定义一个类继承QObject,并override类的eventfilter方法,并定义一个signals,当检测到该参数时,向外传递;

  2)在该方法中过滤QEvent::FileOpen类型的事件,当检测到该种事件时,可以通过获取event的url内容来获取到需要传递给app的参数;

  3)发送signals,将参数传递出去;

  4)在main函数中,为application对象安装事件过滤器,通过调用installeventfilter安装。并通过QObject::connect()方法将事件过滤器中发送出来的信号链接到槽函数上(一般可以使用lambda表达式)。

  5)在槽函数中处理参数解析逻辑。

  具体的代码,网上可以找到,就不再贴了,如果是简单的程序逻辑,可以通过这种办法搞定。

  但是有一个现象需要注意就是:如果我们想通过传递的参数来决定程序的启动状态时(比如:当判断到参数不合理时不启动程序,当参数不同时启动不同的页面?),可能做不到这一点,因为很大概率上,我们接收到信号的时候,程序的初始化已经完毕了,这与我们的逻辑不符。如何解决呢?可以大致想到如下几种解决办法:

  i) 定义一个全局变量,主程序初始化时,如果需要通过接受的参数来初始化,那我们就等待该全局变量置位,看着很理想,但是已测试发现,行不通,如果我们的主进程在还没有接收到置位信号时就来到等待状态,那么程序很大概率就会一直处于等待状态了。也就是因为进程被挂起所以也收不到event了,收不到event了,所以也没法过滤了,没法过滤了,所以也就没办法得到参数了。貌似就是死循环了,可见行不通。

  ii)再i)的基础上写一个定时器,不再主进程等待,而是去定时器等待,主线程继续能接受事件,这种思路看着可行,但是程序的响应啊,以及把主界面的一些逻辑甚至窗体初始化放到了另一个线程中构建,可能会引入其他的问题,考虑到此,也就并没有尝试。

  iii)再写一个app,由这个app来响应url protocol。在该app中按照上述注册这些事件过滤器,当过滤到该事件后,可以通过启动一个process来启动真正的应用程序,通过process启动的程序,可以将参数传递进去。此处的逻辑便与windows相一致了。这个辅助的app可以写一个定时器,稍微等待一段时间就自己退出即可。通过测试,这种办法是可行的,但是记得这个process是通过startdetached启动的,这样就可以与辅助app无关啦,代码如下:

技术图片

 

   但是这个有个问题就是你需要两个app,这两个app都附带有QT相关的库,比较重。还有个小问题就是:你会发现通过url protocol启动的时候会有2个图标显示在dock里,看着很别扭,有没有办法能做的像只启动一个app呢,办法当然是有的,很简单:

  打开辅助的app包的info.plist文件。增加一个项,application is agent,并将其设置为YES即可。如此便只会显示一个app图标了,搞定。

c) 使用apple script(重点):

  既然都有了上述办法,按理说我们的问题可以解决了,但是还是不够完美,因为这个包比较大,如果不做一个QT依赖的排除的话,应用程序包太大比友好。所以就有了重点解决方法:使用applescript,具体applescript的使用可以参考相关手册,我没有深入研究,但是看他的语法,感觉特别口语化。那具体怎么做呢?

  先说一下大致思路:将编写的apple script保存为app bundle格式,就是.app。这个脚本的内容后面描述,我们先看里头,里头也会存在info.plist文件,根据上面的研究,我们重点设置两项内容:Url types和application is agent,如何设置可以参考上面。

  脚本的内容很简单,如下所示:

on open location this_URL
    return do shell script "open -b ‘ff.youreappidentify‘ --args" & space & quoted form of this_URL
end open location

  你只需要替换ff.youreappidentify为你的目标app的identify即可。这个identify怎么看呢,是在info.plist里头,可以自己找找看,当然这项内容是可以更改的。

  最后可以将这个app放到我们的目标app的目录里即可。这样通过url protocol 我们可以打开applescript,进儿applescript打开我们的app。形成一个打开链条,即只有一个图标,也比较轻量。

  但是需要主要,不过是url types还是identify都需要被移动一次,才能被系统监测到,不然调用的过程中可能没反应。不过这种现象可能只存在与开发机上,用户的电脑上,如果要用程序,至少存在一次拷贝,所以问题不大。

 

很可能第一种办法是最好的,但是奈何没做过Mac下的开发,不懂。不知道像chrome,zoom这些软件在Mac上是如何实现的?

  

 

 

 

 

 

 

 

 

 

 

 

 

 

------------恢复内容结束------------

以上是关于URL Protocol打开应用程序并传递程序启动参数(WindowsMac)的主要内容,如果未能解决你的问题,请参考以下文章

如何从 iOS 应用程序启动 Safari 并打开 URL

url protocol

处理OpenURL 方法。显示 modalviewcontroller 并传递 url 信息

通过Url Protocol实现web调用本地exe,兼容谷歌IE,并实现本地验证

在电子应用程序中实现延迟深度链接

C#:打开浏览器并从 Windows 桌面应用程序 POST 到 url