Nico's digital footprint

I grew up in the nineties, that makes me awesome by default

Launching a Win8 app from WP8 with Azure custom API

by Nico

Imagine you have an app where people can browse through all sorts of data, let’s take Wikipedia for example. You find an interesting article on the Wikipedia app on your Windows Phone device. A phone screen is (usually) pretty small so it would be nice if we could just send that article to our pc where a toast pops up, when the toast is clicked the Wikipedia app on Windows 8 opens up on that same article. A nice experience for the user, added value for our apps and not too hard to do.

The Service

As the title of this post mentiones, we’re going to use Windows Azure Mobile Services for this. A while ago Microsoft launched the custom API option in Mobile Services (WAMS for short) and those custom APIs are just what we need.

The server side of WAMS uses Node.js so that means:

We’ll start by creating a new Mobile Service (if you don’t know how, follow this tutorial to the point where they’re creating a new app, we’ll create the app manually).

Once the mobile service is created, navigate to the API tab and add a new API. Gave it a name and leave the permissions default. The end result should look like this.

Click the arrow icon next to the API name to start editing the script. The script looks like this by default.

Code Snippet
  1. exports.post = function (request, response) {
  2.     // Use "request.service" to access features of your mobile service, e.g.:
  3.     //   var tables = request.service.tables;
  4.     //   var push = request.service.push;
  5.  
  6.     response.send(statusCodes.OK, { message: 'Hello World!' });
  7. };
  8.  
  9. exports.get = function (request, response) {
  10.     response.send(statusCodes.OK, { message: 'Hello World!' });
  11. };

There are options here both for POST and GET methods, implemented with Hello World stuff. We’ll only be needing the POST part, the GET method we’ll just leave alone.

This is the new POST method:

Code Snippet
  1. exports.post = function (request, response) {
  2.     process.env.WNS_CLIENT_ID = 'YOUR_CLIENT_ID_HERE';
  3.     process.env.WNS_CLIENT_SECRET = 'YOUR_CLIENT_SECRET_HERE';
  4.  
  5.     var wns = request.service.push.wns;
  6.     var message = request.body.message;
  7.     var title = request.body.title;
  8.     var launchParam = request.body.launchParam;
  9.     var channel = request.body.channel;
  10.  
  11.     wns.sendToastText02(channel, {
  12.         text1: title,
  13.         text2: message
  14.     },
  15.          {
  16.              launch: launchParam,
  17.              success: function () {
  18.                  response.send(statusCodes.OK, { isSuccess: true, response: statusCodes.OK });
  19.              },
  20.              error: function () {
  21.                  response.send(statusCodes.OK, { isSuccess: false, response: statusCodes.NOK });
  22.              }
  23.          }
  24.          );
  25.  
  26. };

You’ll notice on line two and three that you’ll need to insert your own client ID and client secret. To get those we’ll need to create a new app on the Windows Store developer site.

Give an app name to the new app, save it and open the Services option.

On the services page, click on “Live Services Site”, on that site select “Authenticating your Service” and take note of the Client ID and Client Secret.

Usually, when using push notifications from a WAMS we can add those two keys into the management portal on Azure. However, when using a Custom API the WNS (Windows Notification Service) doesn’t seem to know that they are there. That’s the reason we’re including them into the script code here on lines two and three.

Last step here is to create a new Windows Store application in Visual Studio, Right-click the project, select Store and associate it with the app we’ve just created on the Windows Developer portal.

We now have an application hooked up to a registered application on the Windows Developer portal with access to WNS through the client ID and secret.

Let’s have a look at the rest of the script.

Code Snippet
  1. var wns = request.service.push.wns;
  2. var message = request.body.message;
  3. var title = request.body.title;
  4. var launchParam = request.body.launchParam;
  5. var channel = request.body.channel;

In the build-in API of WAMS we have access to an object called push. Push has a reference to WNS and can call push notifications. In a custom API we can find the Push object in request.service. Message and Title will be the content of the toast, channel is the channel used to send the toast from the server to the client and launchParam is what will determine the page we navigate to when the toast is clicked. All these parameters will be send over the wire from the Windows Phone app.

Code Snippet
  1. wns.sendToastText02(channel, {
  2.     text1: title,
  3.     text2: message
  4. },
  5.      {
  6.          launch: launchParam,
  7.          success: function () {
  8.              response.send(statusCodes.OK, { isSuccess: true, response: statusCodes.OK });
  9.          },
  10.          error: function () {
  11.              response.send(statusCodes.OK, { isSuccess: false, response: statusCodes.NOK });
  12.          }
  13.      }
  14.      );

This piece of the script will do the actual sending of the push notification. We call the sendToastText02 method on the wns object (for an overview of all the possibilities of wns, have a look at MSDN). The parameters for the method are simple, first it needs the channel. The channel is a direct link between an installation of your app and the server. It’s unique for every installation of the app. Next parameter is the payload of the toast, the information that will be shown on the toast message itself. Third parameter are the options. This is where we pass the launch parameters for the Windows app and the functions for success and error.

