Windows 8 Consumer Preview and Visual Studio 11 Beta – Licensing and In-app purchases (Part 7/11)

February 29, 2012

Windows 8 Metro applications are distributed by Windows Store. The store handles all installation tasks, updating to the new versions when published by developer. Also it handles purchasing the application, supporting trial mode (if application developer chooses to support it) and handles in-app purchases.

All licensing supported by Windows.ApplicationModel.Store namespace.

image

Note: CurrentApp provides license information for the current app.This object obtains its data from the Windows Store, which is not currently (Consumer Preview timeframe) supported.

For development purposes we will use CurrentAppSimulator class, which completely mimics APIs of CurrentApp class but enables developing licensing support before publishing the app.

Let’s see the licensing initialization code:

private async void InitializeLicenseEngine()
{
#if DEBUG
    //Point to XML infomration provoded with application instrad of getting data from Windows Store
    await InitializeProxyFolderAsync();
    await SetupProxyFile("LicenseInfo.xml");
#endif
    initializeLicense();

    UpdateCurrentLicenseMode();
}

private void initializeLicense()
{
#if DEBUG
    //Use simulator for debugging
    licenseInformation = CurrentAppSimulator.LicenseInformation;
#else
    //Use real Windows Store data
    licenseInformation = CurrentApp.LicenseInformation;
#endif
    //Subscribe to license changes
    licenseInformation.LicenseChanged += licenseInformation_LicenseChanged;
}

void licenseInformation_LicenseChanged()
{
    //Update application logic on license changes
    UpdateCurrentLicenseMode();
}

For development purposes two helpers functions are used to provide response as it is provided by Windows Store.

async Task InitializeProxyFolderAsync()
{
    // setup licensing proxy XML folder
    proxyFolder = await ApplicationData.Current.LocalFolder.CreateFolderAsync("Microsoft\\Windows Store\\ApiData", CreationCollisionOption.OpenIfExists);
    installLocation = Windows.ApplicationModel.Package.Current.InstalledLocation;
}

async Task SetupProxyFile(string fileName)
{
    // open the proxy file
    StorageFile proxyFile = await installLocation.GetFileAsync(fileName);

    // create proxy file in application data
    StorageFile targetFile = await proxyFolder.CreateFileAsync("WindowsStoreProxy.xml", CreationCollisionOption.ReplaceExisting);

    // replace the contents
    await proxyFile.CopyAndReplaceAsync(targetFile);
}

The XML file with all license info packed with the application to enable debugging:

image

The file content uses same XML structure as real response from Windows Store:

<?xml version="1.0" encoding="utf-16" ?>
<CurrentApp>
  <ListingInformation>
    <App>
      <AppId>3C14D306-D8F8-4066-A45B-0FB3464C67F3</AppId>
      <LinkUri>http://apps.microsoft.com/app/3C14D306-D8F8-4066-A45B-0FB3464C67F3</LinkUri>
      <CurrentMarket>en-us</CurrentMarket>
      <AgeRating>4</AgeRating>
      <MarketData xml:lang="en-us">
        <Name>Valentine Love Catcher</Name>
        <Description>Sample application to demonstrate new APIs of Windows 8</Description>
        <Price>5.99</Price>
        <CurrencySymbol>$</CurrencySymbol>
      </MarketData>
    </App>
    <Product ProductId="NewYearGift">
      <MarketData xml:lang="en-us">
        <Name>Happy 2013 New Year Gift</Name>
        <Price>1.99</Price>
        <CurrencySymbol>$</CurrencySymbol>
      </MarketData>
    </Product>
    <Product ProductId="ValentineBouquet">
      <MarketData xml:lang="en-us">
        <Name>Valentine Bouquet</Name>
        <Price>2.99</Price>
        <CurrencySymbol>$</CurrencySymbol>
      </MarketData>
    </Product>
  </ListingInformation>
  <LicenseInformation>
    <App>
      <IsActive>true</IsActive>
      <IsTrial>true</IsTrial>
      <ExpirationDate>2012-05-01T00:00:00.00Z</ExpirationDate>
    </App>
    <Product ProductId="NewYearGift">
      <IsActive>false</IsActive>
      <ExpirationDate>2013-01-02T00:00:00.00Z</ExpirationDate>
    </Product>
    <Product ProductId="ValentineBouquet">
      <IsActive>false</IsActive>
    </Product>
  </LicenseInformation>
