Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement file association Open a file from Finder/Explorer #2918

Merged
merged 39 commits into from Oct 21, 2023

Conversation

APshenkin
Copy link
Contributor

@APshenkin APshenkin commented Sep 17, 2023

Description

Implements file association for macOS/Windows #1830

Users can specify list of associated file types in wails.json config with following params

"ext": :"The extension (minus the leading period). e.g. png"
"name": "The name. e.g. PNG File"
"iconName": "The icon name without extension. Icons should be located in build folder. Proper icons will be generated from .png file for both macOS and Windows)"
"description": "Windows-only. The description. It is displayed on the `Type` column on Windows Explorer."
"role": "macOS-only. The app’s role with respect to the type. Corresponds to CFBundleTypeRole."

Also custom icons for files are supported πŸš€

For Linux will try to investigate what can be done later

Few comments regarding implementation
MacOS: Darwin handle opening file by raising openFile event. Callback is added for app configuration to handle this correctly.
Windows: On Windows fileAssociation is done via NSIS installer. So apps should be distributed with it to have this feature.
When associated file is opened, Windows launches new instance of the app and pass filePath as argument. So apps developers should parse args and handle situation properly. However it's common practic to frameworks like Electron or Tauri provide capabilities to lock single instance and handle cases, when new instance is opened. Seems wails v3 will have support of it #1351 . But currently this plugin not supporting passing arguments from new instance for first one https://github.com/wailsapp/wails/blob/v3-alpha/v3/plugins/single_instance/plugin_windows.go
Linux: To setup association and icons changes in client system should be done. As wails doesn't support bundling for linux now, nothing was added in this PR for it, but in test repo that is provided below you can see how this can be done using nfmp

You can see how it works here.

  • Windows
  • MacOs
  • Linux – NOTE THIS IS NOT PART OF PR AS WAILS DOESN'T SUPPORT BUNDLING FOR LINUX

Fixes # (issue)

Type of change

Please delete options that are not relevant.

  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update

How Has This Been Tested?

Test repo is available here https://github.com/APshenkin/wails-open-file
PR should be fetched and replace in go.mod should be adjusted

  • Windows
  • macOS
  • Linux

Test Configuration

# Wails
Version  | v2.6.0
Revision | a419721dcdf16da7a4afd92b9ba63b2050229a26
Modified | true

# System
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
| OS           | MacOS    |
| Version      | 13.5.2   |
| ID           | 22G91    |
| Go Version   | go1.20.2 |
| Platform     | darwin   |
| Architecture | arm64    |
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜


# System
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
| OS           | Windows 10 Pro      |
| Version      | 2009 (Build: 22621) |
| ID           | 22H2                |
| Go Version   | go1.21.1            |
| Platform     | windows             |
| Architecture | arm64               |
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                         

# System
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
| OS           | Ubuntu              |
| Version      | 22.04               |
| ID           | ubuntu              |
| Go Version   | go1.21.1            |
| Platform     | linux               |
| Architecture | arm64               |
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Checklist:

  • I have updated website/src/pages/changelog.mdx with details of this PR
  • My code follows the general coding style of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes

@leaanthony
Copy link
Member

This is awesome! Thanks for taking the time to do it. I'm all for having it register on install via NSIS, but I'm also thinking people might like to do it programmatically and be able to toggle it on or off as a preference setting. What are your thoughts on this?

@APshenkin
Copy link
Contributor Author

@leaanthony
I can see few problems with programatically approach:

  1. Registry pollution. With installer/uninstaller option you can control removal of file association, when application is uninstalled. It will clean up registry keys + icons. With program approach if user will just delete application, nobody will cleanup system after. In MacOs for example everything is configured within the app, so when you will delete your app, it will no longer try to open such file extensions in non-existing app
  2. file icon association is hard then, as you should rely that client will put icons file in proper place. Of course you can embed icons and then install it somewhere in the system, but then if I was a developer and want such of flexibility, I probably will implement it by myself as different scenarios can be (install icons in temp folder?, install in same folder, where app is, etc)

As well, just tried to check if some other similar projects provide such feature – both electron and tauri are using installer approach.

Also small remark about Linux:
Same as for Windows Linux requires some system manupulations to make such assignments
Here is good tutorial that I'll try to implement in next few days in my test project https://unix.stackexchange.com/questions/585997/assign-an-icon-to-a-custom-mimetype

However I also think that this should be part of some installer like .deb that will creates Desktop Entry, file associations, check that webkit is installed etc. And also some uninstaller, that will clean up everything if application is removed.

I don't know is there any plans to support installers for Linux (as this issue says no but it was 4 years ago #2), but will implement some bash prototype in example repo

@leaanthony
Copy link
Member

Thanks for taking the time to dive into that. Yeah, agree that the installer approach is probably better πŸ‘ Good luck with the Linux side of things πŸ˜…

@APshenkin
Copy link
Contributor Author

@leaanthony finally, I was able to achieve required result on Ubuntu. Updated PR description and test repo to demonstrate how this can be implemented. However as wails is not supporting now bundling for linux – nothing to add in this PR.

