'Pass URI to Bundled Application
I have a .app created with pyinstaller. The info.plist
is excerpted below:
...
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLName</key>
<string>Flagship</string>
<key>CFBundleURLSchemes</key>
<array>
<string>flagship</string>
</array>
</dict>
</array>
...
If I open anything that begins with flagship
in the browser, i.e. flagship:foo
, then it launches the application. However, sys.argv
only contains the url to the compiled-python executable. How do I capture the parameters of the URI call, i.e. how do I get the foo
from the URI?
Update 1:
So the following works to launch the app:
do shell script "open -a /Applications/AppName.app --args foo1 foo2"
when I use this Apple Script bundled as a .app and using the same info.plist options:
on open location this_URL
do shell script "open -a /Applications/AppName.app --args " & this_URL & ""
end open location
The question is: how can I achieve something similar directly from the URI? I would like to avoid the intermediary app if at all possible.
Update 2: I found a working example: https://pyobjc.readthedocs.io/en/latest/examples/WebKit/PyDocURLProtocol/index.html
It looks like it is definitely possible, just a pain. Will update if I get it working. This command, for example, pydoc:///credid=foo
spits out perfectly in the example, so it is definitely possible.
Update 3: I ended up going to a workaround with PySide6. I posted it below.
Solution 1:[1]
I ended up figuring this out using PySide6. Using a subclass of QApplication allowed me to define an event handler that catches a 'file open' event... the browser, even if it is not 'opening' a file, still passes the full uri. Code below:
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 needs to include what I have in the original question and this only works once bundled with PyInstaller.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 |