How to use WNS to deliver raw push notifications to a lock screen app (XAML)

[This article is for Windows 8.x and Windows Phone 8.x developers writing Windows Runtime apps. If you’re developing for Windows 10, see the latest documentation]

This topic shows how to use the Windows Notification Service (WNS) and raw push notifications in a Windows Runtime app to receive network notifications in the background by lock screen app. This covers the process of registering a push notification channel and send it to your server, how to register a background task to activate from a raw push notification, send a raw push notification to the channel and activate the background task.

What you need to know

Technologies

Prerequisites

  • The following information applies to any connected or network-aware Windows Runtime app that depends on network connections using raw push notifications to always be connected. This topic applies to apps written in C++/XAML and apps using the .NET Framework 4.5 in C#, VB.NET, or managed C++ for Windows 8.1, Windows Phone 8.1, and Windows Server 2012 R2.

    Background network connectivity using raw push notifications is supported by a JavaScript app. For more information on background tasks that apply to JavaScript apps, see Supporting your app with background tasks. For information on background network connectivity supported by a JavaScript app, see Staying connected in the background (HTML).

Instructions

Step 1: Using WNS to deliver raw push notifications to a lock screen app

Windows Runtime apps that use WNS do not need to be running to receive push notifications and can appear to the user like they are running when they are not. For example, a weather app can always show the latest weather in an updated live tile. WNS can also be used to deliver on-screen notifications to users when important events happen. A good example of an on-screen notification is some breaking news event. Any device running Windows 8 with a connection to the Internet can use WNS. These WNS notifications usually are delivered as soon as they are sent.

Although WNS helps power the live tiles and notifications on the start screen of Windows 8.1, it can also be used to enable real-time connectivity scenarios such as IM, VoIP, and email. When an app that uses WNS is added to the lock screen, it can be used to activate a background task. A background task is part of your app code that runs when your app is in the background (no longer in the foreground).

Some examples of a background task that can be activated by a WNS notification include the following:

  • Call the notification badge API to increment a badge icon for an email app on the lock screen to indicate that a new email message has arrived.
  • Call the modification toast API to raise a notification for a VoIP app signaling an incoming phone call for the user.

There are four types of push notifications:

  • Tile update
  • Badge update
  • Toast notification
  • Raw notification

All Windows Runtime apps can use the first three push notifications when in the foreground. Only lock screen apps can receive raw push notifications from WNS. Raw notifications allow lock screen apps to run code in the form of a background task when the raw push notification arrives from WNS, even when the app is not in the foreground.

Most apps do not need to be a lock screen app and can use WNS without being on the lock screen. WNS can be used by all apps to update tiles and badges and to raise toast notifications when in the foreground. Using WNS with a lock screen app is a more advanced version of using WNS for lighting up live tiles and raising notifications to users. Developers should become familiar with the WNS documentation on MSDN before attempting to use WNS with a lock screen. For more information, see Push notification overview.

You will need a secret key that has been provisioned through the Windows Store to send push notifications to WNS. For more information about authenticating with WNS and configuring your app, see How to authenticate with the Windows Push Notification Service (WNS).

The following steps show how to send a raw push notification to a lock screen app.

  • Register for a WNS push notification channel and send it to your server.

  • Send a properly formatted raw push notification to WNS using the notification channel.

  • Write a background task that gets activated from a raw push notification. For more information, see

    How to write a background task for raw push notifications (XAML).

Raw push notifications are delivered to a client app using a developer’s app server by performing an HTTP PUSH of a well-formed XML payload to a notification channel. A notification channel is generated by the client app, sent to your app server, and used to send the push notification. The notification channel is unique to your app’s instance on the user’s account on Windows 8.

Register for a push notification channel and send it to your server

  1. Register for a channel by calling one of the CreatePushNotificationChannelForApplicationAsync methods on the PushNotificationChannelManager class in the Windows.Networking.PushNotifications namespace.

    This will generate a push notification channel for your app, which will look something like the following:

    https://db3.notify.windows.com/?token=AQQAAADX3Wr8MA%2fCoZk4n1CmR5ZU7tdic6ksvG4TQq1tiyZtpetjfzuPHSjvliEeqaqJcPuo1jrVnbyCZvnbuU%2byLvZNDONTgUNu6lavpl5EGtWx7iQgpGkyHLbZeosxioQ42Cg%3d
    
  2. Send the channel to your server. Channels expire after 30 days, so there are best practices:

    • Register to get a new push notification channel every time your app starts, and send it to your server to replace the channel previously tied to the user.
    • For a local computer that is always powered, run a background task to renew the channel every once in a while before the channel expires. This is known as a maintenance timer.

