Skip to content

Commit

Permalink
Implement custom protocol association support (#3000)
Browse files Browse the repository at this point in the history
* implement MacOS openFile/openFiles events

* wip: windows file association

* fix macro import

* add file icon copy

* try copy icon

* keep only required part of scripts

* update config schema

* fix json

* set fileAssociation for mac via config

* proper iconName handling

* add fileAssociation icon generator

* fix file association icons bundle

* don't break compatibility

* remove mimeType as not supported linux for now

* add documentation

* adjust config schema

* restore formatting

* try implement single instance lock with params passing

* fix focusing

* fix focusing

* formatting

* use channel buffer for second instance events

* handle errors

* add comment

* remove unused option in file association

* wip: linux single instance lock

* wip: linux single instance

* some experiments with making window active

* try to use unminimise

* remove unused

* try present for window

* try present for window

* fix build

* cleanup

* cleanup

* implement single instance lock on mac os

* implement proper show for windows

* proper unmimimise

* get rid of openFiles mac os. change configuration structure

* remove unused channel

* remove unused function

* add documentation for single instance lock

* add PR link

* wip mac os deeplinks

* put custom url listner on top to catch link on app opening

* put custom url listner on top to catch link on app opening

* try add custom url windows

* adjust custom url

* add docs

* merge master

* update documentation

* add comment for darwin

* add PR link

* change naming

* change naming

* change naming

* change naming

* fix formatting

* fix naming

* Fix typo

---------

Co-authored-by: Lea Anthony <[email protected]>
  • Loading branch information
APshenkin and leaanthony authored Nov 2, 2023
1 parent e960798 commit ae688aa
Show file tree
Hide file tree
Showing 12 changed files with 346 additions and 0 deletions.
14 changes: 14 additions & 0 deletions v2/internal/frontend/desktop/darwin/CustomProtocol.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#ifndef CustomProtocol_h
#define CustomProtocol_h

#import <Cocoa/Cocoa.h>

extern void HandleCustomProtocol(char*);

@interface CustomProtocolSchemeHandler : NSObject
+ (void)handleGetURLEvent:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent;
@end

void StartCustomProtocolHandler(void);

#endif /* CustomProtocol_h */
20 changes: 20 additions & 0 deletions v2/internal/frontend/desktop/darwin/CustomProtocol.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#include "CustomProtocol.h"

@implementation CustomProtocolSchemeHandler
+ (void)handleGetURLEvent:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent {
[event paramDescriptorForKeyword:keyDirectObject];

NSString *urlStr = [[event paramDescriptorForKeyword:keyDirectObject] stringValue];

HandleCustomProtocol((char*)[[[event paramDescriptorForKeyword:keyDirectObject] stringValue] UTF8String]);
}
@end

void StartCustomProtocolHandler(void) {
NSAppleEventManager *appleEventManager = [NSAppleEventManager sharedAppleEventManager];

[appleEventManager setEventHandler:[CustomProtocolSchemeHandler class]
andSelector:@selector(handleGetURLEvent:withReplyEvent:)
forEventClass:kInternetEventClass
andEventID: kAEGetURL];
}
24 changes: 24 additions & 0 deletions v2/internal/frontend/desktop/darwin/frontend.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ package darwin
#cgo LDFLAGS: -framework Foundation -framework Cocoa -framework WebKit
#import <Foundation/Foundation.h>
#import "Application.h"
#import "CustomProtocol.h"
#import "WailsContext.h"
#include <stdlib.h>
Expand Down Expand Up @@ -39,6 +40,7 @@ var messageBuffer = make(chan string, 100)
var requestBuffer = make(chan webview.Request, 100)
var callbackBuffer = make(chan uint, 10)
var openFilepathBuffer = make(chan string, 100)
var openUrlBuffer = make(chan string, 100)
var secondInstanceBuffer = make(chan options.SecondInstanceData, 1)

type Frontend struct {
Expand Down Expand Up @@ -79,6 +81,9 @@ func NewFrontend(ctx context.Context, appoptions *options.App, myLogger *logger.
}
result.startURL, _ = url.Parse(startURL)

// this should be initialized as early as possible to handle first instance launch
C.StartCustomProtocolHandler()

if _starturl, _ := ctx.Value("starturl").(*url.URL); _starturl != nil {
result.startURL = _starturl
} else {
Expand Down Expand Up @@ -110,6 +115,7 @@ func NewFrontend(ctx context.Context, appoptions *options.App, myLogger *logger.
go result.startMessageProcessor()
go result.startCallbackProcessor()
go result.startFileOpenProcessor()
go result.startUrlOpenProcessor()
go result.startSecondInstanceProcessor()

return result
Expand All @@ -121,6 +127,12 @@ func (f *Frontend) startFileOpenProcessor() {
}
}

func (f *Frontend) startUrlOpenProcessor() {
for url := range openUrlBuffer {
f.ProcessOpenUrlEvent(url)
}
}

func (f *Frontend) startSecondInstanceProcessor() {
for secondInstanceData := range secondInstanceBuffer {
if f.frontendOptions.SingleInstanceLock != nil &&
Expand Down Expand Up @@ -385,6 +397,12 @@ func (f *Frontend) ProcessOpenFileEvent(filePath string) {
}
}

func (f *Frontend) ProcessOpenUrlEvent(url string) {
if f.frontendOptions.Mac != nil && f.frontendOptions.Mac.OnUrlOpen != nil {
f.frontendOptions.Mac.OnUrlOpen(url)
}
}

func (f *Frontend) Callback(message string) {
escaped, err := json.Marshal(message)
if err != nil {
Expand Down Expand Up @@ -434,3 +452,9 @@ func HandleOpenFile(filePath *C.char) {
goFilepath := C.GoString(filePath)
openFilepathBuffer <- goFilepath
}

//export HandleCustomProtocol
func HandleCustomProtocol(url *C.char) {
goUrl := C.GoString(url)
openUrlBuffer <- goUrl
}
7 changes: 7 additions & 0 deletions v2/internal/project/project.go
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,7 @@ type Info struct {
Copyright *string `json:"copyright"`
Comments *string `json:"comments"`
FileAssociations []FileAssociation `json:"fileAssociations"`
Protocols []Protocol `json:"protocols"`
}

type FileAssociation struct {
Expand All @@ -232,6 +233,12 @@ type FileAssociation struct {
Role string `json:"role"`
}

type Protocol struct {
Scheme string `json:"scheme"`
Description string `json:"description"`
Role string `json:"role"`
}

type Bindings struct {
TsGeneration TsGeneration `json:"ts_generation"`
}
Expand Down
17 changes: 17 additions & 0 deletions v2/pkg/buildassets/build/darwin/Info.dev.plist
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,23 @@
{{end}}
</array>
{{end}}
{{if .Info.Protocols}}
<key>CFBundleURLTypes</key>
<array>
{{range .Info.Protocols}}
<dict>
<key>CFBundleURLName</key>
<string>com.wails.{{.Scheme}}</string>
<key>CFBundleURLSchemes</key>
<array>
<string>{{.Scheme}}</string>
</array>
<key>CFBundleTypeRole</key>
<string>{{.Role}}</string>
</dict>
{{end}}
</array>
{{end}}
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsLocalNetworking</key>
Expand Down
17 changes: 17 additions & 0 deletions v2/pkg/buildassets/build/darwin/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -42,5 +42,22 @@
{{end}}
</array>
{{end}}
{{if .Info.Protocols}}
<key>CFBundleURLTypes</key>
<array>
{{range .Info.Protocols}}
<dict>
<key>CFBundleURLName</key>
<string>com.wails.{{.Scheme}}</string>
<key>CFBundleURLSchemes</key>
<array>
<string>{{.Scheme}}</string>
</array>
<key>CFBundleTypeRole</key>
<string>{{.Role}}</string>
</dict>
{{end}}
</array>
{{end}}
</dict>
</plist>
2 changes: 2 additions & 0 deletions v2/pkg/buildassets/build/windows/installer/project.nsi
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ Section
CreateShortCut "$DESKTOP\${INFO_PRODUCTNAME}.lnk" "$INSTDIR\${PRODUCT_EXECUTABLE}"

!insertmacro wails.associateFiles
!insertmacro wails.associateCustomProtocols

!insertmacro wails.writeUninstaller
SectionEnd
Expand All @@ -107,6 +108,7 @@ Section "uninstall"
Delete "$DESKTOP\${INFO_PRODUCTNAME}.lnk"

!insertmacro wails.unassociateFiles
!insertmacro wails.unassociateCustomProtocols

!insertmacro wails.deleteUninstaller
SectionEnd
29 changes: 29 additions & 0 deletions v2/pkg/buildassets/build/windows/installer/wails_tools.nsh
Original file line number Diff line number Diff line change
Expand Up @@ -218,3 +218,32 @@ RequestExecutionLevel "${REQUEST_EXECUTION_LEVEL}"
Delete "$INSTDIR\{{.IconName}}.ico"
{{end}}
!macroend

!macro CUSTOM_PROTOCOL_ASSOCIATE PROTOCOL DESCRIPTION ICON COMMAND
DeleteRegKey SHELL_CONTEXT "Software\Classes\${PROTOCOL}"
WriteRegStr SHELL_CONTEXT "Software\Classes\${PROTOCOL}" "" "${DESCRIPTION}"
WriteRegStr SHELL_CONTEXT "Software\Classes\${PROTOCOL}" "URL Protocol" ""
WriteRegStr SHELL_CONTEXT "Software\Classes\${PROTOCOL}\DefaultIcon" "" "${ICON}"
WriteRegStr SHELL_CONTEXT "Software\Classes\${PROTOCOL}\shell" "" ""
WriteRegStr SHELL_CONTEXT "Software\Classes\${PROTOCOL}\shell\open" "" ""
WriteRegStr SHELL_CONTEXT "Software\Classes\${PROTOCOL}\shell\open\command" "" "${COMMAND}"
!macroend

!macro CUSTOM_PROTOCOL_UNASSOCIATE PROTOCOL
DeleteRegKey SHELL_CONTEXT "Software\Classes\${PROTOCOL}"
!macroend

!macro wails.associateCustomProtocols
; Create custom protocols associations
{{range .Info.Protocols}}
!insertmacro CUSTOM_PROTOCOL_ASSOCIATE "{{.Scheme}}" "{{.Description}}" "$INSTDIR\${PRODUCT_EXECUTABLE},0" "$INSTDIR\${PRODUCT_EXECUTABLE} $\"%1$\""

{{end}}
!macroend

!macro wails.unassociateCustomProtocols
; Delete app custom protocol associations
{{range .Info.Protocols}}
!insertmacro CUSTOM_PROTOCOL_UNASSOCIATE "{{.Scheme}}"
{{end}}
!macroend
1 change: 1 addition & 0 deletions v2/pkg/options/mac/mac.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,6 @@ type Options struct {
//ActivationPolicy ActivationPolicy
About *AboutInfo
OnFileOpen func(filePath string) `json:"-"`
OnUrlOpen func(filePath string) `json:"-"`
//URLHandlers map[string]func(string)
}
Loading

0 comments on commit ae688aa

Please sign in to comment.