Native Integrations — OS Features
Native Integrations — OS Features Frequently Used in Desktop and Mobile
What sets desktop and mobile apps apart from web apps is usually OS integration. Toast notifications, system trays, file dialogs, clipboard, autostart, global shortcuts, and deep links are frequent items in that list.
1. Toast notifications
OS standards:
| Platform | Mechanism |
|---|---|
| Windows | Toast Notifications (Windows 10+, ToastNotificationManager). XML template based. |
| macOS | User Notifications framework (10.14+). |
| Linux | Desktop Notifications Specification (freedesktop.org, D-Bus). |
| Android | NotificationManager + Channel (8.0+, 2017). |
| iOS | UserNotifications framework (10+, 2016). |
Each OS has different parameters and behavior. Plain title and body are common, but action buttons, images, and sound differ per OS.
Browsers use the OS notification system as the host. That is, Chrome notifications eventually become Windows Toast or macOS notifications.
// Web Notifications API
if (Notification.permission === "default") {
await Notification.requestPermission()
}
new Notification("제목", { body: "본문", icon: "/icon.png" })
Tauri's tauri-plugin-notification:
import { sendNotification, isPermissionGranted, requestPermission }
from "@tauri-apps/plugin-notification"
let granted = await isPermissionGranted()
if (!granted) granted = (await requestPermission()) === "granted"
if (granted) sendNotification({ title: "완료", body: "저장됨" })
Android 13+ requires the POST_NOTIFICATIONS permission separately.
2. System tray
A small icon in the taskbar (Windows), menu bar (macOS), or system tray (Linux). It is common as a marker that an app stays alive in the background even when closed.
use tauri::tray::TrayIconBuilder;
use tauri::menu::{Menu, MenuItem};
let menu = Menu::with_items(app, &[
&MenuItem::with_id(app, "show", "보이기", true, None::<&str>)?,
&MenuItem::with_id(app, "quit", "종료", true, None::<&str>)?,
])?;
TrayIconBuilder::new()
.icon(app.default_window_icon().unwrap().clone())
.menu(&menu)
.on_menu_event(|app, event| match event.id.as_ref() {
"quit" => app.exit(0),
"show" => { /* show window */ }
_ => {}
})
.build(app)?;
Per-platform differences:
- Linux — no unified tray standard. Dependence on KDE/GNOME extensions is common.
- macOS — menu bar icons usually recommend monochrome (template image).
- Windows — taskbar notification area. Frequently hidden by users.
3. File dialogs
OS-standard open/save dialogs.
Standards:
- Windows — Common Item Dialog (Win32 IFileDialog).
- macOS — NSOpenPanel, NSSavePanel.
- Linux — GTK FileChooser or portal (xdg-desktop-portal).
In web standards, File System Access API (Chrome 86+, 2020) exists, but Safari and Firefox support is limited.
tauri-plugin-dialog:
import { open, save, message, ask, confirm } from "@tauri-apps/plugin-dialog"
const file = await open({
multiple: false,
filters: [{ name: "이미지", extensions: ["png", "jpg", "webp"] }],
})
const path = await save({
defaultPath: "export.json",
filters: [{ name: "JSON", extensions: ["json"] }],
})
await message("저장 완료", { kind: "info" })
const yes = await ask("정말 삭제할까요?", { kind: "warning" })
4. Clipboard
Standards:
- Web —
navigator.clipboard(Async Clipboard API). Requires user gesture, HTTPS, and permission. - Windows — OpenClipboard/SetClipboardData (Win32).
- macOS — NSPasteboard.
tauri-plugin-clipboard-manager:
import { writeText, readText, writeImage }
from "@tauri-apps/plugin-clipboard-manager"
await writeText("복사할 텍스트")
const t = await readText()
Images and registering multiple formats simultaneously are also possible.
5. Autostart
Register the app to launch when the OS user logs in.
| Platform | Mechanism |
|---|---|
| Windows | Registry HKCU\Software\Microsoft\Windows\CurrentVersion\Run. |
| macOS | LaunchAgents (~/Library/LaunchAgents/*.plist) or SMAppService (13+). |
| Linux | XDG autostart (~/.config/autostart/*.desktop). |
tauri-plugin-autostart:
import { enable, disable, isEnabled } from "@tauri-apps/plugin-autostart"
if (!(await isEnabled())) await enable()
Verifying that it is added at install and cleaned up on uninstall is needed (especially the Windows registry).
6. Global shortcuts
A shortcut where the OS captures the input and invokes a callback even when the app does not have focus.
Standards:
- Windows — RegisterHotKey (Win32).
- macOS — NSEvent global monitor or Carbon RegisterEventHotKey. Accessibility permission needed.
- Linux — depends on the desktop environment. Wayland uses per-environment portals.
tauri-plugin-global-shortcut:
import { register, unregister } from "@tauri-apps/plugin-global-shortcut"
await register("CommandOrControl+Shift+K", () => {
// open search bar, etc.
})
CommandOrControl maps to ⌘ on macOS and Ctrl on other OSes.
7. Deep links (URL schemes)
Open the app from outside via custom URLs like myapp://post/123.
Standards:
- Windows — register under
HKCR\<scheme>in the registry. - macOS —
CFBundleURLTypesinInfo.plist. - Linux —
MimeTypein.desktop+xdg-mime. - Android —
<intent-filter>withandroid:scheme="myapp". - iOS —
CFBundleURLTypesinInfo.plistor Universal Links.
For safer integration with the web, Universal Links (iOS) and App Links (Android) were introduced (the app proves domain ownership).
import { onOpenUrl, getCurrent } from "@tauri-apps/plugin-deep-link"
await onOpenUrl((urls) => {
for (const u of urls) console.log("opened:", u)
})
const initial = await getCurrent() // when the app started via deep link
8. Window and instance management
- Single instance (focus the existing window instead of opening a new one if already running) —
tauri-plugin-single-instance. - Window state save/restore (remember size and position) —
tauri-plugin-window-state.
9. Plugin mapping
| Feature | Tauri plugin | Notes |
|---|---|---|
| Notifications | tauri-plugin-notification |
Android 13+ permission separate. |
| Tray | core (tauri::tray) |
Linux compatibility caution. |
| Dialog | tauri-plugin-dialog |
Use filter to limit extensions. |
| Filesystem | tauri-plugin-fs |
Use scope to limit paths. |
| Clipboard | tauri-plugin-clipboard-manager |
Image support. |
| Autostart | tauri-plugin-autostart |
Verify install/uninstall cleanup. |
| Global shortcut | tauri-plugin-global-shortcut |
macOS accessibility permission. |
| Deep link | tauri-plugin-deep-link |
OS registration declaration. |
| Single instance | tauri-plugin-single-instance |
Recover window focus. |
| Window state | tauri-plugin-window-state |
Save position across multiple displays. |
| Shell command | tauri-plugin-shell |
Run external programs. |
| Updater | tauri-plugin-updater |
Signing key storage matters. |
| HTTP | tauri-plugin-http |
Use scope to limit domains. |
Each plugin's permission must be declared in the capabilities JSON for the call to pass.
10. Common pitfalls
Missing permissions — commands not in capabilities are rejected at runtime.
Linux divergence — tray, deep link, and autostart behave differently per desktop environment.
macOS code signing and notarization — notifications, global shortcuts, and accessibility permissions can be denied for unsigned apps.
Windows notifications not appearing — Focus Assist setting. Without an AppUserModelID, they may not display.
Deep link double dispatch — handle both the URL at start time (getCurrent) and the URL during runtime (onOpenUrl).
Single instance + deep link — the second instance should not appear and must pass the URL to the first.
Closing thoughts
Native integration carries a heavy burden if you handle OS-specific standards directly. The strength is that one Tauri plugin line abstracts away the OS differences. The permission model (capabilities) declaration feels burdensome at first, but it is a major gain for security.
Next
- loading-ux
We refer to Tauri Plugins, tauri-plugin-notification, tauri-plugin-dialog, tauri-plugin-deep-link, Windows Toast XML, Apple UserNotifications, freedesktop Notifications, Android Notifications, MDN Notifications, MDN Clipboard, and File System Access API.