Category Archives: Microsoft

Working with the Windows Azure Toolkit for Android

At the end of August, Microsoft published the Windows Azure Toolkit for Android. At Neudesic, the partner behind developing the both toolkits for iOS and Android, we’ve been working with customers that use the toolkit to connect mobile applications to the cloud. One of the recent requests however has been to provide a walkthrough of getting started with the toolkit. The current build on GitHub was released for a specific version of Eclipse and the Android tools, and as a result, can be a little challenging getting the library and sample code up and running.

In this post, I’ll explain what it takes to download the toolkit, create a brand new environment in Eclipse, and get started quickly with the toolkit.

Getting Started – What You’ll Need

Firstly, there is a list of tools that you’ll need to download.

1. Eclipse. Download from – we’ll be using Helios in this tutorial.

2. JDK. We’ll be using the default that ships with Mac OSX, but if you are on a PC, you’ll need JDK 1.6 or higher.

3. Android SDK and Eclipse Tooling. Download the Android SDK from (we are using r14 for this walkthrough). Also follow the instructions for configuring the Android tooling within Eclipse. After you have installed everything, use the AVD manager to setup a new AVD for an Android 2.3.3 device.

Setting Up the Library in Eclipse

To import and build the library in Eclipse, perform the following steps.

1. Download the Windows Azure Toolkit for Android from GitHub. If you have the Git client installed, you can use this command:

git clone

Otherwise, go to the site and pull down the zip file of the repo.

2. Create a new directory for your Eclipse workspace:

mkdir wa-toolkit-android-workspace

3. Launch Eclipse, and point the default workspace to this newly created directory:

myWPEdit Image

  1. Create a new Android project called AzureLibrary, set the target to Android 2.3.3, use as the package name, but do not create an activity or test project.

myWPEdit Image

  1. Right click on the AzureLibrary project and select Import. Choose General / File System as the import source, and click on Next.
  2. Browse to the /library/src/com folder in the toolkit folder that you downloaded from GitHub.
  3. Click on the Browse (into folder) button and select the src folder under your project. Expand the src folder, and check the com folder as shown in this screenshot:

myWPEdit Image

  1. Click on the Finish button. The import will complete.

myWPEdit Image

  1. Right click on the project, select properties, and change the Java compiler version from 1.5 to 1.6. (The default is 1.5, yet the toolkit uses many constructs only supported in 1.6)

myWPEdit Image

  1. Click OK, and say yes to rebuilding the project. The project should now build with no errors.
  2. Assuming everything builds correctly, right click on the project, and select Properties again. Go to the Android setting, and click on the Is Library check box.

myWPEdit Image

Setting Up the Sample Application in Eclipse

To import and build the sample application in Eclipse, perform the following steps:

  1. Create a new Android project called AzureSample. Select Android 2.3.3, set the namespace to com.windowsazure.samples.sample, and choose not to create an activity.

myWPEdit Image

  1. As you did with the library, right click on the project, and select Import. Select the /samples/simple/src as the source and import into the AzureSample/src folder.

myWPEdit Image

  1. Right click on the project, select Properties, select Android and add a reference to the AzureLibrary project:

myWPEdit Image

  1. Right click on the project, select Import. Import from the /samples/simple/res folder into the AzureSample/res folder. This will import the resources required for the sample application.

myWPEdit Image

Answer yes when prompted to overwrite the main.xml file.

  1. Right click on project, select Import and select the file system again. Select the AndroidManifest.xml from the root of the source directory and import into the root of the destination project.

myWPEdit Image

The Sample project should now build with no errors.

Configuring your Windows Azure Account Name and Key

