Thursday, July 28, 2011

Push notifications in Windows Phone 7.5 (Mango) -part 2

This post follows up from PART 1. So far, we’ve created our custom web service and registered our phone app with the service. Now let’s implement the main operation in our web service.




Implementing PushToSubscribedPhones

This operation will be invoked from an external app that needs to have push notifications send out to registered devices. Here we need to create a web request, and depending on the type of notification we want to send out, create the payload in accordance with the required schema for that type. Then we send the request out to MPNS to each registered device, through the channelUri we stored for each device in the subscribedPhones dictionary :
public void PushToSubscribedPhones(NotificationData data)
{
foreach (var entry in subscribedPhones)
{
var uri = entry.Value;
byte[] payload;
 
var request = (HttpWebRequest)WebRequest.Create(uri);
request.Method = "POST";
request.ContentType = "text/xml";
 
if (data.PushType == "toast")
{
payload = GetToastPayload(data.Title, data.JobId);
request.Headers.Add("X-WindowsPhone-Target", "toast");
request.Headers.Add("X-NotificationClass", "2");
}
 
else if (data.PushType == "tile")
{
payload = GetTilePayload(data);
 
request.Headers.Add("X-WindowsPhone-Target", "token");
request.Headers.Add("X-NotificationClass", "1");
}
 
else //raw
{
payload = Encoding.UTF8.GetBytes(myMessageData);
request.Headers.Add("X-NotificationClass", "3");
}
 
request.ContentLength = payload.Length;
 
using (Stream requestStream = request.GetRequestStream())
{
requestStream.Write(payload, 0, payload.Length);
}
 
var response = (HttpWebResponse)request.GetResponse();
}
}
}

Here’s an example of the GetTilePayload method, that generates the message to be sent within a tile notification :


private byte[] GetTilePayload(NotificationData data)
{
string payload = string.Format(
"<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
"<wp:Notification xmlns:wp=\"WPNotification\">" +
"<wp:Tile Id=\"/Views/JobDetailsView.xaml?id=" + data.JobId + "\">") +
"<wp:BackgroundImage>{2}</wp:BackgroundImage>" +
"<wp:Count>{1}</wp:Count>" +
"<wp:Title>{0}</wp:Title>" +
"<wp:BackBackgroundImage>{3}</wp:BackBackgroundImage>" +
"<wp:BackTitle>{4}</wp:BackTitle>" +
"<wp:BackContent>{5}</wp:BackContent>" +
"</wp:Tile> " +
"</wp:Notification>",
text, data.Count, data.TileUri, data.BackTileUri, data.BackTitle, data.BackContent);
 
return Encoding.UTF8.GetBytes(payload);
}

Note a couple things : first, the message’s components are provided by the calling app through the data parameter. Second, many of these elements are actually values that will be set on the properties of the target live tile, both for the front and back side of the tile. And third, notice the Id attribute that identifies the tile targeted by the notification – remember there may be more than one tiles pinned to the phone’s start menu.

When GetResponse() is called in the previous snippet, the notification is actually sent out to MPNS, which sends back a response. Depending on network, device and other factors, MPNS will then send the notification to the registered phones.



Invoke the web service from an external app

Now that your setup is complete, you can have an external caller invoke the operation to send out information to registered devices in the form of either a push, tile or raw notification. For example, within a WPF app you may write :


pushClient.PushToSubscribedPhones(
new NotificationData
{
PushType = "toast",
JobId = job.Id,
DriverId = driverId,
Title = "Job updated : "
});

This uses an instance of the web service client proxy class, which can be generated for you by Visual Studio using the Add Service Reference command. You call the PushSubscribedPhones operation in our service (you may want to do so asynchronously).  You create a NotificationData instance to specify the information you need to pass to the phones in the notification. Note this example sends a Toast, but you can also send a Tile notification and set the properties of the target tile :


var data = new NotificationData
{
PushType = "tile",
JobId = jobId,
Title = "Cancelled",
TileUri = "/Images/TileJobCancel.png",
BackTileUri = "/Images/TileJobCancelBack.png",
Count = 0,
BackTitle = "CANCELLED",
BackContent = "Unpin this job"
};


When the phone app receives the tile notification, any pinned tile will be updated with the values passed in the message.


So we’ve gone briefly through the push notification setup process involving our phone app, a custom service, MPNS, and possibly an external caller. We could also implement the service part in the cloud, as well as the calling app if we chose to.

In a later post, I’ll discuss possible failures and how to handle them.

If you’d like me to cover certain topics, feel free to send a comment.


Happy notifications!

2 comments:

  1. Can you post an example project? In some parts of this tutorial, I got lost.

    Thanks :)

    ReplyDelete
  2. Hey Ryan, coming up with basic, self contained push examples is not easy, perhaps I can help you figure out the specific step or part that got you puzzled ?

    ReplyDelete