Register a background task to activate from a raw push notification

  1. To build a background task that runs when a raw push notification is received, you must specify the code that is to be activated by the background task. To do this, you must ensure your app manifest points to the correct entry point for the background task. The app manifest must consist of the name of the class name of entry point for the background task in the file.

    The following sample adds extensions for a pushNotifyTask background task under the <Application> element in an app manifest.

    <Extensions>
       <Extension Category="windows.backgroundTasks" EntryPoint="BackgroundTasks.SampleBackgroundTask">
         <BackgroundTasks>
           <Task Type="pushNotification" />
         </BackgroundTasks>
       </Extension>
    </Extensions>
    
  2. The app needs to open the channel for raw push notifications.

    The following sample shows how to open a channel for a raw push notification.

        private async void OpenChannelAndRegisterTask()
        {
            // Open the channel. See the "Push and Polling Notifications" sample for more detail
            try {
                if (rootPage.Channel == null) {
                    PushNotificationChannel channel = await PushNotificationChannelManager.CreatePushNotificationChannelForApplicationAsync();
                    String uri = channel.Uri;
                    rootPage.Channel = channel;
                    // This event comes back in a background thread, so we need to move to the UI thread to access any UI elements
                    await _dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => {
                        OutputToTextBox(uri);
                        RootPage.NotifyUser("Channel request succeeded!", NotifyType.StatusMessage);
                    });
                }
    
                // Clean out the background task just for the purpose of this sample
                UnregisterBackgroundTask();
                RegisterBackgroundTask();
                    rootPage.NotifyUser("Task registered", NotifyType.StatusMessage);
            }
            catch (Exception ex) {
                rootPage.NotifyUser("Could not create a channel. Error number:" + ex.Message, NotifyType.ErrorMessage);
            }
        }
    
    void OpenChannelAndRegisterTask()
    {
        // Clear out the task just for the purpose of this sample
        UnregisterBackgroundTask();
    
        // Open the channel. See the "Push and Polling Notifications" sample for more detail
    
        if (rootPage->Channel == nullptr) {
            create_task(PushNotificationChannelManager::CreatePushNotificationChannelForApplicationAsync()).then([this] (task<PushNotificationChannel^> channelTask)
            {
                PushNotificationChannel^ newChannel;
                try
                {
                    newChannel = channelTask.get();
                }
                catch (Exception^ ex)
                {
                    rootPage->NotifyUser("Could not create a channel. Error: " + ex->Message, NotifyType::ErrorMessage);
                }
    
                if (newChannel != nullptr)
                {
                    // This event comes back in a background thread, so we need to move to the UI thread to access any UI elements
                    OutputToTextBox(newChannel->Uri);
                    rootPage->NotifyUser("Channel request succeeded!", NotifyType::StatusMessage);
    
                    rootPage->Channel = newChannel;
    
                    RegisterBackgroundTask();
                    rootPage->NotifyUser("Task registered", NotifyType::StatusMessage);
                }
            });
        } else {
            RegisterBackgroundTask();
            rootPage->NotifyUser("Task registered", NotifyType::StatusMessage);
        }
    }
    
        Private Async Sub OpenChannelAndRegisterTask()
            ' Open the channel. See the "Push and Polling Notifications" sample for more detail
            Try
                If rootPage.Channel Is Nothing Then
                    Dim channel As PushNotificationChannel = Await PushNotificationChannelManager.CreatePushNotificationChannelForApplicationAsync()
                    Dim uri As String = channel.Uri
                    rootPage.Channel = channel
                    ' This event comes back in a background thread, so we need to move to the UI thread to access any UI elements
                    Await _dispatcher.RunAsync(CoreDispatcherPriority.Normal, Sub()
                                                                                  OutputToTextBox(uri)
                                                                                  rootPage.NotifyUser("Channel request succeeded!", NotifyType.StatusMessage)
                                                                              End Sub)
                End If
    
                ' Clean out the background task just for the purpose of this sample
                UnregisterBackgroundTask()
                RegisterBackgroundTask()
                rootPage.NotifyUser("Task registered", NotifyType.StatusMessage)
            Catch ex As Exception
                rootPage.NotifyUser("Could not create a channel. Error number:" & ex.Message, NotifyType.ErrorMessage)
            End Try
        End Sub
    
  3. The app must also register the background task to be activated when a raw push notification is received.

    The following sample shows how to register and unregister a background task for a raw push notification.

        private void RegisterBackgroundTask()
        {
            BackgroundTaskBuilder taskBuilder = new BackgroundTaskBuilder();
            PushNotificationTrigger trigger = new PushNotificationTrigger();
            taskBuilder.SetTrigger(trigger);
    
            // Background tasks must live in separate DLL, and be included in the package manifest
            // Also, make sure that your main application project includes a reference to this DLL
            taskBuilder.TaskEntryPoint = SAMPLE_TASK_ENTRY_POINT;
            taskBuilder.Name = SAMPLE_TASK_NAME;
    
            try {
                BackgroundTaskRegistration task = taskBuilder.Register();
                task.Completed += BackgroundTaskCompleted;
            }
            catch (Exception ex) {
                rootPage.NotifyUser("Registration error: " + ex.Message, NotifyType.ErrorMessage);
                UnregisterBackgroundTask();
            }
        }
    
        private bool UnregisterBackgroundTask()
        {
            foreach (var iter in BackgroundTaskRegistration.AllTasks)
            {
                IBackgroundTaskRegistration task = iter.Value;
                if (task.Name == SAMPLE_TASK_NAME)
                {
                    task.Unregister(true);
                    return true;
                }
            }
            return false;
        }
    
    void RegisterBackgroundTask()
    {
        auto taskBuilder = ref new BackgroundTaskBuilder();
        auto trigger = ref new PushNotificationTrigger();
        taskBuilder->SetTrigger(trigger);
    
        // Background tasks must live in separate DLL, and be included in the package manifest
        // Also, make sure that your main application project includes a reference to this DLL
        taskBuilder->TaskEntryPoint = ref new String(SAMPLE_TASK_ENTRY_POINT);
        taskBuilder->Name = ref new String(SAMPLE_TASK_NAME);
    
        BackgroundTaskRegistration^ task;
        try
        {
            task = taskBuilder->Register();
        }
        catch (Exception^ ex)
        {
            rootPage->NotifyUser("Registration error: " + ex->Message, NotifyType::ErrorMessage);
            UnregisterBackgroundTask();
        }
    
        if (task != nullptr)
        {
            task->Completed += ref new BackgroundTaskCompletedEventHandler(this, &ScenarioInput1::BackgroundTaskCompleted);
        }
    }
    
    bool UnregisterBackgroundTask()
    {
        auto iter = BackgroundTaskRegistration::AllTasks->First();
        while (iter->HasCurrent)
        {
            auto task = iter->Current->Value;
            if (task->Name == ref new String(SAMPLE_TASK_NAME))
            {
                task->Unregister(true);
                return true;
            }
            iter->MoveNext();
        }
    
        return false;
    }
    
        Private Sub RegisterBackgroundTask()
            Dim taskBuilder As New BackgroundTaskBuilder()
            Dim trigger As New PushNotificationTrigger()
            taskBuilder.SetTrigger(trigger)
    
            ' Background tasks must live in separate DLL, and be included in the package manifest
            ' Also, make sure that your main application project includes a reference to this DLL
            taskBuilder.TaskEntryPoint = SAMPLE_TASK_ENTRY_POINT
            taskBuilder.Name = SAMPLE_TASK_NAME
    
            Try
                Dim task As BackgroundTaskRegistration = taskBuilder.Register()
                AddHandler task.Completed, AddressOf BackgroundTaskCompleted
            Catch ex As Exception
                rootPage.NotifyUser("Registration error: " & ex.Message, NotifyType.ErrorMessage)
                UnregisterBackgroundTask()
            End Try
        End Sub
    
        Private Function UnregisterBackgroundTask() As Boolean
            For Each iter In BackgroundTaskRegistration.AllTasks
                Dim task As IBackgroundTaskRegistration = iter.Value
                If task.Name = SAMPLE_TASK_NAME Then
                    task.Unregister(True)
                    Return True
                End If
            Next
            Return False
        End Function
    
  4. You also need to provide code for the function that runs when the background task is triggered. For more information, see:

    How to write a background task for raw push notifications (XAML).

Raw push notifications are similar to badge and tile notifications. The key difference is that the payload of a raw push notification does not contain attributes that update parts of the Windows 8.1 user interface. The payload of the raw push notification is all context data that gets passed directly to your app when the background task is activated. Your app must understand the format of the context data sent by the server.

Before your server can send a raw push notification you must do the following:

Send a raw push notification to the channel and activate the background task

  1. Ensure that you have registered your app with the Windows Store and have a private key and package SID.

  2. Write code on your app server to authenticate with WNS using the private key and package SID before sending a push notification from the server.

  3. Properly craft a WNS raw push notification and perform an HTTP POST to the notification channel that you have previously received from the Windows Store app. The HTTP POST should include several additional HTTP headers:

    • X-WNS-Type=wns/raw
    • Content-Type=application/octet-stream
    • Authorization=The string “Bearer”, a space, and then the authorization token received from the authentication step

    The body of the HTTP POST should include any context that you want to provide to the client app when it runs the background task triggered by receiving the raw push notification. The maximum amount of data that can be included in the raw notification payload is 5KB.

    When the notification is received by the client, the background task is activated and the data payload specified is passed in and accessible through your app’s background task code.

Step 2: Previous steps

For more information on how to create a lock screen app to receive background network notifications that use raw push notifications, see Quickstart: Create a lock screen app that uses background raw push notifications.

Step 3: Further steps

For more information on how to write a background task to receive background network notifications that use raw push notifications, see How to write a background task for raw push notifications.

For more information on guidelines and checklists for using raw push notifications, see Guidelines and checklist for raw notifications.

Other resources

Adding support for networking

Background Networking

Guidelines and checklist for raw notifications

How to authenticate with the Windows Push Notification Service (WNS)

Lock screen overview

Push notification overview

Staying connected in the background

Supporting your app with background tasks

Troubleshooting and debugging network connections

Reference

HttpClient

HttpClientHandler

IXMLHTTPRequest2

System.Net.Http

Windows.ApplicationModel.Background

Windows.Networking.BackgroundTransfer

Windows.Networking.PushNotifications

Windows.Networking.Sockets

Windows.Web.Http

Samples

Background task sample

Lock screen apps sample

Push and periodic notifications client-side sample

Raw notifications sample