[V3] Add universal link support for macOS
Description
This PR backports https://github.com/wailsapp/wails/pull/4693/files to V3
Fixes # (issue)
Type of change
Please select the option that is relevant.
- [ ] Bug fix (non-breaking change which fixes an issue)
- [x] 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?
Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration using wails doctor.
- [ ] Windows
- [x] macOS
- [ ] Linux
If you checked Linux, please specify the distro and version.
Test Configuration
# System
┌──────────────────────────────────────────────────┐
| Name | MacOS |
| Version | 26.1 |
| ID | 25B78 |
| Branding | MacOS 26.1 |
| Platform | darwin |
| Architecture | arm64 |
| Apple Silicon | true |
| CPU | Apple M4 Max |
| CPU 1 | Apple M4 Max |
| CPU 2 | Apple M4 Max |
| GPU | 40 cores, Metal Support: Metal 4 |
| Memory | 128 GB |
└──────────────────────────────────────────────────┘
# Build Environment
┌─────────────────────────────────────────────────────────┐
| Wails CLI | v3.0.0-dev |
| Go Version | go1.24.0 |
| Revision | 4a445ce218b58db4a16ee8fa84eac0d7c9a69932 |
| Modified | false |
| -buildmode | exe |
| -compiler | gc |
| CGO_CFLAGS | |
| CGO_CPPFLAGS | |
| CGO_CXXFLAGS | |
| CGO_ENABLED | 1 |
| CGO_LDFLAGS | |
| GOARCH | arm64 |
| GOARM64 | v8.0 |
| GOOS | darwin |
| vcs | git |
| vcs.modified | false |
| vcs.revision | 4a445ce218b58db4a16ee8fa84eac0d7c9a69932 |
| vcs.time | 2025-08-04T22:42:25Z |
└─────────────────────────────────────────────────────────┘
# Dependencies
┌────────────────────────────────────────────────────────────────────────┐
| Xcode cli tools | 2416 |
| npm | 10.9.2 |
| *NSIS | Not Installed. Install with `brew install makensis`. |
| |
└─────────────────────── * - Optional Dependency ────────────────────────┘
Please paste the output of wails doctor. If you are unable to run this command, please describe your environment in as much detail as possible.
Checklist:
- [ ] I have updated
website/src/pages/changelog.mdxwith details of this PR - [x] My code follows the general coding style of this project
- [x] I have performed a self-review of my own code
- [x] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my feature works
- [x] New and existing unit tests pass locally with my changes
Summary by CodeRabbit
-
New Features
- Added Universal Link / web URL continuation on macOS so apps can open directly from supported web links.
-
Refactor
- Unified macOS URL handling and Apple Event processing, preserving existing window-reopen behavior.
-
Documentation
- Added cross-platform guidance for Universal Links and Web-to-App linking with configuration and hosting examples for macOS and Windows.
✏️ Tip: You can customize this high-level summary in your review settings.
Walkthrough
Renames the C-exported URL handler from HandleCustomProtocol to HandleOpenURL, adds macOS Universal Link support via application:continueUserActivity:restorationHandler:, updates Apple Event URL handling to call the new entry, removes an obsolete secure restorable state declaration, and adjusts a reopen method signature.
Changes
| Cohort / File(s) | Summary |
|---|---|
Go export rename v3/pkg/application/application_darwin.go |
Exported C bridge renamed: HandleCustomProtocol(urlCString *C.char) → HandleOpenURL(urlCString *C.char) (behavior unchanged). |
Objective‑C header updates v3/pkg/application/application_darwin_delegate.h |
Replaced extern void HandleCustomProtocol(char*); with extern void HandleOpenURL(char*);, removed - (BOOL)applicationSupportsSecureRestorableState:(NSApplication *)app;, added + (void)handleGetURLEvent:withReplyEvent:, and updated comment to include Universal Link support. |
Delegate implementation changes v3/pkg/application/application_darwin_delegate.m |
Added application:continueUserActivity:restorationHandler: to handle Universal Links (calls HandleOpenURL), updated Apple Event handler to call HandleOpenURL, and changed applicationShouldHandleReopen:hasVisibleWindows: first parameter from NSApplication * to NSNotification *. |
Docs & changelog v3/UNRELEASED_CHANGELOG.md, docs/src/content/docs/guides/custom-protocol-association.mdx |
Added changelog entry for macOS Universal Link support and expanded docs with Universal Links / Web-to-App linking guidance for macOS and Windows. |
Sequence Diagram(s)
sequenceDiagram
participant Apple as Apple OS
participant Delegate as AppDelegate
participant Go as Go runtime
rect rgb(248,249,255)
note over Apple,Delegate: Apple Event (Custom URL Scheme)
Apple->>Delegate: handleGetURLEvent:withReplyEvent:
Delegate->>Go: HandleOpenURL(urlString)
Go->>Go: Parse URL & emit ApplicationLaunchedWithUrl
end
rect rgb(240,255,245)
note over Apple,Delegate: Universal Link (NSUserActivity)
Apple->>Delegate: application:continueUserActivity:restorationHandler:
Delegate->>Delegate: verify NSUserActivityTypeBrowsingWeb & webpageURL
Delegate->>Go: HandleOpenURL(webpageURL)
Go->>Go: Parse URL & emit ApplicationLaunchedWithUrl
end
Estimated code review effort
🎯 3 (Moderate) | ⏱️ ~20 minutes
- Confirm
//exportname and C symbol match betweenapplication_darwin.goand header. - Review
application:continueUserActivity:restorationHandler:for nil checks and correct extraction ofwebpageURL. - Check callers and usages of
applicationShouldHandleReopen:for compatibility with the changed first parameter.
Suggested labels
Enhancement, size:M, lgtm
Suggested reviewers
- leaanthony
Poem
🐰 I hopped through Darwin's apple tree,
A tiny URL came bounding to me,
Schemes and web links now share one way,
HandleOpenURL saves the day—hooray! 🥕
Pre-merge checks and finishing touches
✅ Passed checks (3 passed)
| Check name | Status | Explanation |
|---|---|---|
| Title check | ✅ Passed | The title clearly and specifically describes the main change: adding universal link support for macOS in V3. |
| Description check | ✅ Passed | The description follows the template structure with completed sections including type of change (new feature), test configuration (macOS tested), and most checklist items. However, documentation updates and changelog.mdx update are marked incomplete. |
| Docstring Coverage | ✅ Passed | Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%. |
✨ Finishing touches
🧪 Generate unit tests (beta)
- [ ] Create PR with unit tests
- [ ] Post copyable unit tests in a comment
📜 Recent review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📥 Commits
Reviewing files that changed from the base of the PR and between 11b04a13daa080cfaecf2c321f213fd85b0fcb7a and dc5bb340528dab61f0ac3cc68c30d490d0548c4d.
📒 Files selected for processing (1)
-
v3/UNRELEASED_CHANGELOG.md(1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: APshenkin
Repo: wailsapp/wails PR: 4484
File: v2/internal/frontend/utils/urlValidator.go:25-31
Timestamp: 2025-08-08T13:15:20.339Z
Learning: In Wails v2 (PR wailsapp/wails#4484), for BrowserOpenURL URL validation (v2/internal/frontend/utils/urlValidator.go), maintainers (APshenkin) prefer not to restrict schemes to an http/https allowlist because supported schemes may vary. The allowlist suggestion is declined; continue with the existing denylist approach and generic validation.
📚 Learning: 2025-08-08T13:15:20.339Z
Learnt from: APshenkin
Repo: wailsapp/wails PR: 4484
File: v2/internal/frontend/utils/urlValidator.go:25-31
Timestamp: 2025-08-08T13:15:20.339Z
Learning: In Wails v2 (PR wailsapp/wails#4484), for BrowserOpenURL URL validation (v2/internal/frontend/utils/urlValidator.go), maintainers (APshenkin) prefer not to restrict schemes to an http/https allowlist because supported schemes may vary. The allowlist suggestion is declined; continue with the existing denylist approach and generic validation.
Applied to files:
-
v3/UNRELEASED_CHANGELOG.md
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: Run Go Tests v3 (windows-latest, 1.24)
- GitHub Check: Run Go Tests v3 (macos-latest, 1.24)
- GitHub Check: Run Go Tests v3 (ubuntu-latest, 1.24)
- GitHub Check: semgrep-cloud-platform/scan
🔇 Additional comments (1)
v3/UNRELEASED_CHANGELOG.md (1)
20-20: Changelog entry is well-formatted and compliant with guidelines.The entry follows the "Keep a Changelog" format, uses present tense, provides a clear description, includes PR reference, and maintains consistency with adjacent entries in the file.
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.
Comment @coderabbitai help to get the list of available commands and usage tips.
Thanks 🙏 Please could you add an entry to the changelog located at v3/UNRELEASED_CHANGELOG.md? Thanks!
@leaanthony added
Would it be possible to have some short documentation on how to use this feature? I'm ok having that in a later PR if we make a ticket for it 👍 Will be updating the docs significantly over the weekend so I'm ok to delay it 👍
@leaanthony happy to add docs for v3, however can't see v3 site docs in repo. Where should I add it?
@leaanthony happy to add docs for v3, however can't see v3 site docs in repo. Where should I add it?
Amazing! 🎉 They are in docs at the project root. The taskfile here docs/Taskfile.yml has everything you need. Just pick your package manager. Use task setup and you should be good to go 👍
@leaanthony added
@leaanthony added. Was blind to not find folder with docs 😀
Quality Gate passed
Issues
0 New issues
0 Accepted issues
Measures
0 Security Hotspots
0.0% Coverage on New Code
0.0% Duplication on New Code
Thanks for your patience again @APshenkin :pray:
@leaanthony no problem, thank you for cooperation!