This article is written for earlier version of Silverlight for Windows Phone 7 and may not be fully compatible with the latest version.
Why is multitasking missing and how to hide the fact?
Windows Phone 7 at this very moment does not support Multitasking for 3rd party applications. There are a lot of reasons for that and as an IPhone user I could not agree more with this decision. Running different applications parallel means more power consumption, more memory consumption and higher cpu load. These factors directly lead to reduced User Experience, like your battery says goodbye in a couple of hours, the screen is not so smooth when using multitouch, it’s „lagging”, or changing between applications might get really slow. No matter how evolved are today’s smartphone hardwares, these devices are not PCs at this very moment. On reduced performance capabilities, you expect lot more innovative applications, higher user experience, more sci-fi like user interfaces than on a PC . You want high definition media, real-“time-ish” connection to you social networks, to your social “identity”. So sacrifices and compromises must be made, so Microsoft had to sacrifice Multitasking in favor of higher user experience and performance. The end user is the king! The end user is not me and it’s probably not you. Microsoft introduced the end users to us. They were Anna and Miles :) I am not Miles and definitely not Anna :) They are two personas created by Microsoft to represent the target market for this phone. While you and I might miss Multitasking Anna and Miles don’t know what multitasking is. You know what? They don’t want to know! Microsoft does a pretty could job to hide the lack of this feature and provides different workarounds to make Anna and Miles think, that they can do many things with their phone at the same time. So how can they miss something, if to them it seems like it’s there?
The Push Notification Experience
To hide the lack of multitasking Microsoft uses different concepts to simulate parallel-ish behavior. One of these is the Push Notification feature.
Okay, what is Push Notification? For Anna and Miles Push Notification means that their applications can tell them if there is something new, there is something interesting, even if the application is not in the foreground! They just tap on the notification and the application comes up and shows whatever is necessary.
How push notification works
For you and me it’s really different. The Push Notification feature consits of many components.
- The Windows Phone application
- Custom (cloud)service to provide the data
- Push Notification Service
- Push Client
So your Windows Phone 7 application get’s the data from a service. But what happens if your application dies? (e.g. gets wiped out of memory) It won’t have to chance to poll your service for more data. (which would consume a lot of resources by the way).
- So your WP7 application has the opportunity to open up an HttpChannel and tell the Push Notification Service that it wants to accept notifications after its lifetime.
- Your WP7 application tells the Push Client, built into your phone, where to display the message when it arrives.
- The Push Notification Service returns a URL for your application.
- The Windows Phone 7 application now can send this url to your custom service, that has your data.
- Your custom service can send information to the Push Notification Service using this url.
- The Push Notification Service identifies your phone by this url and pushes down the data to the Push Client, built into your phone
- The Push Client transfers the message where it was told to.
- Tapping on the message opens up the application.
It’s simple as that!
The Push Notification Service pushes the messages arrived from different source to the push client in packages in a timely fashion. Please note that the service DOES NOT guarantee message delivery. Which means that your message probably arrives but you cannot count on it! So you should use push notification only in scenarios where losing a message is not critical.
Push Notification Types
Windows Phone 7 support 3 types of notification:
- Raw Notification
In this case your application runs and you get a push notification while running.
- Toast Notification
In this case your application might or might not run but the message will be displayed anyway as a toast message.
- Tile Notification
If you pin down your application on the main screen, you can tell the shell that when a notification arrives change to picture (the tile) on the main screen. In this case your application is not running.
Okay but how to implement that?
Implementing a Toast Notification
Preparing your phone to accept push notifications is very easy.
Step 1
You have to setup an HttpNotificationChannel to get the URL and you have to pass that to your custom (cloud) service.
private void SetupChannel()
{
HttpNotificationChannel httpChannel = null;
string channelName = "DemoChannel";
try
{
Debug.WriteLine("Creating Channel");
httpChannel = new HttpNotificationChannel(channelName);
//When we get the URI (which might change anytime)
httpChannel.ChannelUriUpdated += new EventHandler<NotificationChannelUriEventArgs>(httpChannel_ChannelUriUpdated);
//When something bad happens
httpChannel.ExceptionOccurred += new EventHandler<NotificationChannelExceptionEventArgs>(httpChannel_ExceptionOccurred);
Debug.WriteLine("Opening Channel");
//Tell push client to register us for push notification
httpChannel.Open();
Debug.WriteLine("Binding to Shell, (Toast)");
//Register for a Notification type
BindToShell(httpChannel);
}
catch (NotificationChannelExistsException)
{
Debug.WriteLine("Channel Exists, retrieving existing channel");
httpChannel = HttpNotificationChannel.Find(channelName);
//If we can't get it, then close and reopen it.
if (httpChannel.ChannelUri == null)
{
Debug.WriteLine("Cannot retrieve channel, retrying...");
httpChannel.UnbindToShellEntryPoint();
httpChannel.Close();
//Re-try
SetupChannel();
return;
}
else
{
ChannelUri = httpChannel.ChannelUri;
Debug.WriteLine("Channel retrieved: " + httpChannel.ChannelUri);
//Make sure, binding to shell exists
BindToShell(httpChannel);
}
}
catch (NotificationChannelOpenException)
{
Debug.WriteLine("Channel is already open");
httpChannel = HttpNotificationChannel.Find(channelName);
ChannelUri = httpChannel.ChannelUri;
//Make sure, binding to shell exists
BindToShell(httpChannel);
}
}
private static void BindToShell(HttpNotificationChannel httpChannel)
{
//This is a toast notification
try
{
httpChannel.BindToShellNotification();
}
catch (NotificationChannelBindingExistsException)
{
}
//This is a tile notification
//ShellEntryPoint Tile = new ShellEntryPoint();
//Tile.RemoteImageUri = new Uri("http://shared.live.com/7E81kqTseEOmzDlpeFPS8g/Web/images/grouplogo.png");
//httpChannel.BindToShellEntryPoint(Tile);
}
void httpChannel_ExceptionOccurred(object sender, NotificationChannelExceptionEventArgs e)
{
//Display Message
Dispatcher.BeginInvoke(() =>
{
txtError.Text = e.Exception.Message;
});
}
void httpChannel_ChannelUriUpdated(object sender, NotificationChannelUriEventArgs e)
{
//We get the new Uri (or maybe it's updated)
ChannelUri = e.ChannelUri;
//Now pass this Uri to your custom service.
//It should now where to send the data
//....
}
Step 2
We have to tell the push client what kind of notification we’re expecting. So let’s setup a toast notification:
httpChannel.BindToShellNotification();
This was easy, wasn’t it :)
I have to mention that you really need to get ready for exceptions since the HttpNotificationChannel and the Open() method really loves to throw all kinds of exceptions like NotificationChannelExistsException or NotificationChannelOpenException. If your channel is already open and did not close before, you can get the instance by calling HttpNotificationChannel.Find(string channelName).
In the previous code sections we mentioned that the channel url should be sent to our custom service.
Step 3
So we are ready to accept Push Notifications. But how can we send them? You have to compose HTTP Messages and send them to the url you received from the phone!
HttpWebRequest sendNotificationRequest = (HttpWebRequest)WebRequest.Create(subscriptionUri);
sendNotificationRequest.Method = "POST";
//Indicate that you'll send toast notifications!
sendNotificationRequest.ContentType = "text/xml";
sendNotificationRequest.Headers = new WebHeaderCollection();
sendNotificationRequest.Headers.Add("X-NotificationClass", "2");
if (string.IsNullOrEmpty(txtMessage.Text)) return;
//Create xml envelope
string data = "X-WindowsPhone-Target: toast\r\n\r\n" +
"<?xml version='1.0' encoding='utf-8'?>" +
"<wp:Notification xmlns:wp='WPNotification'>" +
"<wp:Toast>" +
"<wp:Text1>{0}</wp:Text1>" +
"</wp:Toast>" +
"</wp:Notification>";
//Wrap custom data into envelope
string message = string.Format(data, txtMessage.Text);
byte[] notificationMessage = Encoding.Default.GetBytes(message);
// Set Content Length
sendNotificationRequest.ContentLength = notificationMessage.Length;
//Push data to stream
using (Stream requestStream = sendNotificationRequest.GetRequestStream())
{
requestStream.Write(notificationMessage, 0, notificationMessage.Length);
}
//Get reponse for message sending
HttpWebResponse response = (HttpWebResponse)sendNotificationRequest.GetResponse();
string notificationStatus = response.Headers["X-NotificationStatus"];
string notificationChannelStatus = response.Headers["X-SubscriptionStatus"];
string deviceConnectionStatus = response.Headers["X-DeviceConnectionStatus"];
Okay this is just a little bit more complex. Personally I’d prefer to write a couple of wrapper classes so the developer doesn’t have to do this. So we created and HttpWebRequest with Post Method type. We add an X-NotificationClass header with the value of 2 which stands for Toast Notifications and (real-time) batching intervals. Next we create an xml envelope-like string to wrap our message. We push our wrapped message into the request stream. We send the request and wait for the answer. The answer is very important because we have to know what’s up with our phone! Is it still connected? Is it still listening? If not, then we should stop sending messages to this url.
Step 4
Make sure, that in the WMAppManifest.xml, the App element has a publisher attribute, and it is set to some constant string. Otherwise you may get a lot of NofiticationChannelExistsException. (Not sure why, and why this is not documented)
Summary
So basically this is it. It’s really not complicated to work with push notification. Most importantly it helps to make the user think that his application is still active even if its not in the foreground. It’s definitely not multitasking and push notification won’t help you make more battery power. But it’s still less expensive than doing actual multitasking. Of course by itself, Push Notification doesn’t replace multitasking or solve the problem, but it definitely does a good job on helping the issue. I think Anna and Miles will be happy with it :)
You can download the source code from here: (a WPF service emulator and the windows phone project)
Download source code