Documentation

Unibill

Introduction

Unibill is a one stop solution for in App purchasing in Unity®; a single plugin that works across the Apple App store, Mac App Store, Google Play, Amazon App store, Samsung Apps Store, Windows Phone 8 and Windows 8.1!

The following snippet initialises Unibill, makes a purchase and works across all seven platforms.

                            
Unibiller.onBillerReady += (state) => {
    if (UnibillState.SUCCESS == state) {
        Unibiller.initiatePurchase(Unibiller.AllPurchasableItems[0]);
    }
};
Unibiller.Initialise();
                            
                        

How it works

Instead of using the raw billing interfaces of Apple, Google, Amazon and Microsoft, your application uses the more abstract Unibill interface. Unibill is responsible for communicating with the underlying billing system on each platform, so your code remains simple and clean.

Unibill does a huge amount of work for you, such as verifying your product data with Apple and Amazon when your application launches, and maintaining a database of what a user has purchased.

Unibill automatically integrates with your project, generating and merging your AndroidManifest and XCode projects as required. Changing between Google Play and Amazon billing is as simple as changing a drop down; Unibill handles everything else for you!

Defining your In App Purchases

The first step is to tell Unibill what purchasable items your application has; the coins, potions, planets or subscriptions that you will be selling to your users.

By doing this first, Unibill can help you upload your purchase metadata to Apple & Google, by generating a bulk upload file describing your purchases.

You define your purchases using the Inventory Editor, a Unity editor window which you can find in the ‘Window/Unibill’ toolbar menu.

Your inventory is tracked in a JSON file located at Assets/Plugins/unibill/resources/unibillInventory.json.txt.

Purchase Types

Consumable Can be purchased repeatedly. Suitable for consumable items such as virtual currencies.
Non Consumable Can only be purchased once. Suitable for one off purchases such as extra levels.
Subscription Has a finite window of validity.

Unibill Id

This uniquely identifies your item to Unibill across all platforms, and is the id you should supply when calling Unibill methods.

By default Unibill assumes that you use the same identifier on each specific billing system (Apple, Google etc).

When this is not the case, you can tell Unibill what identifier your item has on each platform by expanding the platform details for the item and 'overriding' the id.

Name

The name of the purchasable item, as you display it to users.

This field is used when generating the bulk upload files for Apple's platforms and Google Play.

Description

This field is used when generating the bulk upload files for Apple's platforms and Google Play.

Dynamic inventory

If you wish to update your catalogue of products dynamically, without having to update your application, you have two options.

Runtime product definition

When initialising Unibill, you can supply a list of additional products that are available to purchase.

Unibill treats these products the same as those defined statically, retrieving their localized details and making them browsable with the normal inventory methods.

When calling Unibill methods you should refer to these dynamic products using the identifier of their ProductDefinition instances.

                            
public class ProductDefinition {
    public string PlatformSpecificId { get; }
    public PurchaseType Type { get; }
}
                            
                        

Used as follows

                            
var prods = new List<ProductDefinition>() {
    new ProductDefinition(
        "a.product.identifier",
        PurchaseType.Consumable
    ),
    new ProductDefinition(
        "another.product.identifier",
        PurchaseType.NonConsumable
    )
};

Unibiller.Initialise(prods);
                            
                        

Hosted Configuration

With hosted configuration, you host your UnibillInventory json file at a URL, and Unibill will try and fetch an updated inventory at launch. This facility is enabled and configured in the inventory editor.

Note that the updated configuration is not used immediately, but on the following launch.

Unibill data types

PurchasableItem

Unibill uses the PurchasableItem type to represent an item for sale.

This type includes a number of fields describing the item, some of which are from the inventory editor and some of which are retrieved from the billing system, such as localised fields.

Name Description
Id The platform independent unique Unibill Id for this PurchasableItem.
PurchaseType Consumable, Non Consumable or Subscription
name As configured in the inventory editor
description As configured in the inventory editor
localizedPriceString A price string formatted with currency symbol for user display.
localizedTitle The localised name of the item.
localizedDescription The localised description of the item.
isoCurrencySymbol The ISO 4217 currency code.
priceInLocalCurrency A decimal price in the user's local currency.
receipt A purchase receipt, if the item is owned, with platform specific schema.

