Skip to main content

Crate mac_usernotifications

Crate mac_usernotifications 

Source
Expand description

A Rust wrapper around UNUserNotificationCenter, designed for use in notify-rust.

§Bundling Requirement

Contrary to mac-notification-sys, this crate requires that the binary is bundled and be code-signed, an ad-hoc signature is sufficient. See the bundled examples for how to set this up with cargo-bundle.

§Quick start

// 1. verify the process has a bundle identifier
check_bundle().unwrap();

// 2. verify user gave permission
blocking::request_auth().unwrap();

// 3a. fire-and-forgeta (handle.notification_id() has the UUID for later use)
let handle = Notification::new()
    .title("Hello")
    .message("World")
    .send_blocking()
    .unwrap();

println!("notification id: {}", handle.notification_id());

// 3b. actionable: use block_on_main to drive the run loop while waiting for the response
let response = block_on_main(async {
    Notification::new()
        .title("Pick one")
        .action(Action::button("ok", "OK"))
        .action(Action::button("cancel", "Cancel"))
        .timeout(Duration::from_secs(30)) // 4. always set a timeout for actionable notifications
        .send()
        .await?
        .response()
        .await
}).unwrap();

println!("User chose: {}", response.action_identifier);

§Threading model

macOS delivers didReceiveNotificationResponse on the main thread’s NSRunLoop, regardless of which thread the delegate was registered from (Apple docs). The main thread’s run loop must be spinning whenever you expect the user to interact with a notification.

This crate uses a lazily-created worker thread for all Objective-C calls, to enable async APIs.

§GUI apps (AppKit / SwiftUI / Tauri)

The framework drives the main run loop automatically. send, send_blocking, and response().await all work from any thread without extra setup.

§Headless / background-only apps

No framework drives the run loop, so you must do it yourself. Use block_on_main to run an async expression on the main thread while pumping the run loop:

let response = block_on_main(async {
    Notification::new()
        .title("Hello")
        .send().await?
        .response().await
});

Or for Tokio, keep the main thread free for [run_main_loop_while] and run the runtime entirely on background threads. See examples/simple_tokio.rs.

§Known pitfalls

ScenarioSymptomFix
response().await called with nothing pumping the main run loopfuture never resolvesUse block_on_main or [run_main_loop_while] on the main thread
#[tokio::main] — main thread is inside Tokiocallbacks never fireUse new_multi_thread() and keep main free for [run_main_loop_while]
User clicks “Clear All” in Notification Centerfuture never resolvesAlways set a timeout via Notification::timeout for actionable notifications

Re-exports§

pub use crate::action::Action;
pub use crate::response::CloseReason;
pub use crate::response::NotificationResponse;

Modules§

action
Notification action buttons and the categories that group them.
blocking
Blocking wrappers for fire-and-forget operations.
response
The response a user gave to a notification.
sound
Sound constants for macOS user notifications.

Structs§

Notification
A notification with title, body, and optional subtitle / sound.
NotificationHandle
A notification that has been delivered to the system but not yet responded to.
NotificationSettings
The current notification settings for the app.

Enums§

AuthorizationStatus
The app’s authorization to post notifications.
Error
Errors returned by this crate.
InterruptionLevel
Controls how a notification interrupts the user.
NotificationSettingStatus
Whether a specific notification feature is enabled.

Functions§

block_on
Blocks the current thread on a future.
block_on_current
Block on the future, using block_on_main if the current thread is the main thread.
block_on_main
Run a future to completion on the main thread while pumping NSRunLoop.
cancel_pending
Cancel a pending notification.
check_bundle
Verify the process has a bundle identifier.
close_delivered
Remove a delivered notification.
get_delivered_notification_ids
Return the identifiers of all delivered notifications currently visible in Notification Center.
get_notification_settings
Query the current notification authorization settings without prompting.
get_pending_notification_ids
Return the identifiers of all pending (scheduled but not yet delivered) notifications.
request_auth
Ask for permission to display notifications.
send
Schedule a notification for immediate delivery.
send_with_actions
Schedule an actionable notification and wait for the user’s response.