Timed Trial: start with all the features in the application and after a certain amount of time will expire and stop working, or work partially, or suddenly be riddled with ads until your user breaks down and pays or deletes it.
one thing to note is that Timed trial is not compatible with in-app purchases, that means if you have a timed trail you can't have consumable or durable products inside you application.
Feature Based Trial: start with a subset of features and require your user to pay to unlock advanced features.
In-app purchase: allow your users to make consumable purchases inside your apps; for example in games you can buy things like coins or powerups
In production we would use the CurrentApp class to handle all of our licensing information and interactivity, but for testing we use CurrentAppSimulator. Our Licencing Information is stored in an xml file at the following location:
C:\Users\Administrator\AppData\Local\Packages\49a7a3ba-c5b6-495d-be63-c1b0560ce3e7_75cr2b68sm664\LocalState\Microsoft\Windows Store\ApiData\WindowsStoreProxy.xml
now I'm using my administrator account for development, so your path will be different, now let's look inside of this xml file, but before we do it may be worth to mention that the WindowsStoreProxy.xml file is created the first time your app accesses the LicenseInformation property of the CurrentAppSimulator class.
<?xml version="1.0" encoding="utf-16" ?>
<CurrentApp>
<ListingInformation>
<App>
<AppId>00000000-0000-0000-0000-000000000000</AppId>
<LinkUri>http://apps.microsoft.com/webpdp/app/00000000-0000-0000-0000-000000000000</LinkUri>
<CurrentMarket>en-US</CurrentMarket>
<AgeRating>3</AgeRating>
<MarketData xml:lang="en-us">
<Name>AppName</Name>
<Description>AppDescription</Description>
<Price>1.00</Price>
<CurrencySymbol>$</CurrencySymbol>
<CurrencyCode>USD</CurrencyCode>
</MarketData>
</App>
<Product ProductId="1" LicenseDuration="0" ProductType="Durable">
<MarketData xml:lang="en-us">
<Name>Product1Name</Name>
<Price>1.00</Price>
<CurrencySymbol>$</CurrencySymbol>
<CurrencyCode>USD</CurrencyCode>
</MarketData>
</Product>
<Product ProductId="2" LicenseDuration="0" ProductType="Consumable">
<MarketData xml:lang="en-us">
<Name>Product2Name</Name>
<Price>1.00</Price>
<CurrencySymbol>$</CurrencySymbol>
<CurrencyCode>USD</CurrencyCode>
</MarketData>
</Product>
</ListingInformation>
<LicenseInformation>
<App>
<IsActive>true</IsActive>
<IsTrial>true</IsTrial>
<ExpirationDate>2014-06-19T09:00:00.00Z</ExpirationDate>
</App>
<Product ProductId="1">
<IsActive>true</IsActive>
</Product>
</LicenseInformation>
<ConsumableInformation>
<Product ProductId="2" TransactionId="00000000-0000-0000-0000-000000000000" Status="Active" />
</ConsumableInformation>
</CurrentApp>
lets look at the ListingInformation Node, in here it contains three children App, and two product nodes, the thing to notice is that they have two different ProductType attributes:
- Durable: buy once keep forever
- Consumable: buy but use up
App: is a the node referring to our application, here it can be in trail mode that expires and can be purchased.
- Product with type Durable: this is a product that can be purchased indefinitely an added feature.
- Product with type consumable: a product that can be used up.
Timed Trial
alright, lets' get started with a Timed trial app, that's an application that you download and you can use for a number of predefined days only to stop entirely or start display adds once the trial expires or perhaps only let's you utilize a subset of Features.Let's take a look at our UI
now the xaml
<Page
x:Class="pc.licenseExample.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:pc.licenseExample"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid.RowDefinitions>
<RowDefinition Height="100"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="1" Text="License Exmaple"
Style="{ThemeResource HeaderTextBlockStyle}"
VerticalAlignment="Center" />
<StackPanel Grid.Column="1" Grid.Row="1">
<TextBox x:Name="AppData_TXT"
Header="App Data:"/>
<TextBox x:Name="ListingInfo_TXT"
Header="Listing Info:"
Height="200"
TextWrapping="Wrap"/>
<TextBox x:Name="LicenceInfo_TXT"
Header="Licence Info:"
Height="100"
TextWrapping="Wrap"/>
<StackPanel Orientation="Horizontal">
<Button x:Name="GetLicenseInfo_BTN" Content="Get Info"
/>
<Button x:Name="BuyLicense_BTN"
Content="Buy" />
</StackPanel>
</StackPanel>
</Grid>
</Page>
using System;
using System.Windows.Input;
using Windows.ApplicationModel.Store;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
namespace pc.licenseExample
{
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
this.GetLicenseInfo_BTN.Click += GetLicenseInfo_BTN_Click;
}
async void GetLicenseInfo_BTN_Click(object sender, RoutedEventArgs e)
{
AppData_TXT.Text = Windows.Storage.ApplicationData.Current.LocalFolder.Path;
var listingInfo = await CurrentAppSimulator.LoadListingInformationAsync();
var listingStr = "Age
Rating: {0}\r\nCurrentMarket:{1}\r\nDescription:{2}\r\nFormattedPrice:{3}\r\nName:{4}";
ListingInfo_TXT.Text = string.Format(listingStr,
listingInfo.AgeRating,
listingInfo.CurrentMarket,
listingInfo.Description,
listingInfo.FormattedPrice,
listingInfo.Name);
var licenseInfo = CurrentAppSimulator.LicenseInformation;
var str = "ExpirationDate:
{0}\r\nIs Trial:{1}\r\nIs Active:{2}";
LicenceInfo_TXT.Text = String.Format(str,
licenseInfo.ExpirationDate.ToString(),
licenseInfo.IsTrial,
licenseInfo.IsActive);
}
}
}
now what we have so far will list all of our application info when we hit the "Get Info" button and by default we can see the following
the App Data Text box gives us a link to our application in our roaming folder so that we can get to our xml file faster, I've already modified mine to have an expiry date in the past, which is why our IsActive property if false and our is Trial is true, so this tells us that the trial period is expired but the user hasn't activated the application.
so now let's write the code for buying our application, to the code behind,
public MainPage()
{
this.InitializeComponent();
this.GetLicenseInfo_BTN.Click += GetLicenseInfo_BTN_Click;
this.BuyLicense_BTN.Click += BuyLicense_BTN_Click;
}
async void BuyLicense_BTN_Click(object sender, RoutedEventArgs e)
{
try
{
await CurrentAppSimulator.RequestAppPurchaseAsync(false);
}
catch (Exception ex)
{
//handle
excption
}
}
public MainPage()
{
this.InitializeComponent();
this.GetLicenseInfo_BTN.Click += GetLicenseInfo_BTN_Click;
this.BuyLicense_BTN.Click += BuyLicense_BTN_Click;
CurrentAppSimulator.LicenseInformation.LicenseChanged += LicenseInformation_LicenseChanged;
}
void
LicenseInformation_LicenseChanged()
{
var licenseInfo = CurrentAppSimulator.LicenseInformation;
var str = "ExpirationDate:
{0}\r\nIs Trial:{1}\r\nIs Active:{2}";
LicenceInfo_TXT.Text = String.Format(str,
licenseInfo.ExpirationDate.ToString(),
licenseInfo.IsTrial,
licenseInfo.IsActive);
}
Durable
Keep in mind that in-app purchases do not work with a timed-trial, so for these to work you have to open your "WindowsStoreProxy.xml" ile and change the app node to
<App>
<IsActive>true</IsActive>
<IsTrial>false</IsTrial>
</App>
Basically remove the expiration date node and set the istrial to false.Now let's look at purchasing a durable, first we're going to list the durable Items so add the following datatemplate to your page's resources in the xaml
<Page.Resources>
<DataTemplate x:Name="DurableTemplate">
<StackPanel>
<TextBox Header="Product Id:"
Text="{Binding ProductId}"/>
<TextBox Header="IsActive:" Text="{Binding IsActive}"/>
<TextBox Header="Expiration Date:" Text="{Binding ExpirationDate}"/>
</StackPanel>
</DataTemplate>
</Page.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<ListView x:Name="Durable_LV" Header="Durable"
ItemTemplate="{StaticResource DurableTemplate}"/>
</Grid>
We're adding a grid with a listview is because we'll ad a second list view later for consumables, now let's add the following line to the Get Licence Info method
Durable_LV.ItemsSource = licenseInfo.ProductLicenses.Values;
Now when we run our application and get the info for our durable products.
notice we also added a buy button to the durable DataTemplate, all we did was add the following
<Button Content="Buy" Command="{Binding ElementName=MainContainer, Path=BuyDurableCommand }" CommandParameter="{Binding ProductId}" />
<Page
x:Name="MainContainer"
DataContext="{Binding RelativeSource={RelativeSource Self}}"
x:Class="pc.licenseExample.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:pc.licenseExample"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
now in the code behind we have to create an ICommand Property we can bind to, so lets add that to our class.
public sealed partial class MainPage : Page
{
//Command
to expose to UI
public ICommand BuyDurableCommand { get; set; }
//stuff in code behind
public class BuyCommand : ICommand {
Action<object> _buyCommand;
//consturctor
that takes in action to perform
public BuyCommand(Action<object> Execute)
{
_buyCommand = Execute;
}
public bool CanExecute(object parameter)
{
return true;
}
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
_buyCommand.Invoke(parameter);
}
}
now finally we need to tie our BuyDurableCommand property to the BuyCommand class we created and we'll do that in our constructor like so.
public MainPage()
{
this.InitializeComponent();
this.GetLicenseInfo_BTN.Click += GetLicenseInfo_BTN_Click;
this.BuyLicense_BTN.Click += BuyLicense_BTN_Click;
CurrentAppSimulator.LicenseInformation.LicenseChanged +=
LicenseInformation_LicenseChanged;
this.BuyDurableCommand = new BuyCommand(async id =>
{
try
{
var pr = await CurrentAppSimulator.RequestProductPurchaseAsync(id.ToString());
}
catch (Exception ex)
{
}
});
}