Skip to content

feat(deeplink): register and handle whatsapp:// links (all platforms) - #25

Open
karem505 wants to merge 2 commits into
masterfrom
feat/whatsapp-deeplink
Open

feat(deeplink): register and handle whatsapp:// links (all platforms)#25
karem505 wants to merge 2 commits into
masterfrom
feat/whatsapp-deeplink

Conversation

@karem505

Copy link
Copy Markdown
Owner

Closes #23 (WhatsApp links don't open the app / don't open the chat on Linux).

Root causes (two separate gaps)

  1. No registration: the generated Linux .desktop had no MimeType= entry, so xdg-mime query default x-scheme-handler/whatsapp returned empty after install — the OS had no reason to hand whatsapp:// links to whatRust.
  2. No handling: even after the reporter manually registered the handler, the app treated the second launch as a plain "show window" — the URL was dropped in the single-instance callback (show_main only), so the chat never opened.

What this PR does

Registration — one config, all platforms

tauri.conf.json gains:

"plugins": {
  "deep-link": { "desktop": [ { "schemes": ["whatsapp"] } ] }
}

The Tauri CLI maps this to MimeType=x-scheme-handler/whatsapp; in the generated .desktop for deb and AppImage, registry handlers in NSIS/MSI, and CFBundleURLTypes in the macOS Info.plist. Verified end-to-end on Linux: built a deb with this config and confirmed the packaged whatRust.desktop now contains MimeType=x-scheme-handler/whatsapp. The Flatpak ships its own .desktop file, so it gets the same MimeType (plus TryExec) added directly.

Handling

  • src-tauri/src/deeplink.rs (new): pure parser for whatsapp://send?phone=...&text=... — digits-only phone normalization (wa.me style), +/%XX decoding, case-insensitive scheme, byte-wise prefix compare (no panics on multi-byte input). 8 unit tests.
  • Single-instance callback: a second launch carrying a whatsapp:// URL routes to open_whatsapp_link() instead of plain show_main().
  • open_whatsapp_link: translates whatsapp://send?phone=1555...&text=hihttps://wa.me/1555...?text=hi and navigates the active account window. wa.me is the exact click-to-chat page WhatsApp Web handles natively, so the chat opens inside the logged-in session. Falls back to the first open account window, and while app-locked it shows the lock screen like every other reveal path.
  • on_navigation: now also rejects whatsapp:// inside the webview, so a stray in-page link can't bounce to the OS handler and re-launch the app.
  • whatsapp://send without a phone (share-sheet style) opens/focuses the app at the chat list.

Verification

  • cargo check clean; cargo test --lib 85 passed (8 new deeplink tests)
  • tauri build --debug --bundles deb succeeds and the deb's usr/share/applications/whatRust.desktop contains MimeType=x-scheme-handler/whatsapp (verified by extracting the package)
  • Flatpak manifest ships its own .desktop — updated with the same MimeType

Post-install note

xdg-mime query default x-scheme-handler/whatsapp returns whatRust after install for deb/AppImage (bundler wires update-desktop-database via the maintainer scripts); Flatpak exports the .desktop with the scheme through its own pipeline. On the Flatpak sandbox, incoming whatsapp:// launches go through flatpak run — the single-instance D-Bus name (already scoped to the Flatpak ID) hands the URL to the running instance.

…age never notifies (#3)

The v0.3.3 diagnostic build proved that on some Windows 11 installs
WhatsApp Web never calls window.Notification NOR
ServiceWorkerRegistration.showNotification (log: session start + AUMID
registered, but no `commands::notify` when messages arrive), so the
JS-driven path silently produces no toast. A page-injected script cannot
reach the service worker's own context, so the fallback must live in Rust.

- set_unread: detect unread-count rises from the <title> and raise a
  Rust-side toast (count only, generic body — no PII)
- notify: record_shim_notify() marks a page-driven toast so the fallback
  stays quiet for 10s (SHIM_GRACE) — no double toast for the same message
- maybe_unread_toast gates: app locked -> suppress; notifications
  disabled -> suppress; account window focused -> suppress; shim fired
  within grace -> suppress; same count within 90s -> suppress
- attribution + logging follow the existing no-PII dlog rules
…macOS) (#23)

Clicking a WhatsApp link (whatsapp://send?phone=...) did nothing: the
installers never registered the scheme, and even with a manual
xdg-mime default the app opened without opening the requested chat.

Registration (all platforms, one config):
- tauri.conf.json: plugins.deep-link.desktop = [{schemes: ["whatsapp"]}].
  The Tauri CLI turns this into MimeType=x-scheme-handler/whatsapp in the
  generated .desktop for deb AND AppImage, registry handlers in NSIS/MSI,
  and CFBundleURLTypes in the macOS Info.plist. Verified end-to-end on
  Linux: the built deb's whatRust.desktop now carries the MimeType line.
- Flatpak ships its own .desktop file: add the same MimeType (plus
  TryExec) there.

Handling:
- new deeplink.rs: pure URL parser (send?phone=&text=, digits-only
  normalisation, case-insensitive scheme, malformed-escape safe) with
  full unit-test coverage
- single-instance callback: a second launch carrying a whatsapp:// URL
  routes to open_whatsapp_link() instead of just show_main()
- open_whatsapp_link: translates the link to https://wa.me/<digits>
  (with ?text= carried over) and navigates the active account window —
  wa.me is the exact click-to-chat page WhatsApp Web handles natively.
  Lock-screen aware: while locked, shows the lock screen like every
  other reveal path.
- on_navigation: reject whatsapp:// in the webview so a stray in-page
  link can't bounce back to the OS handler and re-launch the app
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.

Opening WhatsApp links doesn't work correctly on Linux

1 participant