That’s all for the script. Pretty easy right?

Windows Phone app

The Windows Phone app is pretty straightforward as well. In this proof of concept it’ll just be an app with a bunch of buttons, when the Windows 8 app starts it will show the button that was clicked on the phone. Create a new Windows Phone 8.0 application and add the following NuGet package to the project.

Install-Package WindowsAzure.MobileServices

This will install the WAMS SDK into the project. We’ll need this SDK to fetch the channel and request the toast message.

The Windows Phone app only has one page with a really simple layout

Code Snippet
  1. <!--  ContentPanel - place additional content here  -->
  2. <StackPanel x:Name="ContentPanel"
  3.             Grid.Row="1"
  4.             Margin="12,0,12,0">
  5.     <TextBlock Text="Enter ID" />
  6.     <TextBox x:Name="TextBoxId" />
  7.     <Button Click="Button_Click" Content="Button 1" />
  8.     <Button Click="Button_Click" Content="Button 2" />
  9.     <Button Click="Button_Click" Content="Button 3" />
  10.     <Button Click="Button_Click" Content="Button 4" />
  11.     <Button Click="Button_Click" Content="Button 5" />
  12.     <Button Click="Button_Click" Content="Button 6" />
  13.     <Button Click="Button_Click" Content="Button 7" />
  14.     <Button Click="Button_Click" Content="Button 8" />
  15. </StackPanel>

A Textbox that will hold an ID and 8 buttons that use the same click event handler. The Windows 8 app that we’ll build in a minute will request a Channel from WNS, we’ll save that channel into our WAMS database. The ID that we enter here in the textbox is the ID of the record that holds the channel that we want to use. That means that in a real app, you’ll need to find a way to get the ID from the Windows 8 app into the Windows Phone app. Possibilities here are NFC or QR codes, or just plain text. Alternatively, you could use the username from a Microsoft Account to store and retrieve the channel instead of an ID.

Next we need to initialize the WAMS SDK in App.xaml.cs

