Wensus Analytics

In-app purchases and Windows Phone 7

As we all know, Windows Phone 7 doesn’t have support for in-app purchases. The support was added in Windows Phone 8. This isn’t a huge deal in most countries as WP7 phones weren’t that popular. Except here in Finland. The big problem is that if your app targets Finnish users and you want to provide some content as in-app purchases, you really can’t skip the WP7 users or you’re going to miss a big part of your market. How big you may ask? Over half:

image

The Lumia 800 was really popular here. And it still is as it has been sold with big discounts in the past few months:

image

I’ve been battling with the problem recently as I’ve added some in-app products to an app which targets Finnish users only. And I’m quite happy with the outcome. Here’s first some features of the implementation and then some more details on how it is done:

Features

One XAP

The app only has one XAP (which targets Windows Phone 7.1). The same XAP gets deployed to both WP8 and WP7 phones.

In-app purchases are managed through Dev Center

The in-app purchases are managed through the Dev Center, just like when we are targeting Windows Phone 8 only:

image

One codebase

There’s no “if platform wp 8 then else” code. The product purchase is initiated with the following code:

var license = await store.RequestProductPurchaseAsync("live2013", true);

Native on Windows Phone 8

If the app is run on Windows Phone 8, it uses the native in-app purchase features:

image

Custom code on Windows Phone 7

If the app is run on Windows Phone 7, it uses custom code which mimics the in-app purchase experience of WP8:

image

Note: The WP7 version gets the product details (price etc.) from the Dev Center.

PayPal on Windows Phone 7

User is taken to PayPal’s mobile checkout site when she decides to purchase the product (on Windows Phone 7):

image

On Windows Phone 8 the user can select from any of her payment methods. Remember, the app uses the native in-app purchase functionality on WP8 device.

And that’s about it on the feature side.The best part is that I don’t have to worry about if the user has Windows Phone 7 or 8 device as the same code works on both platforms. Biggest limitation is that the WP7 side is currently PayPal only.

Implementation details

Client

The idea behind the implementation was taken from the code sample “WP8 Store Wrapper for IAP”. The original code sample shows how it is possible to wrap the WP8 store so that it can be used when a WP7 app is run on a WP8 device.

I used a similar wrapping mechanism but in addition I implemented a custom store which is used on WP7 devices. Here’s a StoreFactory-class which decides what store to use:

public static class StoreFactory 
{ 
    public static StoreBase Create() 
    { 
        StoreBase store = null;

        if (Environment.OSVersion.Version.Major >= 8) 
        { 
            store = StoreLauncher.GetStoreInterface("WP8StoreWrapper.Store, WP8StoreWrapper, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"); 
        } 
        else 
        { 
            store = StoreLauncher.GetStoreInterface("CustomStore.MyCustomStore, CustomStore, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"); 
        }

        return store; 
    } 
}

Here’s an example which shows how to check if the user owns product “myproduct”:

var ownsProduct = store.LicenseInformation.ProductLicenses.ContainsKey("myproduct");

Without the wrapper, using directly the Windows Phone 8 SDK, the above code would be written like this:

var ownsProduct = CurrentApp.LicenseInformation.ProductLicenses.ContainsKey("myproduct");

The custom store includes the product details page. The page is similar to WP8’s page, showing the product’s price with the buy and cancel buttons.

Service

The custom store isn’t just a client side thing. There’s a service which the client uses to get the product details and to communicate with the PayPal. The whole thing could be implemented without a service but in that case, if the user changes her phone, the purchase would be lost. With the help of the service, user can install her previously purchased products on a new phone.

The service itself is just a ASP.NET MVC site, which returns the product details to client in JSON format, communicates with PayPal using their old WebService interface and stores the receipts for purchases.

Code

Code isn’t yet available as it needs some fine tuning. But if you’re interested, just give me a shout and can provide more details about the implementation.

  • Daniel Lucena

    great post, i don’t no if this is a right place for my question but.. I’m working on a windows phone 8 app, and i want use a azure db from storage all the user data, what is better? azure moblie services or sql azure ?

    and if is a sql azure, how i can connect my app with this db? thanks..

    • http://mikaelkoskinen.net/ Mikael Koskinen

      Thanks Daniel.

      Personally I recommend that you start from the Azure Mobile Services. They are easy to get started and fit nicely into a WP8 app. Behind the scenes Azure Mobile Services uses SQL Azure, so you can think of it as a wrapper around the database.

      • Daniel Lucena

        Thanks for your help, mobile services is very easy to implement!

  • skendrot

    What happens when users upgrade their device? They’ll be very upset that have to purchase the upgrade once again.

    • http://mikaelkoskinen.net/ Mikael Koskinen

      Good point. From WP7 to WP7 device doesn’t cause any problems as the user stays on our “custom store” side. Same thing from WP8 to WP8, as then she stays on the “native store” side. But the move from WP7 to WP8 is problematic.

      The way we’re trying to solve this by customizing the wrapper which we have around the WP8 store. Currently the wrapper just passes the calls to the native code but the idea is that the wrapper could also check from the custom store’s service if the user has the receipt. Currently every user has to login with Live ID to use the app so we can identify everyone who has purchased the feature on either WP7 and WP8. But it could be possible just use the user’s ANID to identify the user. Though the ANID implementation changed between the WP7 and WP8 so that has to be taken into account.

      • skendrot

        How is this handled WP7 to WP7 (or uninstall/reinstall)? How is your custom store built? I’d love to know more about this. Are you storing the userID or deviceID somewhere? Thanks again, looking forward to a followup post

        • http://mikaelkoskinen.net/ Mikael Koskinen

          Our current implementation uses Live ID to identify the user on WP7. So, before a user makes a purchase, she logs in to the app using the Live ID. We store the user’s Live ID authentication token which we can use to identify the user on the server side. Every time the app communicates with our store, it send the authentication token as the header so that we can ID the user.

          After she has paid the purchase using PayPal, our service creates a receipt and stores it in a database. The receipt is also stored into to the phone so that store.LicenseInformation.ProductLicenses doesn’t always have to check the service.

          If the user changes her WP7 to an another WP7 phone, she again has to log into the app. This time, when we first check for the license from store.LicenseInformation.ProductLicenses we get null. So the user doesn’t have the license. So we initiate the purchase using store.RequestProductPurchaseAsync. But at that point we check if the user has the license stored in our database and if she has, the user doesn’t have to purchase the license again. Instead she can just “install” the license, meaning that the license is stored on her phone. After this installation, store.LicenseInformation.ProductLicenses will report that she has the license.

          The key point is to have some mechanism for identifying the user. We use the Live ID authentication token, which we can convert to a user on a server side. Also, this works even if the user changes her phone, as long as she keeps using the same Live ID.

          A simpler solution would be to use something called ANID to identify the user. ANID is an anonymous user ID. For example, if you have three WP7 phones and you have logged into these phones using the same Microsoft Account (the one you use when first starting the phone), the ANID is same on these devices. So that can be used to ID the user.

          • skendrot

            This is awesome! Thanks for sharing. For the upgrade story (WP7 to WP8) you could check both services (MSFT and yours) or offer a “I already puchased” option that would save something locally. Cool solution.

  • paulwp1

    Definitively waiting for the example, great article :)