将 URI 传递给捆绑的应用程序

Pass URI to Bundled Application

我有一个用 pyinstaller 创建的 .app。 info.plist 摘录如下:

...
    <key>CFBundleURLTypes</key>
    <array>
        <dict>
            <key>CFBundleURLName</key>
            <string>Flagship</string>
            <key>CFBundleURLSchemes</key>
            <array>
                <string>flagship</string>
            </array>
        </dict>
    </array>
...

如果我在浏览器中打开任何以 flagship 开头的内容,即 flagship:foo,然后它会启动应用程序。但是,sys.argv 仅包含 url 到已编译的 python 可执行文件。如何捕获 URI 调用的参数,即如何从 URI 获取 foo

更新 1: 因此,以下工作可以启动应用程序: do shell script "open -a /Applications/AppName.app --args foo1 foo2" 当我使用捆绑为 .app 的 Apple 脚本并使用相同的 info.plist 选项时:

on open location this_URL
    do shell script "open -a /Applications/AppName.app --args " & this_URL & ""
end open location

问题是:如何直接从 URI 实现类似的功能?如果可能的话,我想避免使用中介应用程序。

更新 2: 我找到了一个工作示例:https://pyobjc.readthedocs.io/en/latest/examples/WebKit/PyDocURLProtocol/index.html

看来是肯定可以的,就是蛋疼。如果我让它工作,将会更新。这个命令,比如pydoc:///credid=foo在例子中完美的吐出来了,所以肯定是可以的

更新 3: 我最终使用 PySide6 进行了解决。我贴在下面了。

我最终使用 PySide6 解决了这个问题。使用 QApplication 的子类允许我定义一个事件处理程序来捕获 'file open' 事件......浏览器,即使它不是 'opening' 文件,仍然传递完整的 uri。代码如下:

from PySide6.QtCore import QEvent, QUrl
from PySide6.QtWidgets import QApplication
from ..logger import logger # NOTE: this code uses a packaged logger I built and you will need to replace it or remove all of the calls to logger to get this code to work.


class CustomURIApplication(QApplication):

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.on_uri_do = None
        self.last_uri = None

    def on_uri_call(self, func):
        """
        Run func when an uri is sent to the application; access the uri @ CustomURIApplication.last_uri
        :param func: the function to run (WITHOUT "()" AT THE END); use lambda for parameters
        :return: None
        """
        self.on_uri_do = func

    def event(self, e):
        """Handle macOS FileOpen events or pass to super."""
        if e.type() == QEvent.FileOpen:
            url: QUrl = e.url()
            self.last_uri: QUrl = url
            if url.isValid():
                logger.info(f"application received valid uri: {url}")
                logger.debug(f"executing callback function")
                self.on_uri_do()
            else:
                logger.warning(f"application received invalid uri: {url.errorString()}")
        else:
            return super().event(e)
        return True

Info.plist 需要包含我在原始问题中所拥有的内容,这仅在与 PyInstaller 捆绑后才有效。