Using BlackBerry PaymentService with Adobe AIR for the PlayBook

Posted on January 15, 2011 | 2 comments

Part of BlackBerry’s AppWorld services is the ability to have your users purchase goods inside your application. This service provides an API to use inside your AIR for PlayBook applications. Read on to check out the basics of using this new API, new as of Beta 3 or Tablet OS SDK for Adobe AIR 0.9.2.

I will show you how to use the API in local mode to test the different responses your application can get during a purchase sequence. To test the API for real you will have to register your goods with BlackBerry as a vendor. I am not familiar with that process at the moment, I’ll leave that for another blog post. Here is a link for more information on the Payment Services.

Although the current documentation, in the link above, does not explain how to use the Tablet OS SDK for AIR payment specific API’s it is available. The rest of the post will walk you through an example application that can be found on github under PaymentService folder.

The PaymentService application looks like this:

What the picture above shows is two labels and 3 arrowhead images. The user would click on the a specific arrowhead to purchase the arrowhead of their choice.

Using the code from my QNX with MXML post, I laid out the application like this.

<?xml version="1.0" encoding="utf-8"?>
<r:QApplication
    xmlns:fx="http://ns.adobe.com/mxml/2009"
    xmlns:r="http://ns.renaun.com/mxml/2010"
    margins="{Vector.&lt;Number&gt;([12,12,12,12])}"
    flow="{ContainerFlow.VERTICAL}"
    align="{ContainerAlign.NEAR}"
    size="100" sizeUnit="{SizeUnit.PERCENT}"
    xmlns:text="qnx.ui.text.*">
   
    <fx:Script source="PaymentServiceSource.as" />
   
    <text:Label text="Click to Purchase an Arrowhead:"
            autoSize="{TextFieldAutoSize.LEFT}" />
    <r:Image source="com/renaun/embed/blue_arrowhead.png"
             click="purchaseObject(event)" />
    <r:Image source="com/renaun/embed/green_arrowhead.png"
             click="purchaseObject(event)" />
    <r:Image source="com/renaun/embed/red_arrowhead.png"
             click="purchaseObject(event)" />
    <text:Label id="lblOutput" text="messages will show up here"
            autoSize="{TextFieldAutoSize.LEFT}" />
</r:QApplication>

This declares a QNX container with vertical flow and adds the labels and images. The Image class (notice the r namespace) in the MXML is actually a class that extends the QNX Image class to allow for setting images by setting a source property. The real logic happens when you click on a button. Here is the code for the PaymentServiceSource.as file:

import net.rim.blackberry.events.PaymentErrorEvent;
import net.rim.blackberry.events.PaymentSuccessEvent;
import net.rim.blackberry.payment.PaymentSystem;

import qnx.ui.core.ContainerAlign;
import qnx.ui.core.ContainerFlow;
import qnx.ui.core.SizeUnit;
import qnx.ui.data.DataProvider;

private var paymentService:PaymentSystem;

private var goods:Array = [{sku:"1001", name: "Blue Arrowhead", meta: "saleprice", app: "Arrow R US", icon: "/com/renaun/embed/blue_arrowhead_small.png"},
    {sku:"1002", name: "Green Arrowhead", meta: "saleprice", app: "Arrow R US", icon: "/com/renaun/embed/green_arrowhead_small.png"},
    {sku:"1003", name: "Red Arrowhead", meta: "saleprice", app: "Arrow R US", icon: "/com/renaun/embed/red_arrowhead_small.png"}]

protected function purchaseObject(event:MouseEvent):void
{
    if (!paymentService)
    {
        paymentService = new PaymentSystem();
        paymentService.addEventListener(PaymentErrorEvent.PAYMENT_SERVER_ERROR, paymentErrorHandler);
        paymentService.addEventListener(PaymentErrorEvent.USER_CANCELLED, paymentErrorHandler);
        paymentService.addEventListener(PaymentErrorEvent.PAYMENT_ERROR, paymentErrorHandler);
        paymentService.addEventListener(PaymentErrorEvent.DIGITAL_GOOD_NOT_FOUND, paymentErrorHandler);
        paymentService.addEventListener(PaymentSuccessEvent.PAYMENT_SUCCESS, paymentSuccessHandler);
        // Set to local mode to test each event/state
        paymentService.setConnectionMode(PaymentSystem.CONNECTION_MODE_LOCAL);
    }
    // Very brittle way to look up the object i know.
    var obj:Object = goods[getChildIndex(event.target as DisplayObject)-1];
    paymentService.purchase(obj.sku, null, obj.name, obj.meta, obj.app, "file://" + File.applicationDirectory.nativePath + obj.icon);
}
private function paymentSuccessHandler(event:PaymentSuccessEvent):void
{
    lblOutput.text = "Success: " + event.purchase.date + " - " + event.purchase.licenseKey;
}
private function paymentErrorHandler(event:PaymentErrorEvent):void
{
    lblOutput.text = "Error[" + event.type + "]: " + event.message;
}

