.Net, Azure and occasionally gamedev

Customized Toasts in Uwp

2017/11/04

Uwp notifications are xml payloads in a predefined pattern.

This is both powerful and limiting.

It's powerful because the server can generate a template for your app to use dynamically.

The app can then subscribe to this template by name on each startup, meaning that the server can modify the look of the notification over time without needing an update to the app (add image to show, change text or format).

It is however also limiting because it does not allow localized data (e.g. date, time or temperature) or access to resources requiring authentication (e.g. user-specific images behind an authenticated server).

Modifying the notification

In the homeapp that I recently built for myself I needed access to the webcam image that was published when the motion sensor was triggered. Obviously I didn't want this image to be publicly available so I required authentication on the server for any kind of access.

Using authenticated resources

I first tried to just intercept the push notification and hide it (by canceling it), manually downloading the image from the authenticated server, saving it to disk and creating a clone of the push notification with the image path set to the local file.

Immediately I noticed that this wouldn't be sufficient because UWP only allows toast notification interception when the app is running. Once the app is closed, the code won't run.

This means that any notifications received with the app closed will display an empty area where the image would be (because uwp fails to downloaded the image from the authenticated server as it doesn't know how to authenticate).

Raw notifications

Luckily UWP has support for raw notifications (notifications that are not visible to the user) and those can execute a piece of code each time a notification is received even when the app is closed.

So I created a fully valid toast notification template that had one "<image src=%secured resource% />" tag that pointed to the image requiring authentication.

Instead of sending it as a toast notification (which cannot be intercepted by the closed app) I sent it as a raw notification by adding the required "wns/raw" headers during registration from my UWP app:

var wnsHeaderCollection = new WnsHeaderCollection
{
    {"X-WNS-Type", @"wns/raw"}
};
var registration = new TemplateRegistration(Token, template.Payload, template.Name, new[] { tag }, wnsHeaderCollection);
var result = await _hub.RegisterAsync(registration);

(I am using the Azure NotificationHub which allows me to send notifications to all android/iOS and UWP users without myself having to store the subscriptions since Azure handles it).

Because it's a raw notification it triggers my UWP background task listening to notifications every time (even when the app is closed).

All the background task then does is:

Using this approach one could also modify time/date/temperature (or any other localized data) to conform the the user requested format without losing the ability to modify the template server side.

(Meanwhile on Android I only get a json object with the data, e.g. "title=foo, image=url" and I then have to manually build up a notification object. This means any modification to the notification format will require an app update).

Uwp notification backgroundtask

Setting up this background task for Uwp involved quite a few steps and was tedious. So here are the steps required to get the background task running:

The same data is thus spread across multiple locations (implementation, appxmanifest definition, app launch code). The required steps to get a background task going are also documented here.

Once I completed all the steps my code was working and I was even able to debug the background task (as long as the debugger was attached and my app open).

tagged as Uwp and Notifications