Skip to main content

tauri_plugin_notification/
lib.rs

1// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
2// SPDX-License-Identifier: Apache-2.0
3// SPDX-License-Identifier: MIT
4
5//! Send message notifications (brief auto-expiring OS window element) to your user. Can also be used with the Notification Web API.
6//!
7//! ## Cargo features
8//!
9//! - **windows7-compat**: Deprecated and does nothing, since Tauri no longer supports Windows 7.
10
11#![doc(
12    html_logo_url = "https://github.com/tauri-apps/tauri/raw/dev/app-icon.png",
13    html_favicon_url = "https://github.com/tauri-apps/tauri/raw/dev/app-icon.png"
14)]
15
16use serde::Serialize;
17#[cfg(desktop)]
18use tauri::AppHandle;
19#[cfg(mobile)]
20use tauri::plugin::PluginHandle;
21use tauri::{
22    Manager, Runtime,
23    plugin::{Builder, TauriPlugin},
24};
25
26pub use models::*;
27pub use tauri::plugin::PermissionState;
28
29#[cfg(desktop)]
30mod desktop;
31#[cfg(mobile)]
32mod mobile;
33
34mod commands;
35mod error;
36mod models;
37
38pub use error::{Error, Result};
39
40#[cfg(desktop)]
41pub use desktop::Notification;
42#[cfg(mobile)]
43pub use mobile::Notification;
44
45/// The notification builder.
46#[derive(Debug)]
47pub struct NotificationBuilder<R: Runtime> {
48    #[cfg(desktop)]
49    app: AppHandle<R>,
50    #[cfg(mobile)]
51    handle: PluginHandle<R>,
52    pub(crate) data: NotificationData,
53}
54
55impl<R: Runtime> NotificationBuilder<R> {
56    #[cfg(desktop)]
57    fn new(app: AppHandle<R>) -> Self {
58        Self {
59            app,
60            data: Default::default(),
61        }
62    }
63
64    #[cfg(mobile)]
65    fn new(handle: PluginHandle<R>) -> Self {
66        Self {
67            handle,
68            data: Default::default(),
69        }
70    }
71
72    /// Sets the notification identifier.
73    pub fn id(mut self, id: i32) -> Self {
74        self.data.id = id;
75        self
76    }
77
78    /// Sets the identifier of the notification channel that delivers this notification.
79    ///
80    /// If the channel does not exist, the notification won't fire.
81    /// Make sure the channel exists with `Notification::list_channels` and
82    /// `Notification::create_channel`.
83    ///
84    /// Only used on Android.
85    pub fn channel_id(mut self, id: impl Into<String>) -> Self {
86        self.data.channel_id.replace(id.into());
87        self
88    }
89
90    /// Sets the notification title.
91    pub fn title(mut self, title: impl Into<String>) -> Self {
92        self.data.title.replace(title.into());
93        self
94    }
95
96    /// Sets the notification body.
97    pub fn body(mut self, body: impl Into<String>) -> Self {
98        self.data.body.replace(body.into());
99        self
100    }
101
102    /// Schedule this notification to fire on a later time or a fixed interval.
103    pub fn schedule(mut self, schedule: Schedule) -> Self {
104        self.data.schedule.replace(schedule);
105        self
106    }
107
108    /// Multiline text.
109    /// Changes the notification style to big text.
110    /// Cannot be used with `inboxLines`.
111    pub fn large_body(mut self, large_body: impl Into<String>) -> Self {
112        self.data.large_body.replace(large_body.into());
113        self
114    }
115
116    /// Detail text for the notification with `largeBody`, `inboxLines` or `groupSummary`.
117    pub fn summary(mut self, summary: impl Into<String>) -> Self {
118        self.data.summary.replace(summary.into());
119        self
120    }
121
122    /// Defines an action type for this notification.
123    pub fn action_type_id(mut self, action_type_id: impl Into<String>) -> Self {
124        self.data.action_type_id.replace(action_type_id.into());
125        self
126    }
127
128    /// Identifier used to group multiple notifications.
129    ///
130    /// <https://developer.apple.com/documentation/usernotifications/unmutablenotificationcontent/1649872-threadidentifier>
131    pub fn group(mut self, group: impl Into<String>) -> Self {
132        self.data.group.replace(group.into());
133        self
134    }
135
136    /// Instructs the system that this notification is the summary of a group on Android.
137    pub fn group_summary(mut self) -> Self {
138        self.data.group_summary = true;
139        self
140    }
141
142    /// The sound resource name for the notification.
143    pub fn sound(mut self, sound: impl Into<String>) -> Self {
144        self.data.sound.replace(sound.into());
145        self
146    }
147
148    /// Append an inbox line to the notification.
149    /// Changes the notification style to inbox.
150    /// Cannot be used with `largeBody`.
151    ///
152    /// Only supports up to 5 lines.
153    pub fn inbox_line(mut self, line: impl Into<String>) -> Self {
154        self.data.inbox_lines.push(line.into());
155        self
156    }
157
158    /// Notification icon.
159    ///
160    /// On Android the icon must be placed in the app's `res/drawable` folder.
161    pub fn icon(mut self, icon: impl Into<String>) -> Self {
162        self.data.icon.replace(icon.into());
163        self
164    }
165
166    /// Notification large icon (Android).
167    ///
168    /// The icon must be placed in the app's `res/drawable` folder.
169    pub fn large_icon(mut self, large_icon: impl Into<String>) -> Self {
170        self.data.large_icon.replace(large_icon.into());
171        self
172    }
173
174    /// Icon color on Android.
175    pub fn icon_color(mut self, icon_color: impl Into<String>) -> Self {
176        self.data.icon_color.replace(icon_color.into());
177        self
178    }
179
180    /// Append an attachment to the notification.
181    pub fn attachment(mut self, attachment: Attachment) -> Self {
182        self.data.attachments.push(attachment);
183        self
184    }
185
186    /// Adds an extra payload to store in the notification.
187    pub fn extra(mut self, key: impl Into<String>, value: impl Serialize) -> Self {
188        self.data
189            .extra
190            .insert(key.into(), serde_json::to_value(value).unwrap());
191        self
192    }
193
194    /// If true, the notification cannot be dismissed by the user on Android.
195    ///
196    /// An application service must manage the dismissal of the notification.
197    /// It is typically used to indicate a background task that is pending (e.g. a file download)
198    /// or the user is engaged with (e.g. playing music).
199    pub fn ongoing(mut self) -> Self {
200        self.data.ongoing = true;
201        self
202    }
203
204    /// Automatically cancel the notification when the user clicks on it.
205    pub fn auto_cancel(mut self) -> Self {
206        self.data.auto_cancel = true;
207        self
208    }
209
210    /// Changes the notification presentation to be silent on iOS (no badge, no sound, not listed).
211    pub fn silent(mut self) -> Self {
212        self.data.silent = true;
213        self
214    }
215}
216
217/// Extensions to [`tauri::App`], [`tauri::AppHandle`], [`tauri::WebviewWindow`], [`tauri::Webview`] and [`tauri::Window`] to access the notification APIs.
218pub trait NotificationExt<R: Runtime> {
219    /// Returns the notification APIs managed by the plugin.
220    ///
221    /// # Examples
222    ///
223    /// ```no_run
224    /// use tauri_plugin_notification::NotificationExt;
225    ///
226    /// fn notify<R: tauri::Runtime>(app: &tauri::AppHandle<R>) {
227    ///   app.notification()
228    ///     .builder()
229    ///     .title("Tauri")
230    ///     .body("Tauri is awesome!")
231    ///     .show()
232    ///     .unwrap();
233    /// }
234    /// ```
235    fn notification(&self) -> &Notification<R>;
236}
237
238impl<R: Runtime, T: Manager<R>> crate::NotificationExt<R> for T {
239    fn notification(&self) -> &Notification<R> {
240        self.state::<Notification<R>>().inner()
241    }
242}
243
244/// Initializes the plugin.
245pub fn init<R: Runtime>() -> TauriPlugin<R> {
246    Builder::new("notification")
247        .invoke_handler(tauri::generate_handler![
248            commands::notify,
249            commands::request_permission,
250            commands::is_permission_granted
251        ])
252        .js_init_script(include_str!("init-iife.js").replace(
253            "__TEMPLATE_windows__",
254            if cfg!(windows) { "true" } else { "false" },
255        ))
256        .setup(|app, api| {
257            #[cfg(mobile)]
258            let notification = mobile::init(app, api)?;
259            #[cfg(desktop)]
260            let notification = desktop::init(app, api)?;
261            app.manage(notification);
262            Ok(())
263        })
264        .build()
265}