First thing to notice is the net.rim.blackberry.payment.PaymentSystem class. This is where the API for purchases happens. You create a new instance of the PaymentSystem and then call the purchase() method. Seems simple, well the complexity is in handling all the success and error cases. This examples adds listeners to all the different events and outputs the different messages to the bottom label.

NOTE: There is an error in 0.9.2 SDK that if you auto import net.rim.blackberry.payments.PaymentSuccessEvent instead of net.rim.blackberry.events.PaymentSuccessEvent. This is a metadata typo and will probably be fixed in the future, for now the workaround is to manual fix the typo in the import statements.

The PaymentService running in local mode allow the developer test all the different scenarios before hooking it up to a real sku that you have registered as a vendor with BlackBerry. This is done through the paymentService.setConnectionMode(PaymentSystem.CONNECTION_MODE_LOCAL); line of code. If you comment this line of code (which is the default) you will be running in production mode against the live AppWorld servers. But on the BlackBerry Tablet OS PlayBook simulator this is the message you get if you try and do that:

Production Mode Message on Simulator

Lets take a closer look at the paymentService.purchase() method call. Here is the current doc info available from the BlackBerry Tablet OS SDK for Adobe AIR asdocs.

digitalGoodID:String (default = null) — Digital Good ID

Only the ID or SKU of the digital good to be purchased is required; it is not necessary to provide both. If both the ID and SKU are provided, then the ID takes precedence; the SKU is only used if the digital good cannot be located by the Payment Service based on the ID.

digitalGoodSKU:String (default = null) — Digital Good SKU

See description of digitalGoodID

Optional Arguments

digitalGoodName:String (default = null) — Digital Good Name

A digital good name should be provided in the case where a single ID/SKU represents multiple digital goods on the Payment Service server, and a more specific digital good name should be displayed on the purchase screen. For example, if a game sells additional levels via the Payment Service at a single price point, then a generic “My game level” digital good can be used for all such levels. However, at purchase time, the game application should override “My game level” with the name of the level being purchased. In this way, the end user is aware of exactly what they are purchasing on the purchase confirmation screen.

metaData:String (default = null) — Metadata

Metadata offers the application developer a way to store information about each purchase on the Payment Service server, and to retrieve that data via net.rim.blackberry.api.payment.PaymentSystem.getExistingPurchases(boolean). For example, assume a book vendor offers many titles at a single price point, and represents them on the vendor portal as a single digital good. In this case, the ISBN of the book can be provided as metadata, which uniquely identifies the digital good that was purchased. The entire list of purchased books can then be retrieved at any time by obtaining previous purchases via the getExistingPurchases method, filtering on the book’s digital good Content ID, and finally enumerating the ISBNs in the metadata of each purchase.

purchaseAppName:String (default = null) — Purchase Application Name

To further give context to the end user during an in-application purchase, a banner is displayed along the top of the purchase and BlackBerry ID login screens, showing the name and icon of the application the purchase is being made from (i.e., the purchasing application). To customize the name and icon that are displayed, simply provide them as arguments. If the name or icon are not provided as arguments, then they are retrieved from the purchasing application’s descriptor. However, this may not work for applications that register with the home screen dynamically; in these cases, it is highly recommended that the purchasing application explicitly provide a name and icon as part of the purchase arguments.

purchaseAppIcon:String (default = null) — Purchase Application Icon

See description of purchaseAppName.

In the code example above all the parameters worked as stated. Except I had no way to test the metadata parameter data. With the the PaymentService set in the local connection mode you can simulator a real purchase, cancel purchase, goods not found, and server error. Here is what it looks like after the purchase() is called.

PaymentService test mode purchase popup.

And here is the options available to test (also hitting the cancel button will send a message).

PaymentService test mode purchase popup with options.

I do not know if this is exactly how the in app purchase UI will look for users, especially as the text refers to a buy now button. But you should notice that I was able to define the app name, goods name and goods icon through the purchase method parameters. The price seems to be coming from the AppWorld side and is probably driving by the process of registering goods as a vendor and getting a sku.

Either way this is the current info on how to get started using the new PaymentService API. More to come as we find more information out about this API.