Closed hulumane closed 2 years ago
The review link does not work for non-FTEs and taints the open source spirit of the project/workflow here. Recommend attaching files as a workaround.
Some early feedback:
It doesn’t appear apps will receive notifications until they notify at least once due to the placement of the registration logic. I was a bit surprised by this, instead expecting to see the registration behavior in a static constructor or module constructor. The impact here is that an app can’t receive notifications from the cloud until they toast once.
Registration of unpackaged desktop apps entails creating a fake GUID to serve as the application’s AUMID. I have several concerns about this:
There's no mention of how this works in 10X containers.
Thanks Rafael!! I fixed the link (included the documentation PDF files). I need to talk with our docs team about seeing if we can open up certain doc branches to the public so we can just share the actual docs!
Responding to those additional points...
This proposal doesn't include push (cloud) notifications, plus to receive push notifications, apps have to make an API call anyways (to obtain the push channel), so we can register the app there. But push will be covered in a separate spec and likely requires even more work like a UWP sidecar (we're still figuring out a plan)... for toasts we've always had "Nitro" down-level to use.
Excellent concerns! We'll take these all into consideration, clearly we need to do something slightly different.
For 10X containers, I'll sync up with the rest of the Reunion team. Good callout.
1) For the Push concern, we could technically abstract the registration call behind channel creation. We still need to think about it a little more though. 2) For the registration, I agree with some of these concerns. Thanks for bringing it up. I think it is valuable to provide a way to unregister. Otherwise we end up with stale orphans in our DB. Also instead of a hash, maybe we could simply use the file path which is guaranteed to be unique? The goal initially was to abstract away all of this for developers but clearly there is a cost here and we need to rethink our approach.
@hulumane File paths aren't guaranteed to be unique, sadly. Consider the removable device scenario, where the path could be reused by multiple apps (e.g. R:\tool.exe
). Probably rare though.
Documenting the Electron EXE case for future reference... indeed the EXE path does change over app versions... tracing the EXE back to the shortcut and using the shortcut would work though as that stays stable (of course the app could rename their app's display name which would change the shortcut path... should see if electron typically assigns the AUMID property on the shortcut).
After updating to 1.0.1...
Changing the name indeed (obviously) changes the shortcut path. Interesting to note the local data path (up till the version) remains constant. It seems to use the subsequent value seen further below within package.json for maker_squirrel... I wonder if that also gets set as the AUMID of the shortcut or what... either way that value seems unique and constant, and possibly the earlier AppData path is constant and unique...
Indeed the AUMID gets set, and that config value seems to get used, not sure where the second "ElectronApp" comes from though... (easy way to view AUMIDs is to CTRL+R
and execute shell:appsfolder
, change the display to detailed list, and press ALT+V, "Choose details…", select AppUserModelId
They seem to use the "product name" and sanitize it for spaces when generating the AUMID, so changing the app name results in a new AUMID (also note that forge's installer doesn't handle deleting the previous shortcut, but that's a separate issue for forge not us).
@andrewleader Portable unpackaged desktop apps may not have a shortcut to leverage, right? (I believe the shortcut dependency was one of the pain points identified in this proposal.)
The Taskbar notification area anchors to image path. But to address some of the pitfalls to that approach, it also provides developers with a method of registering with an ID they control. Perhaps a similar approach can be adopted here?
Yes, shortcuts aren't required, but when present they provide some more options for a more stable app identity (for example for Electron apps, that resolves the problem with the EXE path changing on upgrade, because the shortcut remains stable and actually has the AUMID property set).
That's super useful to know how taskbar notification area identifies apps! Indeed an optional option for developers to register an ID might be necessary. I'd like to keep things as easy and seamless as possible for developers, which is why I'm searching for solutions to avoid that and use existing ways to uniquely identify apps.
How will Adaptive Cards play into this new API?
What about ScheduledToastNotifications? Currently, that doesn't even work if the win32 application has never called the CreateToastNotifier().show()
method. A work around my app in production uses is, if its the first time the app has run, it calls .show() and then immediately calls .hide() on a blank notification, just so the scheduled notifications work.
ScheduledToastNotification toast = new ScheduledToastNotification(toastContent.GetXml(), DateTime.Now.AddMinutes(60));
DesktopNotificationManagerCompat.CreateToastNotifier().AddToSchedule(toast);
@mdtauk We don't have any plans to support Adaptive Cards in toast notifications today. Do you or your company have a need/requirement for this and if so can you explain why and what end-user experience or developer benefit you're hoping to achieve?
@uBadRequest I wasn't aware of this issue, thank you for reporting that, I'll double check to see if our new solution for toasts works with scheduled toast notifications out-of-the-gate (I probably haven't seen this issue myself since in my test apps I've usually sent a local toast first).
@andrewleader we also looking to have something like adaptive cards or even something more complex as a need; I'm happy to take it offline with you
The updated Notifications Toolkit preview is available to try for C# apps (WPF/Winforms, MSIX, or UWP)! Shortcuts are no longer needed!! Documentation and instructions here: https://docstaging.z5.web.core.windows.net/aleader/toolkit-7/design/shell/tiles-and-notifications/send-local-toast.html
If you run into any problems or find anything that could be better or doesn't work for your scenarios, please let us know (if your app requires running as admin, there are some known problems with activation there that we haven't fixed yet). If the preview works well for you, please let us know about that too!
See above issue, something to keep track of context of any Reunion notification work.
@andrewleader, while browsing a section for Win32 C++ apps on the address you provided, I can see that shortcuts are still required:
If you're using classic Win32 (or if you support both), you have to declare your Application User Model ID (AUMID) and toast activator CLSID (the GUID from step # 4) on your app's shortcut in Start.
Could you please elaborate under what conditions was the requirement lifted? I assume, certain Windows update is required?
@ForNeVeR this feature is still in proposal state for Project Reunion and hasn't been implemented, but when it is, shortcuts won't be required in any scenario, including support back to version 1809 of Windows 10.
In a couple days, we're going to be releasing the updated version of the Windows Community Toolkit which includes support for the shortcut-less notification experience for C# apps, and along with that we're publishing a docs article that might help you try this now for C++ apps. I'll let you know here when that's available!
Do you have a C++ app?
@andrewleader, I am considering using the new toast notifications instead of the older XP-styled ones in a large Java application that has a C++ bootstrapper (so we coud use pure C++ solution based on WRL, but it would be harder for me to push WinRT/UWP-based solution).
Main problem with XP-style notifications is that they force us to add a tray notification icon, which is otrherwise completely unused by the app, and is defunct and confusing for the users (as a free bonus, the new notiifcations are much more functional, but that's not our main focus — though we may try to use some of the features such as clickable links).
And, yes, the custom shortcut requirement is one of the reasons we weren't able to bring the new notifications into the app: we have a complex deployment system with custom updates, application being sometimes distributed as a ZIP archive, and such, so we aren't always controlling the shortcuts.
The WinAppSDK now implements a Toast Notification featureset that supports all Win32 apps (Packaged and Unpackaged). https://github.com/microsoft/WindowsAppSDK/pull/2192
Customer / job-to-be-done: App developers using WPF, WinForms, or Win32 C++ need to keep their users informed via toasts regardless of whether their app is currently open
Problem: WPF apps must use the Community Toolkit to send notifications, C++ and Electron apps have told us they hate needing to have a shortcut and setting up notifications is difficult and they also have to use raw XML
How does our solution make things easier? All types of apps will benefit from the easier experience WPF apps currently have through the Toolkit (no more shortcut, zero configuration work to send a notification, easy activation). WPF app developers will benefit from only having to reference and update one single NuGet package (Reunion) instead of two (Reunion+Toolkit)
Target customer
While this work should be consumable by cross-platform platforms to improve experiences there, we should have a separate feature specifically for ensuring notifications are built in "natively" and developers don't have to do additional custom work to access the Windows native layer.
Customer's job-to-be-done's
Problems that exist today
CreateToastNotifier()
... Win32 apps have to callCreateToastNotifier("MyAumid")
Summary
Along with simplifying the APIs for UWP apps, these new simplified APIs will also work for all Win32 apps, AND they will work down-level too, so that developers (UWP or Win32) can use them instantly! There will be no requirement to change existing code to the new APIs, and existing SDKs that worked before will still work with your apps.
To make the registration experience seamless for Win32 apps, we'll take on the heavy lifting of registering a Win32 app down-level, using their existing app assets (app name, icon). Developers simply have to call our new simplified APIs, and regardless of their app type, toasts will automatically work!
Quick links
Rationale
Scope
API experience
Here's a look at what (UWP) developers do today, compared to what we're proposing (any app type) developers will do using Reunion...
Today
**Tomorrow (Reunion)***
To receive activation, we haven't been able to get a 100% converged experience...
ToastNotificationManagerInterop.OnActivated
ToastNotificationManagerInterop.OnActivated
Sending toast API experience
First, developers would install the Reunion NuGet package.
Then, we're bringing in the toast XML object model that the Toolkit Notifications library has, so that you can have everything you need to easily construct toasts within one library! No manipulating XML necessary :) There will be a new ToastNotificationBuilder class, which allows you to create a toast using zero XML, set all the properties on it, and show it without calling the lengthy call-chain soup that today is
ToastNotificationManager.CreateToastNotifier().Show()
!Receiving activation API experience
UWP apps
UWP apps would receive activation as they do today, within their App.xaml.cs OnActivated method.
Win32 MSIX apps
First, in your Package.appxmanifest, add:
Then, in your app's startup code (App.xaml.cs OnStartup for WPF), subscribe to the OnActivated event.
Win32 or sparse apps
In your app's startup code (App.xaml.cs OnStartup for WPF), subscribe to the OnActivated event.
What about existing SDKs? Please don't break those!
I fully agree with you. If you're using a SDK that returns an XmlDocument or a ToastNotification, you'll still be able to use those, we'll provide APIs to allow you to pass those through to the new APIs.
API definitions
NOTE: These are OUTDATED, haven't been updated to the new Builder style
Introduce a new class...
Microsoft.UI.Notifications.ToastNotificationManagerInterop
Methods
Windows.UI.Notifications.ToastNotifier
Windows.UI.Notifications.ToastCollectionManager
IAsyncOperation<
Windows.UI.Notifications.ToastNotifier>
IAsyncOperation<
Microsoft.UI.Notifications.ToastNotificationHistoryInterop>
Omitted methods
We're explicitly omitting a few methods from the platform ToastNotificationManager and ToastNotificationManagerForUser...
Properties
Microsoft.UI.Notifications.ToastNotificationHistoryInterop
Events
(Microsoft.UI.Notifications.
ToastNotificationActivatedEventArgsInterop e)
And add another new class...
Microsoft.UI.Notifications.ToastNotificationHistoryInterop
void
IReadOnlyList<
Windows.UI.Notifications.ToastNotification>
void
void
void
Omitted methods
We're explicitly omitting a few methods from the platform ToastNotificationHistory...
And one more new class... (unfortunately we can't just instantiate ToastNotificationActivatedEventArgs).
Microsoft.UI.Notifications.ToastNotificationActivatedEventArgsInterop
This class will only be used by Win32 MSIX/sparse and Win32 apps... there's nothing stopping UWP apps from using it, but it just won't ever do anything or be sent to them.
Or ideally we should have a converged activation experience with the rest of Reunion...
Properties
string
ValueSet
Implementation details
When the developer calls
ToastNotificationManagerInterop.CreateToastNotifier()
, we'll handle the differences between UWP/Win32 MSIX/spase and Win32.If running with identity: We simply call
CreateToastNotifier()
If not running with identity (Win32): We'll first register the app by obtaining its display name and icon and using the EXE path for the AUMID, and then we'll call
CreateToastNotifier(aumid)
.We'll do the same forking logic for when they access
.History
.Uniquely and consistently obtaining an app's identity
We need to be able to uniquely identify (and consistently re-identify) a Win32 app so that we can register it with a stable identity.
Scenarios we should support are...
In all those cases, we should hopefully be able to keep the same identity.
How NotificationIcon (taskbar notification icons) identifies apps
Taskbar either uses hWnd + uId (where uId is an integer) or guidItem to uniquely identify the notification icon in the system tray (docs). There's a code sample here. You can only set hWnd and leave uId as default 0, that's the most minimal. It doesn't automatically infer your hWnd though.
Open questions
Would appreciate community feedback on any of the following!!
DesktopNotificationManagerInterop
class? It's not usable by UWP at all, and won't do anything on UWP (since UWP activation goes through the OnActivated App.xaml.cs method). Or maybe we just throw an exception when running on UWP to let the developer know to not use it (in addition to having an IntelliSense comment).CreateToastNotifier()
orGetToastNotifier()
? For the new toast notifier for toast collections, we went with Get... should we converge but possibly make it slightly tougher to switch? Existing apps shouldn't need to switch to these new APIs anyways though.Important Notes
PM gathered feedback from 12 developers on GitHub who used our Desktop notifications library today in Win32 non-packaged apps to learn what their pain points are, what approaches they would prefer, etc • Overwhelmingly, people’s biggest pain point was needing to create the shortcut (only 2 found that easy) • About 50/50 were happy with current COM activation. • About 50/50 were happy with the current documentation experience • When asked whether they’d prefer COM or EXE activation, of those who responded, most (4 developers) said COM, only one said EXE, two said in-memory callback • Handling activation of COM server from an elevated process is a challenge/problem today and something we need to fix • One developer was a scripting developer, we can’t forget the PowerShell community (there’s a BurntToast library for sending toasts via PowerShell, we can update that to use the new registration).
A sample of the docs for sending toasts are available here: Internal link / Public link