Receiving messages from Unibill

Unibill sends messages to your Application asynchronously; once you have initialised Unibill, they can be received at any time.

As a result, it is imperative that you subscribe to Unibill's events before you initialise Unibill.

Unibill Initialisation

This event notifies your App that Unibill has finished intialising

                            
public static event Action<UnibillState> onBillerReady;
                            
                        

The UnibillState parameter takes the following values

UnibillState Description
SUCCESS Unibill encountered no problems and is ready to make purchases
SUCCESS_WITH_ERRORS Unibill encountered one or more non critical errors and is ready to make purchases. Details of these errors will have been printed to the console, or you can retrieve the errors manually via the Unibiller.Errors property.
CRITICAL_ERROR Unibill was unable to initialise. Details of the error will have been printed to the console, or you can retrieve them manually. You should not attempt to make any purchases.

Successful Purchases

This event is fired when a purchase succeeds.

                            
public static event Action<PurchaseEvent> onPurchaseComplete;
                            
                        

The PurchaseEvent has the following properties

Name Description
PurchasedItem The item that has been purchased.
Receipt The purchase receipt, issued by the billing system provider (Apple, Google etc).
TransactionId A unique identifier for the transaction, issued by the billing system provider (Apple, Google etc).

Cancelled Purchases

This event is fired when a user cancels the purchase confirmation screen displayed by the billing system.

                            
public static event Action<PurchasableItem> onPurchaseCancelled;
                            
                        

Failed Purchases

This event is fired when a user agrees to the purchase confirmation screen, but the a problem is encountered during the purchase.

Typically this fires if a card is declined or if the network is down.

                            
public static event Action<PurchasableItem> onPurchaseFailed;
                            
                        

Refunded Purchases

This event is fired when a user's purchase has been refunded.

This will occur if you issue a manual refund.

                            
public static event Action<PurchasableItem> onPurchaseRefunded;
                            
                        

Transactions Restored

This event is fired after a call to Unibiller.restoreTransactions();.The parameter tells you if the restoration process was successful.

                            
public static event Action<bool> onTransactionsRestored;
                            
                        

Browsing available items

By type

The following properties list all items for sale, optionally filtered by type (Consumable, Non Consumable, Susbscription).

                            
Unibiller.AllPurchasableItems;
Unibiller.AllNonConsumablePurchasableItems;
Unibiller.AllConsumablePurchasableItems;
Unibiller.AllSubscriptions;
                            
                        

By Id

You can retrieve a specific product if you know its Unibill Identifier.

                            
Unibiller.GetPurchasableItemById("levelPack1");
                            
                        

Making Purchases

You start the purchase process with the following method call, telling Unibill what the user wants to buy.

                            
Unibiller.initiatePurchase("levelPack1");
                            
                        

Note that 'levelPack1' is a platform independent Unibill Id. When the process completes, one of the purchase events will fire.

Restoring Purchases

When your App is installed on a new device, it is important that you give your users any content they have already purchased and are entitled to.

The restore transactions functionality lets you do this this by retrieving details of any Non Consumable purchases the user has previously made.

When this method is called Unibill will fire the purchase event for any items the user owns and is entitled to, the same as if they'd just been purchased.

You should not call this method on every launch; on iOS it will prompt for your password. Instead you should give the user the explicit option to restore by offering them a 'restore' button that calls Unibiller.restoreTransactions().

                            
void Unibiller.restoreTransactions();
                            
                        

The purchase database

Unibill maintains its own local database of which items a user has purchased.

Querying the purchase database

Use this method to find out whether a user has purchased a Non-Consumable item, or how many times a user has purchased a Consumable item

                            
int Unibiller.getPurchaseCount("levelPack1");
                            
                        

Clearing the purchase database