Code Snippet
  1. public partial class App : Application
  2. {
  3.      public static MobileServiceClient MobileService = new MobileServiceClient(
  4.             "https://nicopushdemo.azure-mobile.net/",
  5.             "qCWCpYmWlJiOyXFQnKscFYnNixruku41"
  6.         );

You’ll need the values of your own service here of course. It can be found by going to the Azure management portal, selecting your WAMS and opening the “Connecting an existing application” option.

Here’s the button event handler for the eight buttons

Code Snippet
  1. private async void Button_Click(object sender, RoutedEventArgs e)
  2. {
  3.     Notification notification = new Notification();
  4.  
  5.     notification.Channel = await FetchChannel(int.Parse(TextBoxId.Text));
  6.     notification.Message = "Click to launch the app";
  7.     notification.Title = "Message from the Phone app!";
  8.     notification.LaunchParam = ((Button) sender).Content.ToString();
  9.  
  10.     var response = await App.MobileService.InvokeApiAsync<Notification, NotificationResult>("notifications", notification);
  11.  
  12.     if (response.IsSuccess)
  13.     {
  14.         MessageBox.Show("Toast succes!");
  15.     }
  16. }
  17.  
  18. private async Task<string> FetchChannel(int id)
  19. {
  20.     var channels = await App.MobileService.GetTable<Channel>().Where(c => c.Id == id).ToListAsync();
  21.  
  22.     return channels[0].ChannelUri;
  23. }

When one of the buttons is clicked an instance of Notification is created, Notification is a class that we build ourselves, looks like this

Code Snippet
  1. public class Notification
  2. {
  3.     [JsonProperty(propertyName: "message")]
  4.     public string Message { get; set; }
  5.  
  6.     [JsonProperty(propertyName: "title")]
  7.     public string Title { get; set; }
  8.  
  9.     [JsonProperty(propertyName: "channel")]
  10.     public string Channel { get; set; }
  11.  
  12.     [JsonProperty(propertyName: "launchParam")]
  13.     public string LaunchParam { get; set; }
  14. }

FetchChannel will use the entered ID to fetch the channel from the WAMS database (saving the channel in the DB will be done from the Windows Store app). The LaunchParam is the content from the button that was clicked.

Once the Notification instance is filled up, we call the custom API by calling InvokeAPIAsync, the generic types passed in are the type of the parameter and the type of the expected result. The expected result is NotificationResult

Code Snippet
  1. public class NotificationResult
  2. {
  3.     [JsonProperty(PropertyName = "isSuccess")]
  4.     public bool IsSuccess { get; set; }
  5.  
  6.     [JsonProperty(PropertyName = "response")]
  7.     public string Response { get; set; }
  8. }

The parameters for InvokeApiAsync are the name of the custom API, the object of the same type that was specified. The WAMS SDK will take care of deserializing that object into a JSON format using Json.NET before sending it over the wire to our API.

Windows 8 app

The final piece of the puzzle is the Windows 8 app. This is a very basic app consisting of two pages. An empty MainPage and a SecondPage. This to prove that you can navigate to any page when launched from a toast.

Create an empty Windows 8 app and once again add the WAMS SDK through NuGet.

Install-Package WindowsAzure.MobileServices

We’ll start by initializing the WAMS SDK in App.xaml.cs

Code Snippet
  1. sealed partial class App : Application
  2. {
  3.      public static PushNotificationChannel CurrentChannel { get; private set; }
  4.  
  5.      public static MobileServiceClient MobileService = new MobileServiceClient(
  6.              "https://nicopushdemo.azure-mobile.net/",
  7.              "qCWCpYmWlJiOyXFQnKscFYnNixruku41"
  8.          );
  9.  
  10.      private async void AcquirePushChannel()
  11.      {
  12.          CurrentChannel = await PushNotificationChannelManager.CreatePushNotificationChannelForApplicationAsync();
  13.          var settings = Windows.Storage.ApplicationData.Current.LocalSettings;
  14.  
  15.          if(settings.Values.ContainsKey("channel"))
  16.          {
  17.              string previousChannel = settings.Values["channel"].ToString();
  18.  
  19.              if(previousChannel == CurrentChannel.Uri)
  20.                  return;
  21.          }
  22.  
  23.          settings.Values["channel"] = CurrentChannel.Uri;
  24.  
  25.          await MobileService.GetTable<Channel>().InsertAsync(new Channel{ChannelUri = CurrentChannel.Uri});
  26.      }

A bit more initial work needed here. First the same codeblock as the one in the WP8 app. Next is the AcquirePushChannel method. This one will ask WNS for a push channel, save it to the WAMS DB and into the Application’s settings. This is because a channel has a lifetime, during this time the application will be able to reuse that same channel. On every app start we’ll check if the channel we receive from WNS is the same one that is stored in the WAMS DB, if it isn’t we store it again.

Now, the magic also happens here in App.xaml.cs, at the end of the OnLaunched method.

Code Snippet
  1. string launchArgs = e.Arguments.Trim().ToString();
  2. if (launchArgs != string.Empty)
  3. {
  4.     rootFrame.Navigate(typeof(SecondPage), launchArgs);
  5. }
  6.  
  7. // Ensure the current window is active
  8. Window.Current.Activate();

We’ll check to see if the LaunchActivedArgs have some arguments. If they don’t, nothing special happens and MainPage is loaded. If they do, the argument will be the LaunchParams we’ve passed from the WP8 app, to the custom API. That value has now finally reached our Windows 8 app via the toast. We navigate to SecondPage and pass in the launchArgs as parameter.

SecondPage.xaml looks like this

Code Snippet
  1. <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
  2.     <TextBlock x:Name="SelectedItem" Style="{StaticResource HeaderTextBlockStyle}" />
  3. </Grid>

In the code behind of SecondPage we’ll need to override OnNavigatedTo

Code Snippet
  1. protected override void OnNavigatedTo(NavigationEventArgs e)
  2. {
  3.     SelectedItem.Text = "Navigated to this page by clicking in the phone app on " + e.Parameter;
  4.     base.OnNavigatedTo(e);
  5. }

And that’s basically it.

Making it happen

Run the Windows 8 app once, so that it’s installed on your system and a channel is registered and saved into the WAMS DB. Feel free to close the app afterwards.

Launch the Windows Phone app, insert the correct ID into the textbox and hit any of the buttons.

Click the toast when it pops up and be amazed by the result Glimlach

Conclusion

In this post I’ve talked about a way to share data between apps through the use of push notifications. When you have the same app on both Windows Phone and Windows 8 this provides a cool way for your user to switch platforms while remaining on the same part of the app.

Download the projects from my SkyDrive:


Tags:

.Net | Azure | Devices | NuGet | WP8 | WinRT | Windows 8 | XAML

  Log in

About the author

Hi,

My name is Nico, I’m an MVP Windows Platform Development living in Belgium.
I’m currently employed as a .NET consultant at RealDolmen, one of Belgium’s leading IT single source providers.

I'm also founding member and board member of the Belgian Metro App Developer Network, a user group focussed on Windows 8 and Windows Phone development. If you're in Belgium feel free to drop by if we're doing an event. http://www.madn.be

Since June 2012 I'm a proud member of Microsoft's Extended Experts Team Belgium. And in February 2013 I became a member of DZone's Most Valuable Bloggers family.

In 2013 I became a book author and wrote "Windows 8 app projects, XAML & C# edition".

In 2014 I received the MVP award for the very first time.

I hope to get feedback from my readers either through comments, mail (nico_vermeir@hotmail.com), twitter, facebook, …

 

mvp

 

mvp

 

 

MeetLogo

 

MVBLogo

mybook

 

Month List