네이티브 통합 — OS 기능들
네이티브 통합 — 데스크탑·모바일에서 자주 쓰이는 OS 기능
데스크탑·모바일 앱이 웹 앱과 차별되는 자리는 보통 OS 통합에 있습니다. 토스트 알림·시스템 트레이·파일 다이얼로그·클립보드·자동시작·전역 단축키·딥링크가 그 목록의 자주 등장하는 항목입니다.
1. 토스트 알림
OS 별 표준:
| 플랫폼 | 메커니즘 |
|---|---|
| Windows | Toast Notifications (Windows 10+, ToastNotificationManager). XML 템플릿 기반. |
| 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). |
각 OS 가 다른 파라미터·동작을 가집니다. 단순 제목/본문은 공통이지만 액션 버튼·이미지·소리는 OS 별로 다릅니다.
브라우저는 OS 의 알림 시스템을 호스트로 사용합니다. 즉 Chrome 의 알림은 결국 Windows Toast 또는 macOS 알림이 됩니다.
// Web Notifications API
if (Notification.permission === "default") {
await Notification.requestPermission()
}
new Notification("제목", { body: "본문", icon: "/icon.png" })
Tauri 의 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+ 는 POST_NOTIFICATIONS 권한이 별도 필요합니다.
2. 시스템 트레이
작업표시줄 (Windows) · 메뉴바 (macOS) · 시스템 트레이 (Linux) 의 작은 아이콘. 닫아도 백그라운드에 살아있는 앱의 표지로 흔합니다.
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" => { /* 윈도우 표시 */ }
_ => {}
})
.build(app)?;
플랫폼별 차이:
- Linux — 트레이 표준이 통일되지 않습니다. KDE/GNOME 확장 의존이 흔합니다.
- macOS — 메뉴바 아이콘은 보통 모노크롬 (template image) 가 권장됩니다.
- Windows — 작업표시줄 알림 영역. 사용자가 숨기는 경우 흔합니다.
3. 파일 다이얼로그
OS 표준 파일 열기/저장 다이얼로그.
표준:
- Windows — Common Item Dialog (Win32 IFileDialog).
- macOS — NSOpenPanel · NSSavePanel.
- Linux — GTK FileChooser 또는 portal (xdg-desktop-portal).
웹 표준에는 File System Access API (Chrome 86+, 2020) 가 있지만 Safari · Firefox 지원이 제한적입니다.
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. 클립보드
표준:
- 웹 —
navigator.clipboard(Async Clipboard API). 사용자 제스처·HTTPS·권한 필요. - 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()
이미지·여러 형식 동시 등록도 가능합니다.
5. 자동시작
OS 로그인 시 앱이 함께 시작되도록 등록.
| 플랫폼 | 메커니즘 |
|---|---|
| Windows | 레지스트리 HKCU\Software\Microsoft\Windows\CurrentVersion\Run. |
| macOS | LaunchAgents (~/Library/LaunchAgents/*.plist) 또는 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()
설치 시점에 추가, 제거 시 정리되는지 검증이 필요합니다 (특히 Windows 레지스트리).
6. 전역 단축키
앱이 포커스 없을 때도 OS 가 캡처해 콜백을 호출하는 단축키.
표준:
- Windows — RegisterHotKey (Win32).
- macOS — NSEvent global monitor 또는 Carbon RegisterEventHotKey. 접근성 권한 필요.
- Linux — 데스크탑 환경 의존. Wayland 는 환경별 portal.
tauri-plugin-global-shortcut:
import { register, unregister } from "@tauri-apps/plugin-global-shortcut"
await register("CommandOrControl+Shift+K", () => {
// 검색창 열기 등
})
CommandOrControl 은 macOS 에서는 ⌘, 다른 OS 에서는 Ctrl 로 매핑됩니다.
7. 딥링크 (URL 스킴)
myapp://post/123 같은 커스텀 URL 로 외부에서 앱을 엽니다.
표준:
- Windows — 레지스트리
HKCR\<scheme>등록. - macOS —
Info.plist의CFBundleURLTypes. - Linux —
.desktop의 MimeType +xdg-mime. - Android —
<intent-filter>android:scheme="myapp". - iOS —
Info.plist의CFBundleURLTypes또는 Universal Links.
웹과의 안전한 통합을 위해 Universal Links (iOS) · App Links (Android) 가 도입됐습니다 (앱이 도메인 소유를 증명).
import { onOpenUrl, getCurrent } from "@tauri-apps/plugin-deep-link"
await onOpenUrl((urls) => {
for (const u of urls) console.log("열림:", u)
})
const initial = await getCurrent() // 앱이 딥링크로 시작된 경우
8. 윈도우·창 관리
- 단일 인스턴스 (이미 떠 있는 앱이면 새로 띄우지 않고 기존 창에 포커스) —
tauri-plugin-single-instance. - 윈도우 상태 저장/복원 (크기·위치 기억) —
tauri-plugin-window-state.
9. 플러그인 매핑
| 기능 | Tauri 플러그인 | 비고 |
|---|---|---|
| 알림 | tauri-plugin-notification |
Android 13+ 권한 별도. |
| 트레이 | core (tauri::tray) |
Linux 호환 주의. |
| 다이얼로그 | tauri-plugin-dialog |
filter 로 확장자 제한. |
| 파일시스템 | tauri-plugin-fs |
scope 로 경로 제한. |
| 클립보드 | tauri-plugin-clipboard-manager |
이미지 지원. |
| 자동시작 | tauri-plugin-autostart |
설치/제거 정리 검증. |
| 전역 단축키 | tauri-plugin-global-shortcut |
macOS 접근성 권한. |
| 딥링크 | tauri-plugin-deep-link |
OS 등록 선언. |
| 단일 인스턴스 | tauri-plugin-single-instance |
윈도우 포커스 회복. |
| 창 상태 | tauri-plugin-window-state |
다중 디스플레이 위치 저장. |
| 셸 명령 | tauri-plugin-shell |
외부 프로그램 실행. |
| 업데이트 | tauri-plugin-updater |
서명 키 보관 중요. |
| HTTP | tauri-plugin-http |
scope 로 도메인 제한. |
각 플러그인은 capabilities JSON 에 권한을 명시해야 호출이 통과합니다.
10. 자주 걸리는 자리
권한 누락 — capabilities 에 없는 명령은 런타임에 거부됩니다.
Linux 의 분화 — 트레이·딥링크·자동시작은 데스크탑 환경마다 동작이 다릅니다.
macOS 코드 서명·notarization — 알림·전역 단축키·접근성 권한은 서명 없는 앱에서 거부될 수 있습니다.
Windows 알림이 안 뜸 — 집중 도움 설정. AppUserModelID 가 없으면 표시 안 될 수 있습니다.
딥링크 이중 발사 — 시작 시점 URL (getCurrent) 과 실행 중 URL (onOpenUrl) 두 경로 모두 처리합니다.
단일 인스턴스 + 딥링크 — 두 번째 실행 인스턴스가 뜨지 않고 첫 인스턴스에 URL 을 전달해야 합니다.
하고픈 말
네이티브 통합은 OS 별 표준이 다양해 직접 다루면 부담이 큽니다. Tauri 플러그인 한 줄로 OS 차이가 추상화되는 자리가 큰 강점입니다. 권한 모델 (capabilities) 명시는 처음에 부담스럽지만 보안에는 큰 이득이 됩니다.
Next
- loading-ux
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 · File System Access API 를 참고합니다.