Use this to clear Unibill's local database of purchases. Note that this will not reset Apple, Google et al's record of purchase.

                            
void Unibiller.clearTransactions();
                            
                        

Purchase Receipts

Each billing system provides a cryptographic purchase receipt which serves as proof of purchase and can be verified on a third party server.

Google Play

Receipts are in JSON format with the following schema.

                            
{
    "json":"[This is the original JSON returned by Google Play]",
    "developerPayload":"[If submitted with the purchase request]",
    "signature":"[Generated by Google Play]"
}
                            
                        

iOS

Receipts are base 64 encoded strings, the contents of which are iOS version dependent.

On iOS <= 6, Unibill provides the (deprecated) transaction receipt.

On iOS 7+, Unibill provides the App Receipt, which includes details of all purchases.

Mac App Store

Receipts are base 64 encoded App Receipts.

Amazon

Receipts are in JSON format with the following schema.

                            
{
    "isSandbox": [boolean, true if against sandbox],
    "userId":"[The user's Amazon user Id]",
    "receiptId":"[The purchase receipt Id]"
}
                            
                        

Windows Phone 8 & Windows 8.1

Receipts are in XML format as specified by Microsoft here.

A sample receipt follows.

                            
<Receipt Version="1.0" ReceiptDate="2012-08-30T23:08:52Z" CertificateId="b809e47cd0110a4db043b3f73e83acd917fe1336" ReceiptDeviceId="4e362949-acc3-fe3a-e71b-89893eb4f528">
	<ProductReceipt Id="6bbf4366-6fb2-8be8-7947-92fd5f683530" ProductId="Product1" PurchaseDate="2012-08-30T23:08:52Z" ExpirationDate="2012-09-02T23:08:49Z" ProductType="Durable" AppId="55428GreenlakeApps.CurrentAppSimulatorEventTest_z7q3q7z11crfr" />
	<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
		<SignedInfo>
			<CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
			<SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" />
			<Reference URI="">
				<Transforms>
					<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
				</Transforms>
				<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" />
				<DigestValue>Uvi8jkTYd3HtpMmAMpOm94fLeqmcQ2KCrV1XmSuY1xI=</DigestValue>
			</Reference>
		</SignedInfo>
		<SignatureValue>TT5fDET1X9nBk9/yKEJAjVASKjall3gw8u9N5Uizx4/Le9RtJtv+E9XSMjrOXK/TDicidIPLBjTbcZylYZdGPkMvAIc3/1mdLMZYJc+EXG9IsE9L74LmJ0OqGH5WjGK/UexAXxVBWDtBbDI2JLOaBevYsyy+4hLOcTXDSUA4tXwPa2Bi+BRoUTdYE2mFW7ytOJNEs3jTiHrCK6JRvTyU9lGkNDMNx9loIr+mRks+BSf70KxPtE9XCpCvXyWa/Q1JaIyZI7llCH45Dn4SKFn6L/JBw8G8xSTrZ3sBYBKOnUDbSCfc8ucQX97EyivSPURvTyImmjpsXDm2LBaEgAMADg==</SignatureValue>
	</Signature>
</Receipt>
                            
                        

Samsung Apps

Receipts consist of the purchase Id string. Consult Samsung's IAP purchase guide for validation details.

Refreshing App Receipts

There are certain scenarios where the App Receipt (provided by Unibill alongside a purchase on OSX and iOS 7+) will be missing or stale, whereby it does not reflect the latest state of purchased items.

Since the introduction of App Receipts in OSX and iOS 7, Apple has provided an API to retrieve the latest version of the App Receipt from Apple's servers.

Unfortunately it is not possible for Unibill to handle these scenarios automatically by refreshing the receipt, since Apple's RefreshReceipt has a number of failure scenarios; the API prompts the user for their username and password and additionally requires Internet access.

If receipt validation is essential to your application you will need to detect missing or stale receipts and prompt the user to agree to enter their credentials to refresh the receipt.

