Skip to content

Commit 6dc46e2

Browse files
committed
Add support for packaged apps in Windows notification handling logic
1 parent ff3a0d5 commit 6dc46e2

2 files changed

Lines changed: 41 additions & 10 deletions

File tree

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ uuid = { version = "1", default-features = false, features = ["v4", "fast-rng"],
5050

5151
[target.'cfg(target_os = "windows")'.dependencies]
5252
windows = { version = "0.61", features = [
53+
"ApplicationModel",
5354
"Data_Xml_Dom",
5455
"Foundation",
5556
"Networking_PushNotifications",

src/windows.rs

Lines changed: 40 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use tauri::{
1010
AppHandle, Runtime,
1111
};
1212
use windows::core::{Interface, HSTRING};
13+
use windows::ApplicationModel::Package;
1314
use windows::Data::Xml::Dom::XmlDocument;
1415
use windows::Foundation::{DateTime, TypedEventHandler};
1516
#[cfg(feature = "push-notifications")]
@@ -21,6 +22,19 @@ use windows::UI::Notifications::{
2122
ToastNotificationManager, ToastNotifier,
2223
};
2324

25+
/// True when the current process has MSIX package identity.
26+
///
27+
/// WinRT notification APIs split into two flavors: no-arg variants that use the
28+
/// package's default AUMID (only valid for packaged apps), and `*WithId`
29+
/// variants that take an explicit AUMID (only valid for unpackaged apps whose
30+
/// AUMID is registered via a Start Menu shortcut). Passing an arbitrary string
31+
/// to the WithId variants from inside an MSIX returns ERROR_NOT_FOUND because
32+
/// the real AUMID is `<PackageFamilyName>!<Application Id>` and the family-name
33+
/// hash is install-time only.
34+
fn is_packaged() -> bool {
35+
Package::Current().is_ok()
36+
}
37+
2438
use crate::error::{ErrorResponse, PluginInvokeError};
2539
use crate::models::*;
2640

@@ -38,6 +52,7 @@ impl From<windows::core::Error> for crate::Error {
3852
/// Shared plugin state wrapped in Arc for thread-safe access.
3953
pub struct WindowsPlugin {
4054
app_id: String,
55+
packaged: bool,
4156
notifier: ToastNotifier,
4257
action_types: RwLock<HashMap<String, ActionType>>,
4358
click_listener_active: RwLock<bool>,
@@ -49,6 +64,7 @@ impl std::fmt::Debug for WindowsPlugin {
4964
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5065
f.debug_struct("WindowsPlugin")
5166
.field("app_id", &self.app_id)
67+
.field("packaged", &self.packaged)
5268
.finish_non_exhaustive()
5369
}
5470
}
@@ -134,10 +150,16 @@ pub fn init<R: Runtime, C: DeserializeOwned>(
134150
_api: PluginApi<R, C>,
135151
) -> crate::Result<Notifications<R>> {
136152
let app_id = app.config().identifier.clone();
137-
let notifier = ToastNotificationManager::CreateToastNotifierWithId(&HSTRING::from(&app_id))?;
153+
let packaged = is_packaged();
154+
let notifier = if packaged {
155+
ToastNotificationManager::CreateToastNotifier()?
156+
} else {
157+
ToastNotificationManager::CreateToastNotifierWithId(&HSTRING::from(&app_id))?
158+
};
138159

139160
let plugin = Arc::new(WindowsPlugin {
140161
app_id,
162+
packaged,
141163
notifier,
142164
action_types: RwLock::new(HashMap::new()),
143165
click_listener_active: RwLock::new(false),
@@ -470,12 +492,14 @@ impl<R: Runtime> Notifications<R> {
470492
let history = ToastNotificationManager::History()?;
471493
let app_id = &self.plugin.app_id;
472494
for id in notifications {
495+
let tag = HSTRING::from(id.to_string());
473496
// Use app-scoped removal with empty group (consistent with GetHistoryWithId usage)
474-
if let Err(e) = history.RemoveGroupedTagWithId(
475-
&HSTRING::from(id.to_string()),
476-
&HSTRING::new(),
477-
&HSTRING::from(app_id),
478-
) {
497+
let res = if self.plugin.packaged {
498+
history.RemoveGroupedTag(&tag, &HSTRING::new())
499+
} else {
500+
history.RemoveGroupedTagWithId(&tag, &HSTRING::new(), &HSTRING::from(app_id))
501+
};
502+
if let Err(e) = res {
479503
log::error!("Failed to remove notification {id}: {e}");
480504
}
481505
}
@@ -484,8 +508,11 @@ impl<R: Runtime> Notifications<R> {
484508

485509
pub async fn active(&self) -> crate::Result<Vec<ActiveNotification>> {
486510
let history = ToastNotificationManager::History()?;
487-
let app_id = &self.plugin.app_id;
488-
let notifications = history.GetHistoryWithId(&HSTRING::from(app_id))?;
511+
let notifications = if self.plugin.packaged {
512+
history.GetHistory()?
513+
} else {
514+
history.GetHistoryWithId(&HSTRING::from(&self.plugin.app_id))?
515+
};
489516

490517
let mut result = Vec::new();
491518
for i in 0..notifications.Size()? {
@@ -533,8 +560,11 @@ impl<R: Runtime> Notifications<R> {
533560

534561
pub fn remove_all_active(&self) -> crate::Result<()> {
535562
let history = ToastNotificationManager::History()?;
536-
let app_id = &self.plugin.app_id;
537-
history.ClearWithId(&HSTRING::from(app_id))?;
563+
if self.plugin.packaged {
564+
history.Clear()?;
565+
} else {
566+
history.ClearWithId(&HSTRING::from(&self.plugin.app_id))?;
567+
}
538568
Ok(())
539569
}
540570

0 commit comments

Comments
 (0)