In order to setup the sample project, you need to supply your account name and key, as provided by Windows Azure. You can obtain this by logging into the Windows Azure Portal ( and navigating to Storage Accounts to obtain the details.

When you have the name and key, perform the following:

  1. In the sample project, open from the src/com.windowsazure.samples.sample package.
  2. At the top of the file replace the ACCOUNT and ACCESS_KEY values with the account name and access key for your Azure storage account.


Running the Sample

1. To run the sample, right click on the sample project, select Run As / Android Application.

  1. Once the emulator is up and running, unlock the device.
  2. Refer to the LogCat/Console window in Eclipse if there are any errors.
  3. Click on the Start button in the sample application.
  4. Select either table, blob, or queue storage and browse the storage associated with your Windows Azure account.

myWPEdit Image

That’s it! Your sample application is now up and running, and you are able to browse Windows Azure storage!

Upgrading your Windows Phone 7 to Mango RC

In late July, Microsoft announced availability of a new build of Mango, build 7712 – also commonly known as the RC Build.  Given that we are close to RTM, yet it may still take carriers some time before deploying Mango to your device, you might be itching to try out the new bits.  If you are, but don’t know where to start, I’ve put together this quick guide based on my own experience of updating my phone, an AT&T Samsung Focus.  Note: As you would expect, if you do decide to upgrade your phone, this is entirely at your own risk.

Before you begin, you’ll need a few things:

1.  A Windows Phone 7 device with all of the current updates (a.k.a. NoDo) installed.  Double check the updates in the Zune application to make sure everything is up to date.  You should see that your WP7 build number is 7390.

2.  Zune Software 4.7.1404.  Although 4.8 was released yesterday, you won’t be able to do the update with this version (yet).  Download 4.7.1404 from here if needed.

3.  Windows Phone 7 Support Tools.  You can download this from here (32bit, 64bit).  Run the installer, but you don’t need to run the application.

4.  Enough battery power to get you through several updates (when the phone is updating, your device isn’t being charged).  I would avoid trying this with anything less than 50% charge.

5.  The mango update tools.  If you are a registered Windows Phone 7 developer, you can supposedly download these from the Microsoft Connect site.  If you are not (or like me you are, but couldn’t find the tools on Connect), you can find a version of the tools on this site.  (Note:  Follow Step 1, and yes, you have to wait for 45 seconds for the download link to work).

With all of the above in place, run the Update.bat from the Mango update tool download.  Assuming there are no errors, you should see something similar to the following.


Firstly, the tool will make a backup of your device to the c:PreMangoState2 directory, and install the updates necessary for your device to receive the pre-release Mango bits.  The time this will take may vary, but on my machine it took 112 seconds to backup, and 70 seconds to update the device.

Once the batch file completes, and the device reboots, the Zune software should automatically launch.  You’ll be shown that an update is available (likely build 7403).


Choose to install this, which will then download the Zune 4.8 software.  After the Zune software has been updated, the phone will be updated to 7403, which should be a fairly quick update.

As the phone reboots once more, the Zune software will do another check – and this time will pick up the 7712 build, which is Mango RC.  Choose to download and install this one.  This is where the battery power is important, as this install can take quite a bit of time to complete (let’s just say that I’ve been able to pen this blog post, and it’s still not 75% of the way there!).

Be patient though – one final reboot, and you’ll be running the latest Mango RC (Build 7712) bits!  Enjoy!

Using Federated Identity for iOS Applications

Last week, Microsoft released v1.2 of the Windows Azure Toolkit for iOS.  As development partner for the toolkit, Neudesic has been working with several customers on implementing ACS for iPhone and iPad applications.  Due to popular demand, I wanted to share a short overview of how simple it is to get this up and working for your own iOS projects.

First, some background…

Many iPhone and iPad applications have a need to authenticate.  Maybe it’s to access sensitive information or record a particular high score against your name.  Implementing an authentication scheme for iOS can however be time consuming and tricky – you often have to create an authentication service, host it, expose the service through REST, and consume it on the device.  And afterwards you are responsible for backing up the user database and dealing with lost passwords, etc.

To help overcome this many applications are now turning to external providers.  For example, to identify yourself when playing Zynga Poker, instead of creating a new account, you simply sign into Facebook (when launching the application for the first time) and the game uses these credentials as you play. This type of sign in method is called federated identity. This prevents Zynga from having to maintain a complex and large set of user accounts and passwords, and also prevents the player from having to remember yet another username and password. 

Adding federated identity to your iPhone or iPad application can be difficult, requiring knowledge of exchange secure tokens with a set of providers, and creating and sending the right OAuth headers in your application.  Removing this difficultly is exactly what we are trying to address in v1.2 of the Windows Azure Toolkit for iOS. 

Sounds great – how do I use it?

To implement ACS in your application, you’ll first need to access the Windows Azure portal by navigating to and signing in with your credentials.


Click on the Service Bus, Access Control & Caching menu item and select the Access Control menu item under the AppFabric folder.  Select an active Windows Azure subscription and click on the New button in the toolbar.


The new service namespace dialog will open.  Ensure that Access Control is selected, and enter a unique namespace and country/region for the service.


The ACS namespace will now be created.  This might take a few minutes.  Wait until the namespace is showing in an Active state.


Once this is complete, highlight the newly created service and click on the Access Control Service button in the toolbar.  This will launch the Access Control Service portal.

Within the portal, click on Identity Providers and add the identity providers you would like to use for your application.


The default is Windows Live ID, but you can add other preconfigured providers (such as Google and Yahoo!) as well as external identity systems configured to use WS-Federation.

Once you have added the required providers, click on the Relying Parties section of the portal.


Click on the Add button and enter the following information for the relying party application:

Name – a given name for your application

Realm – a unique ID for your application.  For this walkthrough, we’ll be using uri:wazmobiletoolkit

Return URL – you can leave this blank

Error URL – you can leave this blank

Token Format – select SWT

Token Lifetime – Feel free to change the default from 600 seconds.

Select the identity providers that you would like to use, and then under the Token Signing Settings section, click on the Generate button to create a new symmetric key that will be used for this application.

Finally, click on the Save button.  This will create the Relying Party Application.

Next, go into the Rule Groups section of the portal and select the default rule group that was created for the application.


Click on the Generate link in order to generate a set of default rules for this rule group.


Select the providers that you wish to use, and click on the Generate button.  Once this is complete, you should see a set of rules.


After this step is complete, ACS has now been configured correctly to be used with your iOS application.  Make a note of your Service Namespace (found at the top of the portal) and Realm.

Ok, the service is now setup.  How do I use it in my Xcode project?

To start, launch Xcode (4.02 or higher) and create a new project.


From the project template dialog, select a View-based application and click on the Next button.  Enter a Product Name and Company Identifier and click on the Next button to continue.  Select a directory to use for the project file and return to the IDE.

Next, download the latest version of the Windows Azure Toolkit for iOS library from In the download will be a zip file containing two versions of the library (one for the device, one for the simulator) and some header files for the project.

Right click on your project and select the Add Files to… menu option.


Locate the .a file (for the simulator) and header files and add them to your project.  You may want to create a new group (called lib) to store these in.


Now we need to add a reference to a library required for XML parsing.  To do this, click on the top most project file, click on the target in the 2nd column of the IDE, and select Build Phases from the tab menu.


In the main window, expand the Link Binary with Libraries option.

Ensure that the libwatoolkitios.a file has been automatically added as a reference, click the + button to add a new library, and select the libxml2.dylib library from the drop down list.


Click on the Add button to add a reference to this library for your project.

Before we start adding any code, we need to add a couple of required linker flags to the project.  To do this, click on the Build Settings tab (next to Build Phases).

In the search box, type “other linker” to filter the settings.


You should see a setting called Other Linker Flags.  Double click on the right side of this row to add new flags.

Click on the + button to add two flags.  The first is –ObjC and the second is –all_load.  Once complete, your linker flags should look like the following screenshot:


Click on the Done button to save these settings.  The project is now configured correctly to reference the Windows Azure Toolkit library.

To test that the library works, click on the project’s [ProjectName]AppDelegate.m file.  Add the following #import statement at the top of the class:

#import "WACloudAccessControlClient.h"

Next, search for a method called didFinishLaunchingWithOptions and after the [self.window makeKeyAndVisible] line, enter the following code.

NSLog(@"Intializing the Access Control Client...");

WACloudAccessControlClient *acsClient = [WACloudAccessControlClient accessControlClientForNamespace:@"iostest-walkthrough" realm:@"uri:wazmobiletoolkit"];

[acsClient showInViewController:self.viewController allowsClose:NO withCompletionHandler:^(BOOL authenticated) {

if (!authenticated)


NSLog(@"Error authenticating");




NSLog(@"Creating the authentication token...");

WACloudAccessToken *token = [WACloudAccessControlClient sharedToken];

/* Do something with the token here! */



Replace the namespace and realm in the first line with the service namespace and realm for your own service.

As you can see from the above, the code creates a new instance of the access control client, requests that the client shows itself in the current view controller, and then extracts a token.

Build and run the application in the iOS Simulator.

Once the application starts, you should be prompted to select an identity provider from the list that you configured in your ACS service.


Pick one of the providers, and enter a valid set of credentials.


Click on the Remember me checkbox if you want to skip this step when running this application again, and click on the Sign in button.

The first time the application is run, you’ll be prompted to authorize the application to access your provider data.


Click on the Allow button to continue.  The login window will now disappear and you’ll be returned to your application.

In the debug window, you should see the following two logs:

2011-07-22 10:12:26.284 iostest-walkthrough[25838:207] Intializing the Access Control Client…

2011-07-22 10:12:36.359 iostest-walkthrough[25838:207] Creating the authentication token…

If you are seeing this, congratulations!  You’ve successfully setup federated identity for your application.  The final message indicates that the access token was retrieved and can be used for further use.  The WACloudAccessToken (derived from [WACloudAccessControlClient sharedToken]) contains an NSDictionary of claims and other properties that can be stored within your application.  Using these properties on future calls can be used to identify returning users to your application.

Running Visual Studio 2010 on the Mac

Following a few recent presentations, I’ve had a couple of people ask how I run Visual Studio on the Mac.

You’ll be sad to hear that I don’t have a special version of Visual Studio for Mac OSX – instead I am using VMWare Fusion 3.1 to run a copy of Windows 7 in a virtual machine. Fusion has a mode called “Unity” which allows windows from the virtual machine to interact with windows on the host operating system (even to the point where I can put icons for Windows-based applications in the dock on the Mac). There is a little performance hit running applications in this way vs. a full screen virtual machine, but it’s certainly useful for presentations where you are flipping between both environments.

TechEd 2011 Slides – DPR304

Thanks to everyone that came to my session at TechEd 2011 yesterday – it was a great crowd, and the presentation was a lot of fun to put together. My apologies for any confusion with the title (i.e. not making it explicit that it was a developer talk in the title) – this will definitely be something that we address next time.

You can find the slides from the talk below, and the source code of all demos can be found on GitHub. Hope you enjoy, and look forward to any feedback.

*** Update – corrected Session code in title ***

Using Apple Push Notifications from Windows Azure

In my MIX11 session last week I demonstrated how to create push notifications to iPhone and iPad devices from Wndows Azure.  I’ve put together this blog post to share more detail and the source code for how this works.

Firstly, if you haven’t already, you will need to register your iPhone/iPad application for push notifications.  To do this, log into the iOS developer center (you’ll need to be a registered Apple Developer) and in the provisioning portal setup a new App ID, enabling it for push notifications.  Here’s the App ID for my MIX demo:


With the development certificate that you downloaded during this process, create a new Azure worker role and import the certificate into a folder called “certs”:  In addition, you’ll need to configure the properties of the certificate file such that the build action is set to “Content”.


(I’ve deliberately skimmed over the previous points of creating and App ID and Azure Worker role as they are both well documented by Apple and Microsoft).


To start configuring the worker role for push notifications, first add a reference to the Windows Azure Storage Client (Microsoft.WindowsAzure.StorageClient) library.  In the OnRun section of the worker role, access the Azure queue that messages are going to be placed in. 

StorageCredentials creds = new StorageCredentialsAccountAndKey("YOUR ACCOUNT NAME", "YOUR ACCOUNT KEY");
CloudQueueClient cqc = new CloudQueueClient(""YOUR QUEUE URL”, creds);
var testQueue = cqc.ListQueues().First(q => q.Name.StartsWith("YOUR QUEUE NAME"));

Then, still within the OnRun method, create a routine that checks the queue for incoming messages and sets up the connection to the APN (Apple Push Notification) service.

while (true)

                if (testQueue.RetrieveApproximateMessageCount() != 0)

                    List messages = testQueue.GetMessages(testQueue.RetrieveApproximateMessageCount()).ToList();
                    foreach (CloudQueueMessage message in messages)
                        Trace.WriteLine("Retrieved message from Queue: " + message.AsString);
                        // open the APN connection
                        // send message
                        string session = message.AsString.Substring(0, message.AsString.IndexOf(':'));
                        SendAPNMessage(message.AsString, session);
                        // tear down the APN connection


You’ll probably want to do something a little more elegant than “while (true)” but this works for the purposes of this post.  Also, as I mentioned in the talk, you may or may not want to setup and tear down the connection to the APN for each message that you send.  If you are planning to send a large volume of messages to a large number of devices, Apple may view this as a denial of service attack and refuse your connection.  A more prescriptive approach in this scenario would be to instead open the connection in the OnStart method and keep it alive during OnRun.

Within the worker role, setup the following declarations.  Most of these should be straightforward, and you’ll need to replace a number of them with your own details. 

private static string HOST = "";
private static int PORT = 2195;
private static string CERT_PASSWORD = "YOUR PASSWORD";
private static X509Certificate2 CLIENT_CERT = new X509Certificate2(Environment.GetEnvironmentVariable("RoleRoot") + @"approotcertsmix11_dev_cert.p12", CERT_PASSWORD);

private static X509Certificate2Collection CLIENT_CERT_COLLECTION = new X509Certificate2Collection(CLIENT_CERT);
private static string DEVICE_TOKEN = "YOUR DEVICE TOKEN";  //Replace this with the Device token we obtain later on in this example

private TcpClient client;
private SslStream sslStream;

With these declarations in place, we can now start writing the APN code.  First, create an IntializeAPN method, responsible for setting up the connection to the APN.

private void InitializeAPN()
    client = new TcpClient(HOST, PORT);
    sslStream = new SslStream(client.GetStream(), false);

        sslStream.AuthenticateAsClient(HOST, CLIENT_CERT_COLLECTION, SslProtocols.Tls, false);
    catch (AuthenticationException ex)
        Trace.WriteLine("Could not open APN connection: " + ex.ToString());
    Trace.WriteLine("APN connection opened successfully.");

Then, create a method called SendAPNMessage which will construct and sent the push notification message in the correct format. 

private void SendAPNMessage(string message, string session)
                MemoryStream memoryStream = new MemoryStream();
                BinaryWriter binaryWriter = new BinaryWriter(memoryStream);

                // construct the message

                // convert to hex and write
                byte[] deviceToken = new byte[DEVICE_TOKEN.Length / 2];
                for (int i = 0; i < deviceToken.Length; i++)
                    deviceToken[i] = byte.Parse(DEVICE_TOKEN.Substring(i * 2, 2), System.Globalization.NumberStyles.HexNumber);

                // construct payload within JSON message framework
                String payload = "{"aps":{"alert":"" + message + "","session":""+session+"","badge":1}}";

                // write payload data
                byte[] payloadBytes = System.Text.Encoding.UTF8.GetBytes(payload);

                // send across the wire
                byte[] array = memoryStream.ToArray();
            catch (Exception ex)
            Trace.WriteLine("Message successfully sent.");

You’ll notice that my SendAPNMessage method signature contains a “session” value.  For the purposes of the demo, I was sending across the session code that had changed as an explicit value in the notification message.  Feel free to change or remove this as you need.

Finally, the close method is called to close the connection.

private void CloseAPN()

At this point, you might be wondering how you obtain the DEVICE_TOKEN value for the above.  This is not the UDID of the device, but instead a separate token that is generated by the phone itself.  To get this token, and to handle incoming push notifications, let’s turn our attention to the XCode project.  For my demo I was receiving push notifications within a PhoneGap application, but this code will work equally in a regular native client application.

First, we need to instruct the application to register for APN messages.  This is done using the registerForRemoteNotificationTypes method.  You’ll need to call this method when the application first starts up (for PhoneGap projects, this can be in the init method of the AppDelegate).

NSLog(@"Registering for APN");
[[UIApplication sharedApplication] registerForRemoteNotificationTypes: (UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound)];

This method has three callbacks that it can take advantage of.  One to indicate that registration was successful (we also get the Device ID from here), one to indicate that something went wrong (e.g. if we are running in the simulator, which doesn’t support push notifications), and one for when we actually receive a message).

The first two are easy to handle:

- (void)application:(UIApplication *)app didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
    NSString *str = [NSString stringWithFormat:@"Device Token=%@",deviceToken];

- (void)application:(UIApplication *)app didFailToRegisterForRemoteNotificationsWithError:(NSError *)err {
    NSString *str = [NSString stringWithFormat: @"Error: %@", err];

Note how the first method (didRegisterForRemoteNotificationsWithDeviceToken) is where we actually extract the DEVICE_TOKEN string required in the worker role.  You’ll have to run this once, and copy and paste appropriately.  Of course, in a production environment, we would likely pass this value to the service via a separate call. 

The third callback gets called when the device actually receives a message.

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
    for (id key in userInfo) {
        NSLog(@"key: %@, value: %@", key, [userInfo objectForKey:key]);
        NSString *payload = [NSString stringWithFormat:@"%@",[userInfo objectForKey:key]];
        // work out the session code from the JSON payload
        NSRegularExpression* regex;
        NSTextCheckingResult* result;
        NSError* error = nil;
        NSString* regexStr = @"session = ([^']*);";
        NSString* value = nil;
        regex = [NSRegularExpression regularExpressionWithPattern:regexStr options:NSRegularExpressionCaseInsensitive error:&error];
        result = [regex firstMatchInString:payload options:0 range:NSMakeRange(0, payload.length)];
        if(result && [result numberOfRanges] == 2)
            NSRange r = [result rangeAtIndex:1];
            value = [payload substringWithRange:r];
            NSLog(@"Found session value in payload: %@",value);
            NSString* jsString = [NSString stringWithFormat:@"handleOpenURL("");",value];
            [webView stringByEvaluatingJavaScriptFromString:jsString];


As you can see above, this method parses the payload of the message, tries to work out the session code, and if one is found, creates a new javascript call to a method called handleOpenURL which instructs PhoneGap to call the method of the same name.  Of course, you are going to want to configure this for your own scenario, but hopefully this gives you a sense of how to pass a value as part of the message, and then take an action on that accordingly. 

Well, that wraps up this post.  I hope you enjoyed the talk at MIX, and that this code is useful if you have services in Windows Azure that have a need to push notification messages to iPhone and iPad devices.


Meet me for lunch!

I’m on the road for the next few weeks, visiting locations across the US, holding a series of “Mobility lunches”.  These lunches are a great way to get up to speed with what mobility means for your organization – from the current state of the mobile market, handsets, tablets, through to building applications and solutions for your own employees and customers.

Each event is held over lunch, and it’s a great opportunity to network with peers in your region as well as folks from the local Neudesic office.  Here is the schedule – it’s free to attend, although you do have to register!  Look forward to seeing you there!

April 19 – San Diego

April 20 – Los Angeles

April 26 – Denver

April 27 – Las Vegas

April 28 – Phoenix

May 5 – Orange County

May 10 – Chicago

May 11 – New York

May 12 – Philadelphia

May 31 – San Francisco

June 1 – Seattle

June 7 – Dallas

June 8 – Houston

Developing iPhone and iPad apps that leverage Windows Azure

Thanks to all that came to my session at MIX11 last week – it was a lot of fun to put together despite a couple of demo glitches!  You can now view the recording of this online, as well as browse and download the slides below. 

I’ll be sharing the source code for the demos in the next couple of posts.

Speaking at MIX11

Just in case you are interested, I will be presenting at MIX11 next week in Vegas.  Mix has always been one of my favorite conferences, and I’m looking forward to speaking. 

Here are the details:

EXT18 – Developing iPhone and iPad Apps that Leverage Windows Azure

You are building apps for the iPhone/iPad, yet you remain curious about what the cloud can offer. Is it possible to deploy scalable, mobile Web applications on Windows Azure? How about storing data in the cloud? Is it possible to use the cloud for push notifications to the device? In this session you’ll learn how to integrate iOS applications into an existing Windows Azure infrastructure, and what types of applications other organizations are building. You’ll walk away confident in knowing how to extend your existing applications to take advantage of features on the device together with services in the cloud.

Lagoon F on Thu, Apr 14 1:30 PM – 2:30 PM

I’m hoping it’s going to be a fun session, and we’ll be investigating the many different ways that Windows Azure can be used to create applications for iOS devices. 

Hope to see you there!

April 12-14, 2011 - Mandalay Bay, Las Vegas

Targeting iPhone, iPad, and Android – WebCast Recording

Thanks to all that attended the Neudesic Mobility Webcast this morning on “Building solutions on the Microsoft platform that target iPhone, iPad, and Android devices”.  It was fun to put together, and even though we went over time, the feedback was great.

For those that couldn’t make it, we’ve posted the recording of the session, together with the slides below.  Hope you enjoy the material!