Note that Unibiller.getAppleExtensions() will return null on any platform other than the Editor, iOS and the Mac App store.

                            
var appleExtensions = Unibiller.getAppleExtensions();
appleExtensions.onAppReceiptRefreshed += appReceipt => {
Debug.Log(appReceipt);
Debug.Log("Refreshed app receipt!");
};

appleExtensions.onAppReceiptRefreshFailed += () => {
Debug.Log("Failed to refresh app receipt.");
};
// This will prompt for the user's password.
appleExtensions.refreshAppReceipt();
                            
                        

Virtual Currencies

Unibill features built in support for virtual currencies; Unibill will track the player’s balance, incrementing it when they buy more and providing methods to check, credit and debit their balance.

Defining your currencies

Currencies are defined in the inventory editor.

Checking balances

Use this to find out how much currency a user has.

                            
decimal Unibiller.GetCurrencyBalance("gold");
                            
                        

Spending currency

Use this to debit a currency balance.

                            
bool Unibiller.DebitBalance("gold", 100);
                            
                        

Gifting currency

Use this to credit a currency balance.

                            
Unibiller.CreditBalance("gold", 100);
                            
                        

The Unibill demo scene

The demo scene is at Assets/Plugins/unibill/scenes/unibillDemo.

The script that powers it is at Assets/script/UnibillDemo. Exploring this scene is a good way to understand how a Unibill application fits together.

The scene covers purchasing and restoring transactions.

Google Play

Configure your Google Play public key

You must enter your application’s public key in the ‘Google Play public key’ field of the inventory editor.

To get your application’s public key you must first upload a draft APK to the publisher console. You can find it’s public key under the ‘Services & APIs’ section for the application as the ‘Base64-encoded RSA public key’.

Bulk uploading purchase metadata to Google Play

There are two ways to upload your metadata to Google Play

Manually

As of Unibill 1.1.4, Unibill uses Google Play billing V3. With Google Play Billing V3, both Consumable and Non Consumable items should be created as ‘managed’. Unibill will manage consumption of items for you; if you designate an item as being of type ‘Consumable’ within the inventory editor, Unibill will automatically consume the item once the OnPurchaseComplete event has completed. For details of how to manually define your purchases follow Google’s guide.

Automatically using bulk upload

Unibill automatically generates a bulk upload CSV file for use with Google Play, located at Assets/Plugins/unibill/generated/googleplay/MassImportCSV.csv

Testing on an Android device

Before publishing your application, you must test your in App purchases on an Android device.

In order to test you must publish your App as an Alpha or Beta distribution; testing from a draft published app is no longer supported by Google.

Note that whilst your Alpha or Beta APK must be published to test your IAPs, this does not mean your App has to be publicly available, ie visible in the Google Play store.

In order to perform a complete end to end test of your In App purchases, you must do so whilst signed into a device using a test account. For purchasing to work using a test account, note the following.

  • You MUST upload a signed, release version of your APK to Google Play that is PUBLISHED as an alpha or beta distribution.
  • The version number of the APK that you upload MUST match the version number of the APK that you test with.
  • After entering your purchase metadata into the Google Play publisher console, it may take up to 24 hours before you are able to purchase your In App purchases using a test account.

Known issues

Item already owned

The Google Play Android application maintains its own cache of data pertaining to purchased items.

Unfortunately, it is possible for this cache to get out of sync with the authoritative version of what is owned, which is that maintained by Google's servers.

This can manifest itself as a 'You already own this item' error when attempting to purchase an item, when a previous purchase attempt was interrupted for some reason.

This can be resolved by clearing the Google Play Application's data cache under Application Settings, then calling Unibiller.restoreTransactions().

Amazon App Store

Entering your purchase metadata in the Amazon portal

You must enter your purchase metadata into the Amazon developer portal manually; there is no bulk upload facility. To do this you should follow the guide.

Testing using the Amazon test client

The Amazon SDK features an SDK tester that assists you with testing your purchases before you submit your app for review, documented here.

