tauri-apps / tauri-apps/plugins-workspace
[feat][notification] Add XDG Desktop Portal backend on Linux
- Dominant language
- Rust
- Stars
- 1.8k
- Forks
- 602
- Avg merge
- 4d 14h
- Merged PRs (30d)
- 9
Description
## Describe the problem
On Linux, `tauri-plugin-notification` delivers notifications through the classic
`org.freedesktop.Notifications` D-Bus interface (via `notify-rust`). This works
in most cases, but it has two notable gaps:
1. **Flatpak sandboxes.** Inside a Flatpak sandbox the classic
`org.freedesktop.Notifications` name generally isn't reachable directly — the
sandbox expects notifications to go through the **XDG Desktop Portal**
(`org.freedesktop.portal.Notification`). This makes reliable notifications
awkward for Flatpak-packaged Tauri apps.
2. **Sessions where the classic name is owned by a non-rendering service.** On
some desktop sessions a process other than the compositor ends up owning
`org.freedesktop.Notifications`. It *accepts* the `Notify` call (returns a
notification id, so `.show()` succeeds) but never renders anything. Because
the call reports success, the failure is completely silent. Apps that use the
portal instead (e.g. sandboxed Telegram) keep working on the same session.
Related existing items: the Linux notification issue #1562 is currently labelled
`status: upstream`, and the notification RFC #2134 already notes that
`sendNotification()` gives the developer no signal about delivery — both touch
the same underlying area.
## Describe the solution you'd like
Add an **XDG Desktop Portal backend** for notifications on Linux, using
`org.freedesktop.portal.Notification.AddNotification`, as the path sandboxed
apps already take.
Suggested behaviour (opt-in / auto-detect rather than a hard replacement, since
the portal isn't a strict superset of the classic interface):
- Prefer the portal when it is available (or when running inside a Flatpak
sandbox), and fall back to the current `notify-rust` path otherwise.
- Optionally expose a config/method to force one backend, for apps that want
explicit control.
A minimal delivery call looks like this with `zbus` (blocking API shown for
brevity; the plugin could use its async connection):
```rust
use std::collections::HashMap;
use zbus::blocking::Connection;
use zbus::zvariant::Value;
let mut notification: HashMap<&str, Value> = HashMap::new();
notification.insert("title", Value::from(title));
notification.insert("body", Value::from(body));
notification.insert("priority", Value::from("normal")); // low | normal | high | urgent
let conn = Connection::session()?;
conn.call_method(
Some("org.freedesktop.portal.Desktop"),
"/org/freedesktop/portal/desktop",
Some("org.freedesktop.portal.Notification"),
"AddNotification",
&(id, notification), // id: unique per notification; reused id = replace
)?;
```
The portal also supports buttons/actions and icons, and (relevant to RFC #2134)
its action activation is a natural place to surface a real click/delivery
signal to the app.
## Alternatives considered
- **Keep the classic path only.** Leaves Flatpak apps without a first-class
notification path and keeps the silent-failure case above.
- **Fix it per-app.** Apps can bypass the plugin and call the portal themselves
(this is what prompted the request — it resolved the issue in a real app), but
that's boilerplate every Linux Tauri app would otherwise duplicate.
## Additional context
Happy to help with a PR if there's interest and agreement on the shape
(auto-detect vs. explicit backend selection). `zbus` is already in the Tauri
dependency tree on Linux, so this shouldn't add a new heavy dependency.
Contributor guide
Research direction
Start by locating the Linux notification plugin entry point and the existing notify-rust delivery path; inspect how zbus is already used in the Linux dependency tree. Define and test portal availability, Flatpak detection, fallback behavior, and backend selection before implementing the requested AddNotification path.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- linux, rust
- Domain
- desktop, operating-systems
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100