HOWTO: Track sales and downloads with XNA and Windows Phone 7 using Dotfuscator and Runtime Intelligence

Phew, that’s quite the headline. If you’re a Windows Phone 7 developer, you’re probably itching to get some real download and sales data, but Microsoft has stated that this won’t be available until the end of January 2011. Without that, you’re stuck checking the Zune marketplace rankings. These are just relative rankings however, and aren’t necessarily based on sales anyway. Some solutions for rolling our own analytics have been posted, notably here (overview of Microsoft Silverlight Analytics Framework) and here (walkthrough for Silverlight with Google Analytics).

You’ll notice that neither of those options work with XNA games (and you cannot mix XNA with Silverlight for WP7 and still pass cert). Fortunately, Microsoft announced that they would be partnering with PreEmptive Solutions to offer Dotfuscator and the Runtime Intelligence service for WP7 developers for free until the end March 2011. Nifty!

Unfortunately, I couldn’t find anywhere that really showed how to do this all the way through. I spent a couple of days on it though and now I can provide a guide based on my experiences, hopefully allowing you to avoid some of the gotchas. This is a long one, but hopefully you’ll get a good sense of what’s actually happening this way.

Overview

The plan here is to use Dotfuscator to instrument our existing game in such a way that it sends messages to the Runtime Intelligence server, where we can later log in and view analytic data. This guide focuses on using the Dotfuscator UI to instrument our project after it has been compiled, though you could theoretically tag your source code with the necessary attributes instead. By using the UI, we can tag methods in our game with attributes that specify what data we should send. The .xap is then rebuilt with the additional functionality, without modifying the source code.

In a nutshell:

  1. Get the required tools.
  2. Instrument our game and rebuild the .xap from the Dotfuscator UI.
  3. Run it.
  4. View analytics data on the Runtime Intelligence portal.

You’ll see that there’s a bit more to it than that, but this is all that is absolutely required.

Getting Started

First off, the partnership between Microsoft and PreEmptive for WP7 seems to be a bit last minute. In particular, there is no version of Dotfuscator specifically for WP7 yet (coming end of November). As such, some of these initial steps may not be valid a month from now.

To get started, you’ll need to get a copy of Dotfuscator with the appropriate license. For now, visit http://www.preemptive.com/windowsphone7.html . On the right is a note about “Can’t wait for the WP7-specific SKU?” with instructions on how to contact PreEmptive and obtain the software. If you want to instrument your app before the end of the month, you’ll need to do this (and to do so, you’ll need to make an account at PreEmptive). Otherwise, give the poor guys a break and don’t bother them if you don’t intend to use it. Grab a copy of the WP7 project template from the same page.

When you hear back from PreEmptive and follow their instructions, you should end up with:

  1. A copy of Dotfuscator Pro installed, with a temporary license.
  2. A Runtime Intelligence account, activated from within Dotfuscator. This is different from the Dotfuscator license.
  3. The project template, download from http://www.preemptive.com/windowsphone7.html (on the right)

Modify your game

Okay, I know I said we’d be instrumenting our game after it has been compiled, but there is one small thing we’ll need to change. I believe this will be handled automatically in the WP7-specific version of Dotfuscator, but I had to do this manually. Go to your WMAppManifest.xml and add ID_CAP_NETWORKING to your capabilities if it’s not there already:

<Capabilities>
<Capability Name="ID_CAP_NETWORKING" />
</Capabilities>

This is required by your instrumented game to send the analytics messages. Go ahead and build your game now too.

Instrument your XAP

Now comes the time to instrument your compiled game using the Dotfuscator UI. Don’t be confused by the name – we don’t need to use any of the obfuscation features (though you can if you want).

There is a handy video made by PreEmptive that you can watch that explains these steps nicely: http://www.youtube.com/watch?v=QvTueq7EJuY . I’ll run through them here as well.

Open up Dotfuscator. If you haven’t already entered your license key, do that. Then enter your Runtime Intelligence portal activation code under Help –> Activate Runtime Intelligence.

When prompted to “Select Project Type”, select “Open Existing Project”, highlight “More…” and press “OK”. Browse to where you saved “wp7app.template.xml”, which you downloaded from http://www.preemptive.com/windowsphone7.html.

Dotfuscator stores its project files in fairly intuitive XML. The “wp7app.template.xml” is a starting template that you will modify and then save a copy of for your particular game.

The first thing to do is go to the “Input” tab. Select the “${configdir}\Add_Your_XAP_here.xap” item and remove it. Then click “Add new input” and browse to your game’s .xap file. If you wanted to include/exclude specific .dlls from being instrumented or obfuscated, you can do that here. By default, everything is included (and nothing is obfuscated anyway), so we can move on.

Next, go to the “Instrumentation” tab. Here we need to add a few things as a little required housekeeping for the Runtime Intelligence service.

First, we need to setup some application-wide settings:

  1. In the tree view, find your main assembly and right-click on it. Select “Add Attribute”.
  2. Add *both* the “Application” and “Business” attributes. Select OK.
  3. Select the Business attribute you just added. In the right-hand pane, add the CompanyKey provided to you by PreEmptive. Add a CompanyName if you want, but it’s optional.
  4. Select the Application attribute. Give it a Name and a Version if you wish and the click the “…” to generate a GUID.

With that done, we need to decorate two methods so that our instrumented app knows when to send session information. The first is the SetupAttribute, which should go on your Game class’s LoadContent method. To do this:

  1. Drill down through the tree into your main assembly and find your Game class.
  2. Right-click on its LoadContent method and select “Add Attribute”.
  3. Choose “PreEmptive.Attributes.SetupAttribute”
  4. In the right-hand pane, set the CustomEndpoint to “Runtime Intellience Services for Windows Phone 7” by clicking the “…” and choosing it from the list.

Next, add the Teardown attribute:

  1. Right-click on your game’s “OnExiting” method and select “Add Attribute”.
  2. Choose “PreEmptive.Attributes.TeardownAttribute”.

Go ahead and save your project with a different name now. I just chose MyAppName.xml for simplicity.

Now hit the green play button to “Build Project”. This will take your .xap file and recompile it with the necessary code injected according to the attributes you placed. The resulting .xap file will live in “\Dotfuscated\YourAppName.xap”, based on where your original .xap lives.

At this point, we’ve done all that is absolutely required, so let’s see what happens.

Checking our data

Start up the WP7 emulator (“C:\Program Files\Microsoft SDKs\Windows Phone\v7.0\Tools\XDE Launcher\XdeLauncher.exe”) as well as the Application Deployment tool (“C:\Program Files\Microsoft SDKs\Windows Phone\v7.0\Tools\XAP Deployment\XapDeploy.exe”), both of which are part of the WP7 tools.

Deploy your instrumented .xap to the emulator (the one in the Dotfuscated subdirectory) and run it. There’s no indication that anything is different, so let’s check if we got our data.

Log into the Runtime Intelligence portal using the credentials you got from PreEmptive. You should see… nothing! Don’t panic.

There are a few caveats to working with the portal:

  1. By default, the filter is set to a day behind. Expand the filter and get it to include today’s date.
  2. It can take around an hour for messages to show up in the portal. They will show up as “Queued Data”. This just lets you know that the service is receiving messages from you.
  3. It can take 12-24 hours for messages to be processed. Once they’re processed, you can actually get information from them.

Yikes! 12-24 hour turnaround before you can see anything useful. Not good for testing and iteration. Worse yet, we’ve only really instrumented our app to send a message on startup and shutdown. That tells us, at best, how many times our app is run. We’re going to need more specific data, and a way of testing it faster.

Using Fiddler to view messages

I ended up using a tool called Fiddler to inspect messages as they were sent by the emulator. This post is long enough already, so I’ll point you to this blog post for instructions on how to get Fiddler to work with the emulator. A few notes: make sure you get Fiddler 2.3.0.7 (it’s a beta), and make sure you restart the emulator after starting Fiddler. If all goes well, you should be able to see traffic when you run Internet Explorer in the emulator.

It helps if you use Fiddler’s “Process Filter” and drag it onto the emulator. This way you avoid seeing packets from all the other programs that are running.

You should have Fiddler running and showing packets from the emulator at this point.

Now, go back to your Dotfuscator project and find the SetupAttribute in the Instrumentation tab again. Select the SetupAttribute and then find the “UseSSL” entry in the right-hand pane. Set it to false for the purposes of testing. Now when we inspect packets in Fiddler, we’ll be able to see the contents.

Save, rebuild the Dotfuscator project and re-deploy it to the emulator.

Now when you run your app, you should see a couple of messages appear in Fiddler:

If you use the XML view under “Inspectors”, you can see the contents of the message nicely. You should see that the event code for the messages are “Session.Start” and “Application.Start”, which seems pretty reasonable.

If you exit, you should see… no new messages! What??!

Start your app a second time and you’ll now see four messages: Session.Stop, Application.Stop and then the expected Session.Start and Application.Start.

This is unintuitive and has some implications. During the teardown method, the Runtime Intelligence code assumes the app is exiting. When WP7 apps are shutting down, network calls will appear to succeed, but nothing is actually sent. To deal with this, the Runtime Intelligence code instead writes the messages to IsolatedStorage and then sends them the next time the app is run. This means you will have a lot of incomplete sessions when viewing data on the portal. There is nothing you can do about this.

Reporting unique users

Right now, our app reports session data. While interesting, we could do a lot better. Let’s start by at identifying unique users.