The SDK tester is a separate Android application that must be installed onto a test device alongside your application; you can install it from the Amazon App Store. You must then select the ‘Use sandbox environment’ checkbox in the Unibill Inventory Editor

When this box is ticked Unibill will automatically generate a JSON metadata file describing your purchases and write it to your device’s SD card when initialising. Be sure to untick this box before building the release version of your application.

You can use the Amazon SDK tester to thoroughly test your application, covering such scenarios as in app purchasing being disabled or otherwise unavailable. Simple launch the Amazon SDK tester application on the device to configure your test scenarios.

Apple App Store

Configuring your iOS SKU

You must enter your Application’s ‘SKU’ into the ‘iOS SKU’ field of the inventory editor, as it is configured in iTunes Connect

Price tiers

This field is only relevant if you will be using the Application Loader and bulk upload template to enter your purchase metadata into iTunes Connect. On iOS, prices are structured in tiers. You can set a purchasable’s tier using the slider within its ‘Apple App Store’ section.

Using the screenshot taker

On iOS, every In App purchase has to have an associated screenshot when being submitted to Apple for review. Unibill can help you prepare and submit these screenshots when using the Application Loader.

When running your application you can take a screenshot using ‘Window/Unibill/Take Screenshot“; screenshots are written to Assets/Plugins/unibill/screenshots/. The screenshot is taken of your game view; be sure you are running with a supported iTunes Connect screenshot resolution, such as 480 x 320 or 960 x 640.

You can then associate these screenshots with your purchasable items by assigning them to the ‘Screenshot’ fields in the Inventory Editor:

Uploading your purchase metadata using the Application loader

Apple’s Application Loader lets you upload various aspects of your application to Apple, including binaries and details of your In App Purchases.

Unibill automatically generates a tab delimited bulk upload file describing your purchases, suitable for use with the Application loader. You can find this file at Assets/Plugins/unibill/generated/storekit/MassImportTemplate. You can read the complete guide to the Application Loader here.

Please note that it may take several minutes between uploading your metadata and the metadata appearing in iTunes Connect.

Also note that subscriptions cannot be created using this method – they must be created manually in iTunes Connect.

Ask to Buy

iOS 8 introduced a new parental control feature; Ask to Buy

Ask to buy allows an In App Purchase to be deferred to a parent for approval. When this occurs, Unibill's onPurchaseDeferred event will fire.

                            
Unibiller.onPurchaseDeferred += (item) => {
    // Let your user know an approval request has been sent, eg:
    yourUi.ShowMessage(item.localizedTitle + " is waiting approval!");
    // Continue your App's normal flow.
};
                            
                        

When the purchase is ultimately approved or rejected, Unibill's normal purchase succeeded/failed events will fire. See Apple's documentation for details on how you should handle this situation.

Testing on device

To test on an iOS device you must be using an iTunes connect test user account; you can create these accounts in iTunes connect, then sign out of the app store on the device. You will be prompted to log in when you attempt a purchase or restore transactions.

Do not verify the email address of your test iTunes connect account! Doing so will make the account invalid for testing with the Apple sandbox environment.

If your products are being returned as unavailable for purchase, follow this checklist.

Mac App Store

Mac App Store purchasing follows a similar flow to that on iOS.

You must be a registered Mac developer, create your Mac App store application in iTunes connect along with your in app purchase metadata.

You cannot use the same product identifiers for both iOS and Mac App store apps. Therefore, you will need to use the ‘override id’ functionality in the Inventory editor to specify the unique Mac App store identifiers you have entered into iTunes connect.

Testing In App Purchasing

When building a desktop Mac build you must select ‘Mac App Store validation’ within Unity’s build settings.

Once you have built your App, you must update its info.plist file with your bundle identifier and version strings. Right click on the .app file and click ‘show package contents’, locate the info.plist file and make the following modifications.

                            
<key>CFBundleShortVersionString</key>
<string>1.0.0</string>
<key>CFBundleIdentifier</key>
<string>[Your bundle identifier eg com.outlinegames.unibill]</string>
<key>CFBundleVersion</key>
<string>1.0.0</string>
                            
                        

