December 2014

Volume 29 Number 12

Windows Runtime : Roaming Data Between Windows Store Apps and Windows Phone Store Apps

Tony Champion | December 2014

There’s an entirely different set of standards and expectations for today’s apps than the desktop apps of a decade ago. One of these expectations is that apps work and share data across multiple devices. If a user has the same app installed on their desktop and laptop, they’ll expect both apps to maintain the same configuration and work on the same set of data. Taking it a step further, if the same app is available on multiple devices, users will expect to be able to share data across devices.

In the world of data-driven apps, you can handle these expectations primarily on the back-end database. An app on multiple devices can query the same remote database, and give the user access to the same data. However, supporting apps with a remote database adds a tremendous overhead in terms of architecture, development and maintainability. It’s simply not necessary for all apps. Even apps that require databases might not want to support app-specific information in a database designed for multiple purposes.

Windows Store and Windows Phone Store apps address this need with the concept of roaming data. Every app automatically receives a small amount of cloud storage per user. The user can use this to save information about the app and share it across multiple installs of the app. Windows Phone Store apps and Windows Store apps take this another step and let the user share data between apps on different devices. Here, I’ll look at the uses of roaming data in your apps and how to use this data effectively across devices.

This article will use universal apps to demonstrate sharing roaming data across devices, however, these same techniques work in separate Windows Phone Store and Windows Store apps. Roaming data also works just as well across HTML- and XAML-based apps.

Use Roaming Data

One of the nicer aspects of using roaming data in your apps is that it’s automatically available and it requires no configuration or other settings. Simply use the roaming data API available to let your app take advantage of roaming data.

What to Roam The first question most developers ask is what type of data is good for roaming settings. Keep in mind there’s a tight size limit on the amount of data that can roam. That means you need to do some advanced planning.

Some of the most common things to roam are user-defined preferences and settings—aspects such as colors, fonts, options and so on. These values might take on different meanings if you’re sharing between Windows Store apps and Windows Phone Store apps, but providing a similar experience and between platforms will be a big win for your app.

Current navigation within your app can be a powerful feature. If a user pulls up a report on a Windows Phone and then logs into a computer at work, why shouldn’t the Windows Store version of the app jump straight to the same report? If a user is watching a video on a desktop, why shouldn’t the Windows Phone version jump to the same video?

Temporary data can be another candidate for roaming. If a user is in the middle of typing an e-mail on a laptop, they should be able to continue that same e-mail at their desktop.

Large datasets typically aren’t candidates for roaming data. However, you could put a key to the data set in roaming data and pull the large dataset down to the new client based on the key you share.

The list goes on, but the goal is the same. Roaming data should let the user always feel connected to your app.

Enable Roaming Data There are a couple of prerequisites for your apps to successfully sync data between devices. First, users have to log on to the device using a Microsoft account. Roaming settings are associated with an app and a Microsoft user account. If the user isn’t using a Microsoft account, the data is missing part of its key. 

Second, it’s important the user hasn’t disabled roaming data capabilities for the device. A user can do this manually or it might be a device policy applied by system administrators. If roaming data is disabled, the data won’t sync.

If roaming data isn’t enabled on a device, data is still available locally. Therefore, your app doesn’t have to worry about checking to see if roaming data is syncing and using a different workflow.

Explore the API

You’ll find the API for roaming data in the Windows.Storage.ApplicationData object. Each app maintains a single instance of ApplicationData you can reference with the Current static property:

var appData = Windows.Storage.ApplicationData.Current;

The API doesn’t include a mechanism to force roaming data to synchronize. That process is left to the device itself to manage.

You can use two types of roaming data. You’ll find the first in the RoamingSettings property of ApplicationData, which is an ApplicationDataContainer that manages key/value pairs. The settings are managed in the RoamingSettings.Values property and you can access them as a string indexed array. The keys can be any alphanumeric string up to 255 characters long. The value can be an object as long as it’s a supported Windows Runtime data type. This means you can’t store custom objects in roaming settings.

You can access roaming settings through the indexed Values property. Add or update a setting by changing the key indexed Values property to the new value. Use the Values.Remove method to remove a setting. The following code shows an example of creating, reading and removing a roaming setting:

var roamingSettings = ApplicationData.Current.RoamingSettings;
// Create setting
roamingSettings.Values["setting1"] = "My First Setting";
// Read setting
var settings1 = roamingSettings.Values["setting1"];
// Remove setting
roamingSettings.Values.Remove("setting1");
// Clear all settings
roamingSettings.Values.Clear();

Storing simple Windows Runtime data types will work for some instances. However, there are times when storing an entire object makes sense. There are a couple of ways to store classes in roaming data, but you can use an ApplicationDataCompositeValue to store more complex objects in RoamingSettings.

An ApplicationDataCompositeValue is a collection of key/­value pairs stored together. This is a great way to group items that will remain synced as a single unit. The following code shows an example of creating an ApplicationDataCompositeValue and adding it to RoamingSettings:

var compositeValue = new ApplicationDataCompositeValue();
compositeValue["firstName"] = "Tony";
compositeValue["lastName"] = "Champion";
compositeValue["age"] = 38;
roamingSettings.Values["personalInfo"] = compositeValue;