</CurrentApp>

It defines ListingInformation (product name, rating, price, etc.), in-app products (if supported) and licensing information (trial, active, expiration for application and all products).

Application uses this information to adjust its functionality. In case of my sample application all the proximity functionality is disabled and changes this support when license changed:

private async void UpdateCurrentLicenseMode()
{
    //Show/hide "Buy Now" button based on Trial mode
    btnBuyNow.Visibility = licenseInformation.IsTrial ? Visibility.Visible : Visibility.Collapsed;

    //Check trial/active to enable/disable NFC
    if (licenseInformation.IsTrial || !licenseInformation.IsActive)
    {
        //Disable proximity sensor if not active or in trial mode
        _proximityDevice = null;
        //Get Windows Store (or simulator) listing info and suggest to purchase the app
#if DEBUG
        ListingInformation listing = await CurrentAppSimulator.LoadListingInformationAsync();
#else
        ListingInformation listing = await CurrentApp.LoadListingInformationAsync();
#endif
        txtStatus.Text = "Proximity disabled in trial or non-licensed modes.\nPurchase this application for only " + listing.FormattedPrice;
    }
    else if (!licenseInformation.IsTrial && licenseInformation.IsActive && null == _proximityDevice)
    {
        //Enable proximity when application become active
        _proximityDevice = ProximityDevice.GetDefault();

        if (null != _proximityDevice)
            txtStatus.Text = "Proxmity device is available and ready to go!";
    }

    //Check supported in-app products to enable/disable some UI elements
    if (!licenseInformation.ProductLicenses["ValentineBouquet"].IsActive)
        btnFlower.IsEnabled = true;
    else
        btnFlower.IsEnabled = false;

    if (!licenseInformation.ProductLicenses["NewYearGift"].IsActive)
        btnBallons.IsEnabled = true;
    else
        btnBallons.IsEnabled = false;
}

This code snippet update application’s UI and enables buying application and in-app products:

imageimage

Pressing “Buy now” button invokes purchasing process:

private async void btnBuyNow_Click(object sender, RoutedEventArgs e)
{
    //Invoke only if still in trial
    if (licenseInformation.IsTrial)
    {
        try
        {
            //Purchase the application
#if DEBUG
            await CurrentAppSimulator.RequestAppPurchaseAsync();
#else
            await CurrentApp.RequestAppPurchaseAsync();
#endif
            //Purchased finished successfully
            txtStatus.Text = "You successfully upgraded your app to the fully-licensed version.";
        }
        catch (Exception)
        {
            //If exception thrown, provide user with information why application were not purchased
            txtStatus.Text = "The upgrade transaction failed. You still have a trial license for this app.";
        }
    }
    else
    {
        txtStatus.Text = "You already bought this app and have a fully-licensed version.";
    }
    UpdateCurrentLicenseMode();
}

While using simulator simple dialog enables to simulate response form Windows Store to debug possible responses:

image

Almost same process is used to purchase in-app products:

private async Task PurchaseProduct(string ProductID)
{
    try
    {
       //Start produc purchaseing
#if DEBUG
        await CurrentAppSimulator.RequestProductPurchaseAsync(ProductID);
#else
        await CurrentApp.RequestProductPurchaseAsync(ProductID);
#endif

        //Provide user some feedback about purchase success
        ListingInformation listing = await CurrentAppSimulator.LoadListingInformationAsync();
        txtStatus.Text = "You successfully purchased " + listing.ProductListings[ProductID].Name + " for " + listing.ProductListings[ProductID].FormattedPrice;
    }
    catch (Exception)
    {
        //Handle purchase exception
        txtStatus.Text = "The upgrade transaction failed. You still have a trial license for this app.";
    }

    UpdateCurrentLicenseMode();
}

As with application purchase scenario, the simulator dialog enables to simulate response form Windows Store to debug possible responses:

imageimage

Note: since this approach uses Windows Store simulator and embedded license information the purchases are not preserved between application launches (not activations – see PLM post to understand the differences) and not synced across different user devices.

 

That’s al I have to say about that © Forest Gump

 

 

Stay tuned for next part.

Alex

Add comment
facebook linkedin twitter email

Leave a Reply

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*