You can use the following commands to do the modification for you, if you'd like to incorporate this step into an automated build.

                            
sed -i '' 's/unity.DefaultCompany.unity/your.bundle.identifier/g' your.app/Contents/Info.plist
sed -i '' 's/Unity Player version[^<]*/1.0.0/g' your.app/Contents/Info.plist
sed -i '' 's/[0-9]\.[0-9]\.[0-9][^<]*/1.0.0/g' your.app/Contents/Info.plist
                            
                        

Remove any meta files added by Unity (Important!)

Unibill includes an OSX framework bundle (unibillosx.bundle) which Unity interprets as a folder and pollutes with meta files, which prevents correct signing when bundled within your App.

                            
find your.app/ | grep "\.meta$" | xargs rm
                            
                        

You must then sign, package and install your application. You will need to run the following commands from an OSX terminal:

Note that as of OSX Mavericks you will need to instruct signtool to sign Unibill's bundle, since Unity places it in a nonstandard location in your app, before signing the app itself, as follows.

                            
codesign -f --deep -s "3rd Party Mac Developer Application: " your.app/Contents/Plugins/unibillosx.bundle
codesign -f --deep -s "3rd Party Mac Developer Application: " your.app
productbuild --component your.app /Applications --sign "3rd Party Mac Developer Installer: " your.pkg
                            
                        

In order to install the package correctly you must delete the unpackaged .app file before running the newly created package.

You must then launch your App from the Applications folder. The first time you do so, you will be prompted to enter your iTunes account details, for which you should enter your iTunes Connect test user account login. You will then be able to make test purchases against the sandbox environment.

You must sign, package, install your App and launch it from the Applications folder. If you do not do this you will not be able to make purchases.

You must not sign into the main App Store application using your test account or the test account will become invalid.

Windows Phone 8

There are two ways to test on Windows Phone 8; using Unibill’s inbuilt support for the WP8 Mock IAP framework, and by creating a beta distribution of your app. Both methods require a Windows Phone 8 device.

Testing

To test using the mock IAP framework, simply check the “Use mock windows phone” checkbox in the inventory editor. When using the mock framework all purchases succeed. Be sure to uncheck this when publishing.

To test your App as a beta App, create it as a Beta distribution in the windows phone dev centre. You will need to enter your App ID and Publisher Id, which you can find in the microsoft developer portal, into the visual studio project Unity generates.

Windows 8.1

To test using the mock IAP framework, simply check the “Use mock windows 8″ checkbox in the inventory editor. Be sure to uncheck this when publishing.

To package and publish your app please follow this tutorial.

Samsung Apps

Setup

You must have a Samsung device with the Samsung Apps market app for testing on device.

You must register for a Samsung Apps seller account at seller.samsungapps.com, and enter your Samsung Apps Item Group in the inventory editor.

On Samsung Apps, your product identifiers are assigned for you by Samsung. You must tell Unibill what these identifiers are, by overriding the platform identifiers on samsung apps to these values, within the inventory editor:

Testing

In the inventory editor there are three modes that Unibill can run Samsung Apps in.

PRODUCTION Purchases are made against the live Samsung Apps service.You must select this mode to publish your APK
ALWAYS_SUCCEED Purchases will always succeed and a developer popup will show
ALWAYS_FAIL Purchases will always fail and a developer popup will show

Unity Analytics

Unibill features an integration with Unity Analytics.

Simply install and initialise the Unity Analytics SDK and Unibill will automatically send accurate transaction information when purchases occur. There's no need to make manual calls to UnityAnalytics.Transaction(); any such calls should be removed.

Troubleshooting

Unity 5 - incorrect unibillosx.bundle import settings

If you are encountering errors pertaining to unibillosx.bundle check that Unity has preserved the correct platform settings, which should be for the 'standalone' platform only, as below.

Support

For all support requests please include a trace from a device (using adb/XCode/Visual studio etc) where possible

Please direct all support queries to support@outlinegames.com