The one downfall to this approach is there’s no mechanism to automatically go to and from a complex object to an ApplicationDataCompositeValue. One approach to resolve this is to create helper functions for your classes that will handle the conversion for you. Figure 1 shows a Person class with two static methods—ToCompositeSetting and FromCompositeSetting. These methods convert the data stored in the previous example into a Person object, which will make things like data binding much less complex.

Figure 1 Convert from ApplicationDataCompositeValue to Person Class

public class Person
{
  public string FirstName { get; set; }
  public string LastName { get; set; }
  public int Age { get; set; }
  public static Person 
    FromComposite(ApplicationDataCompositeValue composite)
  {
    return new Person()
    {
      FirstName = (string)composite["firstName"],
      LastName = (string)composite["lastName"],
      Age = (int)composite["age"]
    };
  }
  public static ApplicationDataCompositeValue 
    ToComposite(Person person)
  {
    var composite = new ApplicationDataCompositeValue();
    composite["firstName"] = person.FirstName;
    composite["lastName"] = person.LastName;
    composite["age"] = person.Age;
    return composite;
  }
}

Figure 2 uses the new Person class to obtain and store the personal information in RoamingSettings.

Figure 2 Obtain and Store Personal Information in RoamingSettings

var person = new Person()
{
  FirstName = "Tony",
  LastName = "Champion",
  Age = 38
};
roamingSettings.Values["personalInfo"] 
  = Person.ToComposite(person);
if (roamingSettings.Values.ContainsKey("personalInfo"))
{
  var composite =
    (ApplicationDataCompositeValue)roamingSettings.Values["personalInfo"];
  var roamingPerson = Person.FromComposite(composite);
}

There’s a special key in the roaming settings you can use for data you need to sync immediately. Adding HighPriority to any setting will have it synced as quickly as possible. This is great for items like a current book page number, a paused video frame and anything else that will help provide a connected experience between devices. For example, if a user is watching a movie on your Windows Store app, you could provide the Windows Phone Store app with the supporting data appropriate to the user’s current location in the movie:

var roamingSettings = ApplicationData.Current.RoamingSettings;
var composite = new ApplicationDataCompositeValue();
composite["movieId"] = myVidPlayer.MovieId;
composite["position"] = myVidPlayer.CurrentTime;
roamingSettings.Values["HighPriority"] = composite;

Files are the second type of roaming data. The ApplicationData object contains a RoamingFolder property that returns a StorageFolder instance where your app can read and write files to be synced.

You can add practically any type of file to the RoamingFolder. However, the file name must conform to certain specifications. First, the maximum file name and extension length is 256 characters. Also, the file name can’t have leading spaces. There’s also a group of Unicode characters that aren’t allowed.

There are also several file types that aren’t allowed because they act like folders, such as .zip and .cab. If you add a file to the RoamingFolder that doesn’t meet these requirements, the file won’t be synced, but will still be available for local access.

One use for the RoamingFolder is storing complex objects. Here’s an example of taking the same Person object, serializing it and then writing it to a file in the RoamingFolder:

var roamingFolder = ApplicationData.Current.RoamingFolder;
// Create file and open a stream to write to
StorageFile personFile = await roamingFolder.CreateFileAsync(
  "personInfo.txt", CreationCollisionOption.ReplaceExisting);
var writeStream = await personFile.OpenStreamForWriteAsync();
// JSON serialize object
var serializer = new DataContractJsonSerializer(typeof(Person));
serializer.WriteObject(writeStream, person);
// Flush the stream
await writeStream.FlushAsync();

JSON serialization is used over XML for size considerations. With size constraints for roaming data in place, every byte counts.

You can use reverse logic to retrieve an object from the RoamingFolder. The following code demonstrates reading that same file and returning a Person object:

// Create file and open a stream to write to
var readStream = await 
  roamingFolder.OpenStreamForReadAsync("personInfo.txt");
// JSON deserialize object
var serializer = new DataContractJsonSerializer(typeof(Person));
var roamingPerson = (Person)serializer.ReadObject(readStream);

Now you can read and write roaming data to be synced between devices, but how will you know when it has been updated? This is handled by the DataChanged event in ApplicationData. Any time a device receives new roaming data, the DataChanged event will fire, passing in the updated ApplicationData object. This lets you make any adjustments to your app when data has changed. There’s no corresponding event to let you know when data has been pushed from the device. The following code demonstrates how to listen to the DataChanged event:

private void HandleEvents()
{
  ApplicationData.Current.DataChanged += Current_DataChanged;
}
void Current_DataChanged(ApplicationData sender, object args)
{
  // Update app with new settings
}

If your app is taking advantage of the DataChanged event, the SignalDataChanged method in ApplicationData is useful. Any time you update any roaming data locally, you can call that method and it will fire the DataChanged event and allow any update handlers you need to run:

// Update settings locally and raise DataChanged event
roamingSettings.Values["favoriteColor"] = "Black";
ApplicationData.Current.SignalDataChanged();