Have just one question now – what is required for approving this PR? πŸ™ƒ If documentation is missing part, then maybe somebody can support me on this, so it will be added in proper place?

@leaanthony
Copy link
Member

Thanks for this. Please could you add an entry to the changelog located at website/src/pages/changelog.mdx?

I'd be keen to get feedback from @stffabi about the NSIS changes. Regarding documentation, I think the best solution might be a guide to walk developers through how to use it.

@APshenkin
Copy link
Contributor Author

@leaanthony changelog updated, documentation created as well.

@APshenkin
Copy link
Contributor Author

@leaanthony please don't merge it for now. I discovered some issue with openFiles method on MacOs during single instance lock implementation. App is crashing if this handler exists and you then try to open binary with passing args like

open -n ./build/bin/wails-open-file.app --args "foo"

I'm looking on how this can be solved

@APshenkin
Copy link
Contributor Author

APshenkin commented Sep 28, 2023

@leaanthony final changes were made:

  1. I removed openFiles listener from macOS, as it works quite weird. It doesn't affect functionality, as now openFile is triggered. And behaviour with open app with args works properly
  2. I moved openFile to macOS configuration, as it's only macOS specific, so it make sence to have it there.

Tested on all platform, works like a charm.

BTW single instance lock branch is ready on my side for all the platforms :) Happy to open PR once this one will be merged :)

@leaanthony
Copy link
Member

I'll try to review this over the weekend πŸ‘

@leaanthony
Copy link
Member

Apologies for the delay on this. Will prioritise this

@PylotLight
Copy link
Contributor

PylotLight commented Oct 10, 2023

Was able to test this one just to add some noise here from a noob, steps I followed and results:

  • Using my own existing project
  • Built testing v2 cli using PR
  • Added sample code for a windows nsis installer to my app.go and wails.json files provided in sample repo.
  • Ran installer which automatically created required registry associations for "testfile.ppshenkin" but not "testfile - Copy.wwwails"
  • taskkill /f /im explorer.exe && explorer was required to update explorer to show updated icon but restart would also achieve that and is unavoidable windows thing.
  • Launching associated files creates a new instance of the app as expected.
    wails.json config:
  "info": {
    "fileAssociations": [
      {
        "ext": "wwwails",
        "name": "Lets Test Wails",
        "description": "Lets New Wails file",
        "iconName": "appicon",
        "role": "Editor"
      },
      {
        "ext": "ppshenkin",
        "name": "Test Pshenkin File",
        "description": "Pshenkin file",
        "iconName": "appicon",
        "role": "Editor"
      }
    ]
  }

image
image

@APshenkin
Copy link
Contributor Author

@PylotLight

Thank you for testing this PR.

I didn't clearly understand this point:

Ran installer which automatically created required registry associations for "testfile.ppshenkin" but not "testfile - Copy.wwwails"

Do you mean that only association for ppshenkin extension was added properly?

I tried now to add extra association in my branch and seems all extensions works correctly. If you will open wails_tools.nsh script in build/windows it should contains all your associations in !macro wails.associateFiles macro.

Also please check that project.nsi is updated as well. It might be the case as you used it in existing project wails didn't update it. Check that !insertmacro wails.associateFiles is presented there

Screen.Recording.2023-10-11.at.19.57.43.mov

@PylotLight
Copy link
Contributor

Hmm yep that's interesting.
My wails_tools.nsh seems to be correct as far as I can see, but the registry isn't updating in the same way for some reason.
One other thing to note is that uninstall did not remove those entries from registry:
Computer\HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts.ppshenkin
Computer\HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts.wwwails
image

Ah I can see !insertmacro wails.associateFiles is not present in project.nsi for some reason, which is curious given 1 extension worked fine and the other only half updated correctly.

To make sure I have an update CLI built, is it correct that I've cloned wails, run checkout for that PR:

gh pr checkout 2918
From https://github.com/wailsapp/wails

  • branch refs/pull/2918/head -> FETCH_HEAD
    Already up to date.

Then built custom CLI with "go build -o wails-test".

Anything else I can check/change that I might be missing as part of project configuration?

@APshenkin
Copy link
Contributor Author

@PylotLight try to copy project.nsi from branch to you locally https://github.com/APshenkin/wails/blob/feature/open-files/v2/pkg/buildassets/build/windows/installer/project.nsi

I think we need input from @leaanthony regarding upgrading project.nsi on new build. I assume it's not doing so to avoid cases when user did some custom changes there

@leaanthony
Copy link
Member

Just catching up. Is the issue that the NSIS config in the PR isn't being picked up when using -nsis?

@stffabi
Copy link
Collaborator

stffabi commented Oct 12, 2023

I will try to take a look into the PR this weekend.

@stffabi
Copy link
Collaborator

stffabi commented Oct 12, 2023

I think we need input from @leaanthony regarding upgrading project.nsi on new build. I assume it's not doing so to avoid cases when user did some custom changes there

Yeah, that's intended behaviour and is in line with other artifacts that only get generated once. The idea is that project.nsi can be customized and is never overwritten if it's there. Whereas the wails_tools.nsh contains predefined macros that get generated during every build and those might change with newer Wails versions, but the project.nsi remains as it because customizations of the developer will be placed in that file.

One can simply delete it and it gets regenerated during the next wails build -nsis.

@PylotLight
Copy link
Contributor

PylotLight commented Oct 13, 2023

I did a new init this time and interestingly the reg files generated weirdly but opposite again.
With ppshenkin missing the required a record.
image
image

I also have both !macro wails.unassociateFiles in wails_tools.nsh and !insertmacro wails.unassociateFiles in project.nsi and the reg keys remain after being uninstalled.

@APshenkin Sorry to be a bother, can you provide exact commands starting from a new init template I can run to test the same senario as your working example to see if something I'm doing differently has caused my issues?

@leaanthony
Copy link
Member

@APshenkin any updates? Looking to get this in πŸ‘ Thank you πŸ™

@APshenkin
Copy link
Contributor Author

APshenkin commented Oct 21, 2023

@PylotLight I think the registry keys that you searching is not something that is inserted by our nsis script.

E.g. if you have such configuration

{
        "ext": "newext",
        "name": "New Extension",
        "description": "Test new extension file",
        "iconName": "fileIcon",
        "role": "Editor"
      },

This is what will be installed in registry
Computer\HKEY_CLASSES_ROOT\.newext for registering .newext with name New Extenstion
Computer\HKEY_CLASSES_ROOT\New Extension where inside will be information what is description, icon location, shell launching command.

Then I assume, when you open file in explorer it will be registered in
Computer\HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.newext

But there is nothing that installation should do. It will be automatically picked by Windows.

the reg keys remain after being uninstalled.

Well, you are looking to other reg keys, that we are not installing. It's something that Windows set by themselves. BTW it's not a problem, that the records are still there, as if you uninstall app, it will not be able to open app and will show "Open With" dialog

BTW here is step by step guide that works to me for from scratch project:

git clone https://github.com/APshenkin/wails.git
cd wails
git checkout feature/open-files
cd .\v2\cmd\wails\
go install

then in some other place

wails init -n myproject -t react-ts

then modify wails.json to

{
  "$schema": "https://wails.io/schemas/config.v2.json",
  "name": "myproject",
  "outputfilename": "myproject",
  "frontend:install": "npm install",
  "frontend:build": "npm run build",
  "frontend:dev:watcher": "npm run dev",
  "frontend:dev:serverUrl": "auto",
  "author": {
    "name": "",
    "email": ""
  },
  "info": {
    "fileAssociations": [
      {
        "ext": "newdemo",
        "name": "NewDemo",
        "description": "new demo extension file",
        "iconName": "appicon",
        "role": "Editor"
      }
    ]
  }
}

run wails build -nsis
then install nsis package, create file with .newdemo extension and click on it

BTW, The same nsis script is used in Tauri and Electron.

@leaanthony I don't have anything to do here more. It's just works :)

@PylotLight
Copy link
Contributor

PylotLight commented Oct 21, 2023

Alrighty can confirm that worked quite well.
After installing new extension registry paths were created under:
Computer\HKEY_CLASSES_ROOT\WwWails\shell\open\command

Only issue im currently seeing its when trying to do multiple registrations, it seems it randomly has issues with some extensions.
e.g I created a build with this config, and the only one that doesn't seem to work is no.3 ppshenkin this time.

Due to the fact that this mostly seems to work with multiple other extensions that I've tested, I would call this good to go as far as my opinion goes, especially given we're not about to unit test every single possible windows extension as to what's not working for me on that one. (Could honestly be a special windows problem or my machine specifically, although I did try multiple rebuilds and reinstalls and that same extension continued to have issues)

{
        "ext": "newdemo",
        "name": "NewDemo",
        "description": "new demo extension file 1",
        "iconName": "appicon",
        "role": "Editor"
      },
      {
        "ext": "wwwails",
        "name": "WwWails",
        "description": "new demo extension file 2",
        "iconName": "appicon",
        "role": "Editor"
      },
      {
        "ext": "ppshenkin",
        "name": "PpShenkin",
        "description": "new demo extension file 3",
        "iconName": "appicon",
        "role": "Editor"
      },
      {
        "ext": "demo",
        "name": "DemoExtension",
        "description": "new demo extension file 4",
        "iconName": "appicon",
        "role": "Editor"
      },
      {
        "ext": "ppshen",
        "name": "Ppshen",
        "description": "new demo extension file 5",
        "iconName": "appicon",
        "role": "Editor"
      }

@leaanthony
Copy link
Member

We can always bugfix if needed. Thanks for this @APshenkin - really appreciate it.

@leaanthony leaanthony merged commit 6c46f6b into wailsapp:master Oct 21, 2023
10 of 12 checks passed
@APshenkin APshenkin deleted the feature/open-files branch October 23, 2023 10:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants