8 min read

Understanding Push Notification Service flow

The following procedure illustrates Push Notification Service (PNS) flow from establishing a channel to receiving a notification:

  1. The mobile device establishes a channel with the PNS and retrieves its handle (URI).
  2. The device registers its handle with a backend service (in our case, a table in our Mobile Service).
  3. A notification request can be made by another service, an admin system, and so on, which calls the backend service (in our case, an API).
  4. The service makes a request to the correct PNS for every device handle.
  5. The PNS notifies the device.

Setting up Windows Store apps

Visual Studio 2013 has a new wizard, which associates the app with the store in order to obtain a push notifications URI. Code is added to the app to interact with the service that will be updated to have a Channels table. This table has an Insert script to insert the channel and ping back a toast notification upon insert. The following procedure takes us through using the wizard to add a push channel to our app:

  1. Right-click on the project, and then navigate to Add | Push Notification.
  2. Follow the wizard and sign in to your store account (if you haven’t got one, you will need to create one).
  3. Reserve an app name and select it. Then, continue by clicking on Next.
  4. Click on Import Subscriptions… and the Import Windows Azure Subscriptions dialog box will appear.
  5. Click on Download subscription file. Your default browser will be launched and the subscriptions file will be automatically downloaded. If you are logged into the portal, this will happen automatically; otherwise, you’ll be prompted to log in.
  6. Once the subscription file is downloaded, browse to the downloaded file in the Import Windows Azure Subscriptions dialog box and click on Import.
  7. Select the subscription you wish to use, click on Next, and then click on Finish in the final dialog box. In the Output window in Visual Studio, you should see something like the following:

    Attempting to install ‘WindowsAzure.MobileServices’ Successfully installed NuGet Package ‘WindowsAzure.MobileServices’ Successfully added ‘push.register.cs’ to the project Added field to the App class successfully Initialization code was added successfully Updated ToastCapable in the app manifest Client Secret and Package SID were updated successfully on the Windows Azure
    Mobile Services portal The ‘channels’ table and ‘insert.js’ script file were created successfully Successfully updated application redirect domain Done

    
    

We will now see a few things have been done to our project and service:

  • The Package.StoreAssociation.xml file is added to link the project with the app on the store.
  • Package.appxmanifest is updated with the store application identity.
  • Add a push.register.cs class in servicesmobile services[Your Service Name], which creates a push notifications channel and sends the details to our service.
  • The server explorer launches and shows us our service with a newly created table named channels, with an Insert method that inserts or updates (if changed) our channel URI. Then, it sends us a toast notification to test that everything is working.

Run the app and check that the URI is inserted into the table. You will get a toast notification. Once you’ve done this, remove the sendNotifications(item.channelUri); call and function from the Insert method. You can do this in Visual Studio via the Server Explorer console. I’ve modified the script further to make sure the item is always updated, so when we send push notifications, we can send them to URIs that have been recently updated so that we are targeting users who are actually using the application (channels actually expire after 30 days too, so it would be a waste of time trying to push to them). The following code details these modifications:

function insert(item, user, request) { var ct = tables.getTable(“channels”); ct.where({ installationId: item.installationId }).read({ success: function (results) { if (results.length > 0) { // always update so we get the updated date var existingItem = results[0]; existingItem.channelUri = item.channelUri; ct.update(existingItem, { success: function () { request.respond(200, existingItem); } }); } else { // no matching installation, insert the record request.execute(); } } }) }


I’ve also modified the UploadChannel method in the app so that it uses a Channel model that has a Platform property. Therefore, we can now work out which PNS provider to use when we have multiple platforms using the service. The UploadChannel method also uses a new InsertChannel method in our DataService method (you can see the full code in the sample app). The following code details these modifications:

public async static void UploadChannel() { var channel = await Windows.Networking.PushNotifications.
PushNotificationChannelManager.
CreatePushNotificationChannelForApplicationAsync(); var token = Windows.System.Profile.HardwareIdentification.
GetPackageSpecificToken(null); string installationId = Windows.Security.Cryptography.
CryptographicBuffer.EncodeToBase64String(token.Id); try { var service = new DataService(); await service.InsertChannel(new Channel() { ChannelUri = channel.Uri, InstallationId = installationId, Platform = “win8” }); } catch (Exception ex) { System.Diagnostics.Debug.WriteLine(ex.ToString()); } }


 Setting up tiles

To implement wide or large square tiles, we need to create the necessary assets and define them in the Visual Assets tab of the Package.appxmanifest editor. This is shown in the following screenshot:

 Setting up badges

Windows Store apps support badge notifications as well as tile and toast. However, this requires a slightly different configuration. To implement badge notifications, we perform the following steps:

  1. Create a 24 x 24 pixel PNG badge that can have opacity, but must use only white color.
  2. Define the badge in the Badge Logo section of the Visual Assets tab of the Package.appxmanifest editor.
  3. Add a Background Tasks declaration in the Declarations tab of the Package.appxmanifest editor, select Push notification, and enter a Start page, as shown in the following screenshot:

  4. Finally, in the Notifications tab of the Package.appxmanifest editor, set Lock screen notifications to Badge. This is shown in the following screenshot:

  5. To see the badge notification working, you also need to add the app to the lock screen badge slots in Lock Screen Applications | Change PC Settings | Lock Screen.

 Setting up Windows Phone 8 apps

Visual Studio 2012 Express for Windows Phone doesn’t have a fancy wizard like Visual Studio 2013 Express for Windows Store. So, we need to configure the channel and register it with the service manually. The following procedure sets up the notifications in the app by using the table that we created in the preceding Setting up Windows Store apps section:

  1. Edit the WMAppManifest.xml file to enable ID_CAP_IDENTITY_DEVICE, which allows us to get a unique device ID for registering in the Channels table, and ID_CAP_PUSH_NOTIFICATION, which allows push notifications in the app. These options are available in the Capabilities tab, as shown in the following screenshot:

  2. To enable wide tiles, we need to check Support for large Tiles (you can’t see the tick unless you hover over it, as there is apparently a theming issue in VS!) and pick the path of the wide tile we want to use (by default, there is one named FlipCycleTileLarge.png under Tiles in the Assets folder). This is shown in the following screenshot:

  3. Next, we need to add some code to get the push channel URI and send it to the service:

    using Microsoft.Phone.Info; using Microsoft.Phone.Notification; using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Text; using System.Threading.Tasks; using TileTapper.DataServices; using TileTapper.Models; namespace TileTapper.Helpers { public class ChannelHelper { // Singleton instance public static readonly ChannelHelper Default = new ChannelHelper(); // Holds the push channel that is created or found private HttpNotificationChannel _pushChannel; // The name of our push channel private readonly string CHANNEL_NAME = “TileTapperPushChannel”; private ChannelHelper() { } public void SetupChannel() { try { // Try to find the push channel this._pushChannel = HttpNotificationChannel.Find(CHANNEL_NAME); // If the channel was not found, then create a new
    // connection to the push service if (this._pushChannel == null ) { this._pushChannel = new HttpNotificationChannel(CHANNEL_NAME); this.AttachEvents(); this._pushChannel.Open(); // Bind channel for Tile events this._pushChannel.BindToShellTile(); // Bind channel for Toast events this._pushChannel.BindToShellToast(); } else this.AttachEvents(); } catch (Exception ex) { System.Diagnostics.Debug.WriteLine(ex.ToString()); } } private void AttachEvents() { // Register for all the events before attempting to // open the channel this._pushChannel.ChannelUriUpdated + = async (s, e) => { // Register URI with service await this.Register(); }; this._pushChannel.ErrorOccurred += (s, e) => { System.Diagnostics.Debug.WriteLine(e.ToString()); }; } private async Task Register() { try { var service = new DataService(); await service.InsertChannel(new Channel() { ChannelUri = this._pushChannel.ChannelUri.AbsoluteUri, InstallationId = this.GetDeviceUniqueName(), Platform = “wp8” }); } catch (Exception ex) { System.Diagnostics.Debug.WriteLine(ex.ToString()); } } // Note: to get a result requires // ID_CAP_IDENTITY_DEVICE // to be added to the capabilities of the WMAppManifest // this will then warn users in marketplace private byte[] GetDeviceUniqueID() { byte[] result = null; object uniqueId; if (DeviceExtendedProperties.TryGetValue(“DeviceUniqueId”,
    out uniqueId)) result = (byte[])uniqueId; return result; } private string GetDeviceUniqueName() { byte[] id = this.GetDeviceUniqueID(); string idEnc = Encoding.Unicode.GetString(id, 0, id.Length); string deviceID = HttpUtility.UrlEncode(idEnc); return deviceID; } } }

    
    

    This is a singleton class that holds an instance of the HttpNotificationChannel object, so that channel URI changes can be captured and sent up to our service. The two methods at the end of the code snippet, GetDeviceUniqueID and GetDeviceUniqueName, will give a unique device identifier for the channels table.

  4. Now that we have the code to manage the channel, we need to call the SetupChannel method in the App.xaml.cs launching method as shown in the following code snippet:

    private void Application_Launching(object sender, LaunchingEventArgs e) { TileTapper.Helpers.ChannelHelper.Default.SetupChannel(); }

    
    

LEAVE A REPLY

Please enter your comment!
Please enter your name here