5
0
mirror of https://github.com/wailsapp/wails.git synced 2025-05-02 10:21:20 +08:00
This commit is contained in:
Lea Anthony 2025-01-22 21:51:35 +11:00
parent 276a1a22a5
commit 7ebb000253
No known key found for this signature in database
GPG Key ID: 33DAF7BB90A58405
8 changed files with 274 additions and 1 deletions

View File

@ -0,0 +1,189 @@
# Custom Protocol Scheme association
Custom Protocols feature allows you to associate specific custom protocol with your app so that when users open links with this protocol,
your app is launched to handle them. This can be particularly useful to connect your desktop app with your web app.
In this guide, we'll walk through the steps to implement custom protocols in Wails app.
## Set Up Custom Protocol Schemes Association:
To set up custom protocol, you need to modify your application's wails.json file.
In "info" section add a "protocols" section specifying the protocols your app should be associated with.
For example:
```json
{
"info": {
"protocols": [
{
"scheme": "myapp",
"description": "My App Protocol",
"role": "Editor"
}
]
}
}
```
| Property | Description |
|:------------|:--------------------------------------------------------------------------------------|
| scheme | Custom Protocol scheme. e.g. myapp |
| description | Windows-only. The description. |
| role | macOS-only. The apps role with respect to the type. Corresponds to CFBundleTypeRole. |
## Platform Specifics:
### macOS
When you open custom protocol with your app, the system will launch your app and call the `OnUrlOpen` function in your Wails app. Example:
```go title="main.go"
func main() {
// Create application with options
err := wails.Run(&options.App{
Title: "wails-open-file",
Width: 1024,
Height: 768,
AssetServer: &assetserver.Options{
Assets: assets,
},
BackgroundColour: &options.RGBA{R: 27, G: 38, B: 54, A: 1},
Mac: &mac.Options{
OnUrlOpen: func(url string) { println(url) },
},
Bind: []interface{}{
app,
},
})
if err != nil {
println("Error:", err.Error())
}
}
```
### Windows
On Windows Custom Protocol Schemes is supported only with NSIS installer. During installation, the installer will create a
registry entry for your schemes. When you open url with your app, new instance of app is launched and url is passed
as argument to your app. To handle this you should parse command line arguments in your app. Example:
```go title="main.go"
func main() {
argsWithoutProg := os.Args[1:]
if len(argsWithoutProg) != 0 {
println("launchArgs", argsWithoutProg)
}
}
```
You also can enable single instance lock for your app. In this case, when you open url with your app, new instance of app is not launched
and arguments are passed to already running instance. Check single instance lock guide for details. Example:
```go title="main.go"
func main() {
// Create application with options
err := wails.Run(&options.App{
Title: "wails-open-file",
Width: 1024,
Height: 768,
AssetServer: &assetserver.Options{
Assets: assets,
},
BackgroundColour: &options.RGBA{R: 27, G: 38, B: 54, A: 1},
SingleInstanceLock: &options.SingleInstanceLock{
UniqueId: "e3984e08-28dc-4e3d-b70a-45e961589cdc",
OnSecondInstanceLaunch: app.onSecondInstanceLaunch,
},
Bind: []interface{}{
app,
},
})
}
```
### Linux
Currently, Wails doesn't support bundling for Linux. So, you need to create file associations manually.
For example if you distribute your app as a .deb package, you can create file associations by adding required files in you bundle.
You can use [nfpm](https://nfpm.goreleaser.com/) to create .deb package for your app.
1. Create a .desktop file for your app and specify file associations there (note that `%u` is important in Exec). Example:
```ini
[Desktop Entry]
Categories=Office
Exec=/usr/bin/wails-open-file %u
Icon=wails-open-file.png
Name=wails-open-file
Terminal=false
Type=Application
MimeType=x-scheme-handler/myapp;
```
2. Prepare postInstall/postRemove scripts for your package. Example:
```sh
# reload desktop database to load app in list of available
update-desktop-database /usr/share/applications
```
3. Configure nfpm to use your scripts and files. Example:
```yaml
name: "wails-open-file"
arch: "arm64"
platform: "linux"
version: "1.0.0"
section: "default"
priority: "extra"
maintainer: "FooBarCorp <FooBarCorp@gmail.com>"
description: "Sample Package"
vendor: "FooBarCorp"
homepage: "http://example.com"
license: "MIT"
contents:
- src: ../bin/wails-open-file
dst: /usr/bin/wails-open-file
- src: ./main.desktop
dst: /usr/share/applications/wails-open-file.desktop
- src: ../appicon.svg
dst: /usr/share/icons/hicolor/scalable/apps/wails-open-file.svg
# copy icons to Yaru theme as well. For some reason Ubuntu didn't pick up fileicons from hicolor theme
- src: ../appicon.svg
dst: /usr/share/icons/Yaru/scalable/apps/wails-open-file.svg
scripts:
postinstall: ./postInstall.sh
postremove: ./postRemove.sh
```
6. Build your .deb package using nfpm:
```sh
nfpm pkg --packager deb --target .
```
7. Now when your package is installed, your app will be associated with custom protocol scheme. When you open url with your app,
new instance of app is launched and file path is passed as argument to your app.
To handle this you should parse command line arguments in your app. Example:
```go title="main.go"
func main() {
argsWithoutProg := os.Args[1:]
if len(argsWithoutProg) != 0 {
println("launchArgs", argsWithoutProg)
}
}
```
You also can enable single instance lock for your app. In this case, when you open url with your app, new instance of app is not launched
and arguments are passed to already running instance. Check single instance lock guide for details. Example:
```go title="main.go"
func main() {
// Create application with options
err := wails.Run(&options.App{
Title: "wails-open-file",
Width: 1024,
Height: 768,
AssetServer: &assetserver.Options{
Assets: assets,
},
BackgroundColour: &options.RGBA{R: 27, G: 38, B: 54, A: 1},
SingleInstanceLock: &options.SingleInstanceLock{
UniqueId: "e3984e08-28dc-4e3d-b70a-45e961589cdc",
OnSecondInstanceLaunch: app.onSecondInstanceLaunch,
},
Bind: []interface{}{
app,
},
})
}
```

View File

@ -126,6 +126,7 @@ type FileAssociation struct {
type UpdateConfig struct {
UpdateBuildAssetsOptions
FileAssociations []FileAssociation `yaml:"fileAssociations"`
Protocols []Protocol `yaml:"protocols"`
}
type WailsConfig struct {
@ -139,6 +140,13 @@ type WailsConfig struct {
Version string `yaml:"version"`
} `yaml:"info"`
FileAssociations []FileAssociation `yaml:"fileAssociations"`
Protocols []Protocol `yaml:"protocols"`
}
type Protocol struct {
Scheme string `json:"scheme"`
Role string `json:"role"`
Description string `json:"description"`
}
func UpdateBuildAssets(options *UpdateBuildAssetsOptions) error {
@ -169,6 +177,7 @@ func UpdateBuildAssets(options *UpdateBuildAssetsOptions) error {
options.ProductCopyright = wailsConfig.Info.Copyright
options.ProductComments = wailsConfig.Info.Comments
options.ProductVersion = wailsConfig.Info.Version
config.Protocols = wailsConfig.Protocols
config.FileAssociations = wailsConfig.FileAssociations
}

View File

@ -44,7 +44,7 @@ dev_mode:
type: primary
# File Associations
# More information at: https://v3alpha.wails.io/noit/done/yet
# More information at: https://v3.wails.io/not/done/yet
fileAssociations:
# - ext: wails
# name: Wails
@ -57,6 +57,14 @@ fileAssociations:
# iconName: jpegFileIcon
# role: Editor
# Custom URL Protocols
# A list of custom URL protocols associated with this application
# More information at: https://v3.wails.io/not/done/yet
protocols:
# - scheme: "magnet"
# description: "Magnet URI Scheme"
# role: "Editor"
# Other data
other:
- name: My Other Data

View File

@ -92,6 +92,7 @@ Section
CreateShortCut "$DESKTOP\${INFO_PRODUCTNAME}.lnk" "$INSTDIR\${PRODUCT_EXECUTABLE}"
!insertmacro wails.associateFiles
!insertmacro wails.associateCustomProtocols
!insertmacro wails.writeUninstaller
SectionEnd
@ -107,6 +108,7 @@ Section "uninstall"
Delete "$DESKTOP\${INFO_PRODUCTNAME}.lnk"
!insertmacro wails.unassociateFiles
!insertmacro wails.unassociateCustomProtocols
!insertmacro wails.deleteUninstaller
SectionEnd

View File

@ -28,5 +28,22 @@
<key>NSAllowsLocalNetworking</key>
<true/>
</dict>
{{if .Protocols}}
<key>CFBundleURLTypes</key>
<array>
{{range .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>

View File

@ -23,5 +23,22 @@
<string>true</string>
<key>NSHumanReadableCopyright</key>
<string>{{.ProductCopyright}}</string>
{{if .Protocols}}
<key>CFBundleURLTypes</key>
<array>
{{range .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>

View File

@ -215,4 +215,33 @@ RequestExecutionLevel "${REQUEST_EXECUTION_LEVEL}"
!insertmacro APP_UNASSOCIATE "{{.Ext}}" "{{.Name}}"
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 .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 .Protocols}}
!insertmacro CUSTOM_PROTOCOL_UNASSOCIATE "{{.Scheme}}"
{{end}}
!macroend

View File

@ -195,6 +195,8 @@ type MacOptions struct {
ActivationPolicy ActivationPolicy
// If set to true, the application will terminate when the last window is closed.
ApplicationShouldTerminateAfterLastWindowClosed bool
// OnURLOpen is a function that is called when the user opens an associated url such as `magnet://l234i2li34h`.
OnUrlOpen func(filePath string)
}
/****** Windows Options *******/