To do this, we’ll make use of the phone’s unique id. This could lead to some duplicates if one user installs your game on multiple devices, but we’ll ignore that use case for now.

Adding an ID to session data is quite simple with Dotfuscator. To start, we’ll need to modify our game code so that we store the device’s unique id somewhere to access later. It needs to be available before the method tagged with “SetupAttribute” is called in order for Dotfuscator to use it (in our case, before Game.LoadContent is called). I just added the following to my game class:

#if WINDOWS_PHONE
using Microsoft.Phone.Info;
#endif

public class DatGame : Microsoft.Xna.Framework.Game
{

#if WINDOWS_PHONE
String phoneID = "0";
#endif

public DatGame()
{
[...]
var value = (byte[])DeviceExtendedProperties.GetValue("DeviceUniqueId");
phoneID = Convert.ToBase64String(value);
[...]

You’ll notice we’re now using the phone’s identity. That’s a new capability, so update your WMAppManifest.xml accordingly by adding:

<Capability Name="ID_CAP_IDENTITY_DEVICE" />

Now we have a field called “phoneID” that should contain the device’s unique ID. Rebuild your game. In order to hook this up in Dotfuscator:

  1. Go to your SetupAttribute and look at the right-hand pane.
  2. For “InstanceIdSourceElement”, select “Field”
  3. For “InstanceIdSourceName”, type “phoneID”

Now Dotfuscator has enough information to fill in the InstanceID of its messages with the phone’s unique ID. All messages will have this ID automatically, so you can now identify unique users for any message type you report.

Reporting Paid versus Trial

Now that we can identify unique users, let’s report on whether the app was launched with a full license or with a trial license. To make this easier, we’ll add some stub methods into our game code that we can then decorate using Dotfuscator.

There are many ways to do this. I chose to simply hook up to my PhoneLaunching event, which will be called only when the game is launched for the first time and not when tombstoned.

protected void OnPhoneLaunching(object sender, EventArgs args)
{
    if (Guide.IsTrialMode)
    {
        LaunchTrialFeatureTick();
    }
    else
    {
        LaunchPaidFeatureTick();
    }
}

public void LaunchTrialFeatureTick()
{
}

public void LaunchPaidFeatureTick()
{
}

This is a pretty simple example (you should check Guide.IsTrial and cache the result somewhere). Note that every time the game is launched, one of either LaunchTrialFeatureTick or LaunchPaidFeatureTick will be called. Rebuild your game. Let’s hook these up in Dotfuscator:

  1. On the “Instrumentation” tab, find the “LaunchTrialFeatureTick” method, right-click and select “Add Attribute”.
  2. This time, select “FeatureAttribute”.
  3. In the right-hand pane, set the Name field to something reasonable like “LaunchTrial”. This is how the feature will be identified in the portal.
  4. Do the same for “LaunchPaidFeatureTick”, with a name like “LaunchPaid”.

The reason I named these methods with “Tick” is because the method represents the entirety of the feature. If you want, you can identify the beginning and end of a feature separately in order to get a sense of how long a feature is used for. I won’t cover that here but it should be pretty intuitive.

Wrap up and where to go from here

At this point, your app should be reporting session data, along with a “Feature” message each time the game is launched indicating if its the paid or trial version. Each message has a unique id per phone, so you should be able to get a pretty accurate idea of how many users are playing your game. You’ll still need to wait for your data to be processed on the portal but you can check your work with Fiddler.

Don’t forget to enable SSL again!
Don’t forget to submit your instrumented .xap to certification and not your original!

What else can you do? You can easily add any custom data to your messages by filling out the “ExtendedKey” properties in Dotfuscator. For example, when a user finishes a round in my game, it also reports their high score. I also store the user’s last IsTrial setting, allowing me to send a message when they purchase the game or run the full version for the first time (rather than filtering LaunchPaid events for unique users). If there’s interest, I can show you how to do that too.

Questions? Comments?

If you found this useful, follow me on Twitter @benkane and check out my new game Zombie Accountant! Thanks!

Advertisements

About Ben Kane
I'm a game developer with a heart of gold.

5 Responses to HOWTO: Track sales and downloads with XNA and Windows Phone 7 using Dotfuscator and Runtime Intelligence

  1. Andy Mild says:

    nice… i will try it

  2. Hosting says:

    Thank for this tutorial

  3. Villy says:

    I tested Dotfuscator 4.9 (WP7 edition as described in this article) with my xna code and it replace (obfuscate) only 6% of my classes/methods names. Maybe someone knows why this may happen ?

  4. Villy says:

    I replace public class declaration with internal and now get 99 %

  5. Pingback: Windows Client Developer Roundup 049 for 11/22/2010 - Pete Brown's 10rem.net

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: