pywebview icon indicating copy to clipboard operation
pywebview copied to clipboard

Open Custom File Extension (MacOS CFBundleTypeExtensions)

Open jmitchel3 opened this issue 5 years ago • 6 comments

Specification

  • pywebview version: 3.3.1
  • platform / version: macOS 0.15.5 and Windows 10

Description

First off. This is an amazing project. Thank you for creating pywebview!!

An event handler for when a file is opened for a specific file extension/type in macOS I believe it's CFBundleTypeExtensions in the plist. I'm able to get pywebview to open using this setting but unable to handle the file being opened. Here's the plist argument I'm passing in setup.py:

OPTIONS = {..
          'plist': {
                'CFBundleName': "MyApp",
                'CFBundleDisplayName': "MyApp",
                'CFBundleGetInfoString': "App it Up",
                'CFBundleIdentifier': "com.example.app",
                'CFBundleVersion': "0.1.0",
                "CFBundleTypeRole": "editor",
                "CFBundleTypeExtensions": ["appy-mc-apperson"],
                'CFBundleShortVersionString': "0.1.0",
                'NSHumanReadableCopyright': u"Copyright © 2020, Justin Mitchel, All Rights Reserved"
            }
}

The appy-mc-apperson represents something like my-project.appy-mc-apperson to, ideally, re-open our application and re-load the project. For context, .appy-mc-apperson is an arbitrary extension I made up for this post.

This works in Electron fairly simply as you can see here under fileAssociations. This would allow pywebview apps to resume projects that are being worked on which would be key for several projects I'm working on.

Practicalities

-YES. Happy to help however I can. -YES. I am prepared to support this issue financially within reason of course. I'm trying not to use Electron as much since it's so bloated especially for tiny projects.

jmitchel3 avatar Jul 11 '20 17:07 jmitchel3

I am not familiar with this API, but this definitely should be implemented. Without dwelling into details, I believe an appropriate event handler should be added to cocoa.py. Other platforms should be investigated as well.

r0x0r avatar Jul 14 '20 08:07 r0x0r

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

github-actions[bot] avatar Aug 26 '20 01:08 github-actions[bot]

@jmitchel3 can you explain more

Ksengine avatar Dec 02 '20 16:12 Ksengine

I wanted to add an update here based on something that's nearly working with py2app configuration.

OPTIONS = {
    "argv_emulation": True,
    ...
    "plist": {
        'CFBundleName': "MyApp",
                'CFBundleDisplayName': "MyApp",
                'CFBundleGetInfoString': "App it Up",
                'CFBundleIdentifier': "com.example.app",
                'CFBundleVersion': "0.1.0",
                "CFBundleTypeRole": "Editor",
                "CFBundleTypeExtensions": ["appy-mc-apperson"],
                "CFBundleTypeIconFile": "icon.icns",
                'CFBundleShortVersionString': "0.1.0",
                'NSHumanReadableCopyright': u"Copyright © 2020, Justin Mitchel, All Rights Reserved"
    },
}

Once you have "argv_emulation": True, the rest of your code will have access to another argument in sys.argv.

When you open your file extension, in this case I called it appy-mc-apperson which means if I double click my-project.appy-mc-apperson I see the following:

Screen Shot 2021-02-01 at 11 20 26 AM

Once you select your pywebview built app, my-project.appy-mc-apperson will always open your app with a new argument in sys.argv:

print(sys.argv[1]) 
# prints path/to/system/location/of/my-project.appy-mc-apperson

This sys.argv[1], if available, is a path to the my-project.appy-mc-apperson file. You can read this file as needed in your pywebview project.

If your app is not open, it works! (without changes to cocoa.py). However, f your app is open and you double-click to open an associated file you'll see this error:

Screen Shot 2021-02-01 at 11 24 33 AM.

I'd guess that pyinstaller might have a different way of implementing this same idea. It stands to reason that when you open any file on your system, the OS will open the application with an argument for that file path.

I think we still need to solve:

  • Errors on multiple file opening
  • Automatic system-wide file association on app opening
  • Cross platform support
  • Simple menu support (including cmd+o and cmd+s)

jmitchel3 avatar Feb 01 '21 19:02 jmitchel3

For anyone that stumbles upon this issue, you can solve the above issue by following these three steps:

  1. Switch to the webview.start(gui='qt') engine, as it's more configurable.
  2. Turn off argv_emulation. Rely on the qt engine's event handling instead of py2app's event handling.
  3. Add an event handler to webview's qt engine, similar to this SO answer.

Here's a minimal change to the hello world pywebview script that shows the idea.

app.py

import webview
import webview.platforms.qt
from qtpy.QtWidgets import QApplication
from qtpy.QtCore import QEvent
import webview.platforms.qt  # needed for us to define a custom application


class MainApplication(QApplication):
    def event(self, event: QEvent):
        if event.type() == QEvent.Type.FileOpen:
            print(event.url())
        return super().event(event)


if __name__ == '__main__':
    app = MainApplication([])  # so that when pywebview calls `QApplication.instance()` your app is returned
    webview.create_window('Hello world', 'https://pywebview.flowrl.com/')
    webview.start(gui='qt')

setup.py

"""Simple setup script for actually building your application. See README"""

from setuptools import setup

APP = ['app.py']  # your main application
OPTIONS = {
    'plist': {
        'CFBundleURLTypes': [
            {
                'CFBundleURLName': 'MyApplication',
                'CFBundleURLSchemes': ['myapp'],
            },
        ],
    },
    'strip': True,
    'includes': ['WebKit', 'Foundation', 'webview'],
}

setup(
    app=APP,
    options={'py2app': OPTIONS},
    setup_requires=['py2app', 'pyqt6'],  # add other dependencies here
)

alvinwan avatar Jun 25 '23 05:06 alvinwan