It’s important to keep track of the amount of data you’re attempting to roam. Each device has a maximum amount of data that can sync between devices, which is currently 100KB. The potential issue is it’s an all-or-nothing approach. If the total amount of data you’re attempting to sync exceeds the limit, then nothing will sync between the devices. The ApplicationData class contains a RoamingStorageQuota property that returns the total size of data allowed to be synced in kilobytes. However, ApplicationData doesn’t contain any mechanism for determining the current amount of data you’re using, so for now it’s up to you to keep track.

New versions of your app could mean new or changed settings from previous versions, as well as data from previous versions no longer being needed. To address this issue, the Windows Runtime lets you version your roaming data. You’ll find the current roaming data version to which the app is set in the ApplicationData.Current.Version. This version number is independent of the app version number and by default is set to zero. The app will sync data that matches its version number. This lets you create new data structures without fear of breaking older versions.

You can change the app version through the ApplicationData.Set­VersionAsync method. This method has two parameters, the new version number and an ApplicationDataSetVersionHandler, to let you write any code necessary to make changes to the app based on the new version.

The handler contains a single SetVersionRequest parameter. This provides the current version through the CurrentVersion property, as well as the new version in the DesiredVersion property. Your app can use these two values to handle any migrations on an iterative approach. It also contains a GetDeferralMethod that lets you hold the thread open until you have the opportunity to complete the migration. That way if you have any async calls such as reading or writing files, you can perform those functions before the version change process is complete. Figure 3shows how to migrate to a new version.

Figure 3 Update Version of Roaming Data

void SetVersionHandler(SetVersionRequest request)
{
  SetVersionDeferral deferral = request.GetDeferral();
  if (request.CurrentVersion < 1)
  {
    // Handle upgrade from 0 to 1
  }
  if (request.CurrentVersion < 2)
  {
    // Handle upgrade from 1 to 2
  }
  deferral.Complete();
}
async void SetVersion()
{
  var appData = ApplicationData.Current;
  if (appData.Version < 2)
  {
    await appData.SetVersionAsync(
      2, new ApplicationDataSetVersionHandler(SetVersionHandler));
  }
}

Share Between Windows Store and Windows Phone Store Apps

Now that you’ve implemented roaming settings in both your Windows Store and Windows Phone Store apps, the next logical step is for the two companion apps to be able to share their roaming data.

Technically speaking, in order for a Windows Phone Store app and a Windows Store app to share roaming data, they must have the same Package Family Name. This field is generated based on the Package Name. Therefore, the two apps must have the same Package Name. You can find these values by associating the apps with names in their respective stores.

The first step to submitting an app in either store is to assign the app a name. You can either create a new name or associate the app with an existing name. The list of existing names is a combination of reserved names for the store you’re in and a list of apps you have in the other store. Selecting an app in the other store will link your app, giving it the same name and letting the apps share roaming data. You can read more about what it means to link a Windows Store and Windows Phone Store app at bit.ly/10Pl2Xi.

Because the stores are still separate, the experience of linking your apps is slightly different. If you have an existing Windows Store app, you can link a Windows Phone Store app by selecting the Windows Store app in the App info section, as shown in Figure 4. You can also link a Windows Store app to an existing Windows Phone Store app up in the App name section, as shown in Figure 5.

Link a Windows Phone Store App to a Windows Store App
Figure 4 Link a Windows Phone Store App to a Windows Store App

Link a Windows Store App to a Windows Phone Store App
Figure 5 Link a Windows Store App to a Windows Phone Store App

Once you’ve created and linked the apps in the stores, the final step is to associate each of your apps in Visual Studio to those names. Right-click in your primary Windows Store and Windows Phone Store solution and select Store | Associate App with the Store. Then follow the wizard and select the correct name. This will update your Package.appxmanifest with the information entered in the store.

At this point, your apps will be able to share roaming data. Remember, it’s important to track the size of the data you’re roaming. If the storage quotas are different across the platforms, you’ll need to plan for the smaller of the two as your limit.

Debug Roaming Data

Testing your roaming settings is straightforward. Again, it’s an all-or-nothing situation. Either your roaming data is synced between devices or it isn’t. When testing the syncing process, locking the device will force the app to attempt to synchronize its data. If this doesn’t happen, there are a couple of things to consider:

  • The most common cause of data not syncing is the app has exceeded the roaming storage quota. If the total size exceeds the limit, the app won’t attempt to sync its roaming data.
  • If you’re storing your data in files, make sure you’ve closed all file handlers. Leaving files opened will maintain a lock on them and also prevent the synchronization.

Wrapping Up

Using roaming data in your apps provides your users a consistent and always-connected experience. Sharing settings, preferences, and current app state on one device and carrying it over to another device lets the users feel like it’s the same app no matter the device. Adding the ability to share data between Windows Store and Windows Phone Store apps amplifies that experience and opens up a wide range of opportunities.


Tony Championa Microsoft MVP, is the president of Champion DS and is active in the community as a speaker, blogger and author. He maintains a blog at tonychampion.net. Reach him at tony@tonychampion.net.

Thanks to the following Microsoft technical expert for reviewing this article: Robert Green