Add in-app purchases to a DirectX game
[This article is for Windows 8.x and Windows Phone 8.x developers writing Windows Runtime apps. If you’re developing for Windows 10, see the latest documentation]
You can offer products and features for players to buy while playing your Windows Store game. In this topic, we'll show you how to enable these offers in your game. This topic walks through an example to explore the required code, what the player should experience, and how to test an in-game purchase (with test code).
Note A customer can only make an in-game purchase if they've purchased a full version of your game.
Enabling in-game purchases
This topic shows code that can be added to the Marble Maze sample. This sample is a game in which the player rolls a marble across a board; when the game starts, the marble is white. This code allows the player to buy a different color marble while playing the game.
The way to initiate the process of in-game purchasing depends on the design of your game. This example uses an app bar button to start the purchase. Here is the XAML code for the app bar button.
<Button Style="{StaticResource AppBarButtonStyle}"
AutomationProperties.Name="Change Marble"
Click="ChangeMarbleButton_Click">
<Button.ContentTemplate>
<DataTemplate>
<Path Stroke="{Binding Foreground, RelativeSource={RelativeSource Mode=TemplatedParent}}"
Fill="White"
Width="20" Height="20" StrokeThickness="2" Stretch="Uniform">
<Path.Data>
<EllipseGeometry Center="10,10" RadiusX="20" RadiusY="20" />
</Path.Data>
</Path>
</DataTemplate>
</Button.ContentTemplate>
</Button>
And, here is how the app bar and the initial (free) marble look in the sample.
The app bar button triggers the ChangeMarbleButton_Click event handler. This example here shows the event handler.
Note This code is for an actual in-game purchase. We'll show you code to test a purchase in the Simulating a purchase section later in this topic.
// Get the license info
// The next line is commented out for testing.
auto licenseInformation = CurrentApp.LicenseInformation;
// The next line is commented out for production/release.
// auto licenseInformation = CurrentAppSimulator::LicenseInformation;
// Check to see if the player already owns the item.
if (!licenseInformation->ProductLicenses->Lookup("blueMarble")->IsActive)
{
// The player does not own the item. Purchase the marble.
concurrency::task<Platform::String^> purchaseOperation(CurrentApp::RequestProductPurchaseAsync("blueMarble", false));
purchaseOperation.then([this](task<Platform::String^> previousTask)
{
try
{
// This line raises an exception if the purchase fails.
previousTask.get();
auto licenseInformation = CurrentApp::LicenseInformation;
if (licenseInformation->ProductLicenses->Lookup("blueMarble")->IsActive)
{
// Marble purchased.
m_renderer.SwitchMarble();
}
else
{
// Marble not purchased.
// Notify the player.
}
}
catch(Platform::Exception^ exception)
{
// Purchase failed.
// Notify the player.
}
});
}
else
{
// The player does own the item.
// Switch the marble color.
m_renderer.SwitchMarble();
}
// Close the app bar.
bottomAppBar->IsOpen = false;
The code in the preceding example first checks to see if the player already has the "blueMarble" product by using the CurrentApp::LicenseInformation::ProductLicenses::IsActive method. If the player doesn't have it, the code starts an asynchronous RequestProductPurchaseAsync task.
At this point, the Windows.ApplicationModel.Store API presents a series of standard prompts to help the player buy the in-game product. The In-game purchase experience section of this topic demonstrates the experience for a player getting a different color marble.
Note The experience for testing a purchase during development is different. We'll walk through the testing experience in Simulating a purchase later in this topic.
The task will return successfully whether the player confirms the purchase or not. So, when the task returns you must check to see if the product is active by calling the IsActive method again. However, if an error occurs during the purchase, the call to previousTask.get()
raises an exception. Catch this exception in your code and handle it as a failed purchase.
Now that the player has purchased the different color marble, our example displays the new marble. You must display the player's new purchase right away.
Simulating a purchase
In order to test your in-game purchase functionality, you must simulate a purchase. Testing requires you to change every reference of CurrentApp to CurrentAppSimulator in your code. The example here shows the body of the event handler from the previous section with the changes necessary for simulating a purchase.
Note You can use preprocessor directives and #ifdefs to change to simulation mode more easily.
// Get the license info
// The next line is commented out for testing.
// auto licenseInformation = CurrentApp.LicenseInformation;
// The next line is commented out for production/release.
auto licenseInformation = CurrentAppSimulator::LicenseInformation;
// Check to see if the player already owns the item.
if (!licenseInformation->ProductLicenses->Lookup("blueMarble")->IsActive)
{
// The player does not own the item. Purchase the marble.
concurrency::task<Platform::String^> purchaseOperation(CurrentAppSimulator::RequestProductPurchaseAsync("blueMarble", false));
purchaseOperation.then([this](task<Platform::String^> previousTask)
{
try
{
// This line raises an exception if the purchase fails.
previousTask.get();
auto licenseInformation = CurrentAppSimulator::LicenseInformation;
if (licenseInformation->ProductLicenses->Lookup("blueMarble")->IsActive)
{
// Marble purchased.
m_renderer.SwitchMarble();
}
else
{
// Marble not purchased.
}
}
catch(Platform::Exception^ exception)
{
// Purchase failed.
}
});
}
else
{
// The player does own the item.
// Switch the marble color.
m_renderer.SwitchMarble();
}
// Close the app bar.
bottomAppBar->IsOpen = false;
When this code runs, the following test dialog is shown:
If you select Continue, the simulated purchase returns successfully. This is equivalent to the customer selecting Buy and paying for the product.
If you select Cancel, the simulated purchase returns unsuccessfully. This is equivalent to the customer selecting Cancel or not paying for the product.
Note In both cases, you must return the error code S_OK. The Windows.ApplicationModel.Store API returns S_OK in both cases.
In-game purchase experience
The Windows.ApplicationModel.Store APIs display a standard set of prompts that confirm the purchase and payment.
When the player chooses to purchase an item from the game, Windows.ApplicationModel.Store queries the Windows Store for current info, such as the price of the item:
Then it displays the confirmation prompt:
The description the confirmation prompt displays is the description that you entered in the Description page for the in-game offer. For info about this description see What to include in your app's description.
After the player clicks Yes, they must sign in to their Microsoft accountto confirm their identity. The player must do this for each in-app purchase to prevent fraudulent and unintentional purchases.
After the purchase and the player's identity have been confirmed, payment for the purchase is processed using the player's default payment method. The player configures their default payment method in their Windows Store settings.
When the transaction completes, a final confirmation prompt is given, and the customer clicks Close to return to the game.
At this point you must confirm that the purchase was successful and, if so, immediately perform the steps to implement the purchase. For example, you may need to add a new item to the player's inventory, or add a new menu option to enable a different theme. In this example, we display the marble in a new color: