Would you like to tell us how we are doing?

You bet No thanks

Creating an advanced application

Before you start working with the advanced application, you should familiarize with the basic application. The basic application shows you how to initialize the UI, and how to create the DigitalGoodsInfo class to store the properties for your digital goods. For more information, see Creating a basic application.

You can use the PaymentSystemDemo.as sample application to learn how to create an advanced application that sells digital goods and manages subscriptions. The sample application shows you how to perform the following tasks:
  • Retrieve and display a list of digital goods
  • Initiate a purchase
  • Check for past purchases
  • Get the price of a digital good
  • Check for subscriptions
  • Cancel a subscription
  • Cancel more than one subscription

Retrieve and display a list of digital goods

The sample application retrieves the list of digital goods from an XML document that is outside of the application. By keeping the list outside of your application, you can easily update the list without having to release a new version of your application.

  1. In PaymentSystemDemo, import the required classes.
    import flash.events.Event;
    import flash.events.IOErrorEvent;
    import flash.net.URLLoader;
    import flash.net.URLRequest;
    
    import qnx.ui.data.DataProvider;
    import qnx.ui.listClasses.List;
    
    import DigitalGoodsInfo;
  2. Declare a variable to hold the list of digital goods that the application retrieves from an external file.
    private var loader:URLLoader;
  3. Declare a variable to hold the list of digital goods that the application displays in the UI.
    private var buyList:List;
  4. Declare a variable to hold the contents of the digitalgoods.xml file, and create a new URLLoader to download the XML document from the specified URL. If the download operation is successful, call the resultHandler function. If there's a problem downloading the list of digital goods, call the faultHandler function.
    var urlRequest:URLRequest = new URLRequest(); 
    urlRequest.url = "http://docs.blackberry.com/digitalgoods.xml";
    loader = new URLLoader();
    loader.addEventListener(IOErrorEvent.IO_ERROR, faultHandler);
    loader.addEventListener(Event.COMPLETE, resultHandler);
    loader.load(urlRequest);
  5. In the resultHandler function, declare the data variable to hold the list of digital goods from the XML document, the remoteData variable to hold onto the XML object, and the dgObject variable to hold the properties of each digital good. After the function loops though the array, populate the list of digital goods by assigning the contents of the data variable to the dataProvider property of the list, and highlight the first item in the list.
    private function resultHandler(event:Event):void
         {
              var data:DataProvider = new DataProvider();
              var remoteData:XML;
              var dgObject:DigitalGoodsInfo;
    
              // creates an array of raw xml data
              remoteData = XML(loader.data);
    
              // loops through each object in the array of xml data, creates
              // DigitalGoodsInfo objects, and displays the names of the
              // digital goods in the list
              for each(var obj:Object in remoteData.digitalgood)
                   {
                        dgObject = new DigitalGoodsInfo(obj.name, 
                             obj.sku, obj.metadata);
                        data.addItem(dgObject);
                   }
    
              buyList.dataProvider = data;
              buyList.selectedIndex = 0;
         }
  6. In the faultHandler function, display an error message if there's a problem retrieving the list of digital goods.
    private function faultHandler(event:Event):void
         {
              trace("Unable to retrieve digital goods from the server.");
         }

Initiate a purchase

When the user presses the Buy button in the sample application, the purchaseHandler function initiates the purchase by invoking paymentSystem.purchase(). PaymentSystem.purchase() takes a variety of arguments that provide information about the digital good that the user wants to buy. For more information about the arguments, see Arguments for purchases.

  1. In PaymentSystemDemo, import the required classes.
    import net.rim.blackberry.events.PaymentErrorEvent;
    import net.rim.blackberry.events.PaymentSuccessEvent;
    import net.rim.blackberry.payment.PaymentSystem;
    import net.rim.blackberry.payment.Price;
    import net.rim.blackberry.payment.Purchase;
  2. In PaymentSystemDemo, declare a variable that is required to initiate purchases.
    private var paymentSystem:PaymentSystem;
  3. In the constructor, add event listeners to listen for successful and unsuccessful purchase attempts.
    public function PaymentSystemDemo()
         {
              .
              .
              paymentSystem.addEventListener(PaymentSuccessEvent.PURCHASE_SUCCESS, purchaseSuccessHandler);
              paymentSystem.addEventListener(PaymentErrorEvent.PURCHASE_ERROR, purchaseErrorHandler);
  4. In the purchaseHandler function, declare a variable called info to hold the properties of the digital good that the user selected from the list of digital goods in the UI. The DigitalGoodsInfo object contains the properties of the digital good.
    private function purchaseHandler(event:MouseEvent):void
         {
              var info:DigitalGoodsInfo = buyList.selectedItem as DigitalGoodsInfo;
  5. In the purchaseHandler function, invoke paymentSystem.purchase(), and pass information about the digital good in the argument list.
    paymentSystem.purchase(null, info.sku, info.name, info.metadata,info.appName, info.icon);
  6. In the purchaseSuccessHandler function, declare a variable for the Purchase object associated with the successful purchase event, and set the value for the variable to the event.purchase property of the PaymentSuccessEvent object that the function receives. The event.purchase property contains the details about the successful purchase. Display the details of the successful purchase, and add the purchase to the past purchases array.
    private function purchaseSuccessHandler
    (event:PaymentSuccessEvent):void
         {
              var purchase:Purchase = event.purchase;
    
              trace("Purchase Success - " + purchase.date
                   + " : " + purchase.digitalGoodID
                   + " : " + purchase.digitalGoodSKU
                   + " : " + purchase.licenseKey
                   + " : " + purchase.metaData
                   + " : " + purchase.itemState
                   + " : " + purchase.startDate
                   + " : " + purchase.endDate
                   + " : " + purchase.intialPeriod
                   + " : " + purchase.purchaseID);
    
              pastPurchases.push(purchase);
         }
  7. In the purchaseErrorHandler function, display the error ID and error message thrown by PaymentSystem. For details about the error message, see Error messages.
    private function purchaseErrorHandler(event:PaymentErrorEvent):void
         {
              trace("Purchase Error - " + event.errorID + 
                   " : " + event.text);
         }

Check for past purchases

Records of a user's past purchases are stored in a file on the device, and on the Payment Service server. When the user presses the Refresh button in the sample application, the refreshHandler function initiates a request to retrieve an array of past purchases by invoking paymentSystem.getExistingPurchases().

When you run your application for the first time, invoke paymentSystem.getExistingPurchases(), and pass in true as the argument. The application refreshes the array of past purchases with the server. Check the array of past purchases, and make sure that all of the digital goods in the array are available.

Each time the application starts afterwards, you can pass in false as the argument to retrieve a cached copy of the purchase history from the device. When you pass in false as the argument, you don't have to worry about web access and network calls.

  1. In PaymentSystemDemo, import the required classes.
    import flash.events.MouseEvent;
    
    import net.rim.blackberry.events.PaymentErrorEvent;
    import net.rim.blackberry.events.PaymentSuccessEvent;
    import net.rim.blackberry.payment.PaymentSystem;
    import net.rim.blackberry.payment.Price;
    import net.rim.blackberry.payment.Purchase;
  2. In the constructor, add event listeners to listen for successful and unsuccessful refresh attempts.
    public function PaymentSystemDemo()
         {
              .
              .
              paymentSystem.addEventListener(PaymentSuccessEvent.
                   GET_EXISTING_PURCHASES_SUCCESS, getPurchasesSuccessHandler);
              paymentSystem.addEventListener(PaymentErrorEvent.
                   GET_EXISTING_PURCHASES_ERROR, getPurchasesErrorHandler);
    
  3. In the purchaseHandler function, invoke paymentSystem.getExistingPurchases() and pass in false as the argument.
    private function refreshHandler(event:MouseEvent):void
         {
              paymentSystem.getExistingPurchases(false);
         }
  4. In the getPurchasesSuccessHandler function, declare a variable for the Purchase object associated with the successful refresh event, and set the value for the pastPurchases array to the event.existingPurchases property of the PaymentSuccessEvent object that the function receives. The event.existingPurchases property contains the details about the past purchase. Check to see if there are any past purchases. If there are past purchases, iterate through the pastPurchases array, and display the details about the purchase. If there are no past purchases, display a message.
    private function getPurchasesSuccessHandler
    (event:PaymentSuccessEvent):void
         {
              var purchase:Purchase;
              pastPurchases = event.existingPurchases;
    
                   if (pastPurchases.length == 0)
                        {
                             trace("No existing purchases");
                        }
                             else
                        {
                             for (var i:int = 0; i < pastPurchases.length; i++)
                                  {
                                       purchase = pastPurchases[i];
                                       trace("Get Existing 
                                       Purchases Success - " + purchase.date
                                       + " : " + purchase.digitalGoodID
                                       + " : " + purchase.digitalGoodSKU
                                       + " : " + purchase.licenseKey
                                       + " : " + purchase.metaData
                                       + " : " + purchase.itemState
                                       + " : " + purchase.startDate
                                       + " : " + purchase.endDate
                                       + " : " + purchase.intialPeriod
                                       + " : " + purchase.purchaseID);
                                  }
                        }
         }
  5. In the getPurchasesErrorHandler function, display the error ID and error message thrown by PaymentSystem. For details about the error message, see Error messages.
    private function getPurchasesErrorHandler
    (event:PaymentErrorEvent):void
         {
              trace("Get Existing Purchases Error - " + event.errorID + " :
              " + event.text);
         }
    

Get the price of a digital good

When the user presses the Get Price button in the sample application, the priceHandler function initiates a request to get the price of the selected digital good by invoking paymentSystem.getPrice().

  1. In PaymentSystemDemo, import the required classes.
    import flash.events.Event;
    
    import net.rim.blackberry.events.PaymentErrorEvent;
    import net.rim.blackberry.events.PaymentSuccessEvent;
    import net.rim.blackberry.payment.PaymentSystem;
    import net.rim.blackberry.payment.Price;
    import net.rim.blackberry.payment.Purchase;
    
    import qnx.ui.listClasses.List;
    
    import valueObjects.DigitalGoodsInfo;
  2. In the constructor, add event listeners to listen for successful and unsuccessful attempts to get the price of a digital good.
    public function PaymentSystemDemo()
    {
        .
        .
        paymentSystem.addEventListener(PaymentSuccessEvent.GET_PRICE_SUCCESS, getPriceSuccessHandler);
        paymentSystem.addEventListener(PaymentErrorEvent.GET_PRICE_ERROR, getPriceErrorHandler);
  3. In the priceHandler function, declare a variable called info to hold the properties of the digital good that the user selected from the list of digital goods in the UI. The DigitalGoodsInfo object contains the properties of the digital good. Invoke paymentSystem.getPrice() and pass in the SKU for the digital good as the argument.
    private function priceHandler(event:Event):void
    {
        var info:DigitalGoodsInfo = buyList.selectedItem as DigitalGoodsInfo;
        paymentSystem.getPrice(null, info.sku);
    }
  4. In the getPriceSuccessHandler function, declare a variable for the Price object associated with the successful get price event, and set the value to the event.price property of the PaymentSuccessEvent object that the function receives. The event.price property contains the price of the digital good. Display the price of the digital good and related subscription information (for example, the cost and length of the subscription).
    private function getPriceSuccessHandler(event:PaymentSuccessEvent):void
    {
        var price:Price = event.price;
        trace("Get Price Success - " + price.price + " : " + price.initialPeriod
            + " : " + price.renewalPrice + " : " + price.renewalPeriod);
    }
  5. In the getPriceErrorHandler function, display the error ID and error message thrown by PaymentSystem. For details about the error message, see Error messages.
    private function getPriceErrorHandler(event:PaymentErrorEvent):void
    {
        trace("Get Price Error - " + event.errorID + " : " + event.text);
    }

Check for subscriptions

When the user presses the Check Existing button in the sample application, the checkExistingHandler function initiates a request to see if the selected digital good is a subscription that the user is subscribed to by invoking paymentSystem.checkExisting().

  1. In PaymentSystemDemo, import the required classes.
    import net.rim.blackberry.events.PaymentErrorEvent;
    import net.rim.blackberry.events.PaymentSuccessEvent;
    import net.rim.blackberry.payment.PaymentSystem;
    import net.rim.blackberry.payment.Price;
    import net.rim.blackberry.payment.Purchase;
    
    import qnx.ui.data.DataProvider;
    import qnx.ui.listClasses.List;
  2. In the constructor, add event listeners to listen for successful and unsuccessful attempts to check for subscriptions.
    public function PaymentSystemDemo()
    {
        .
        .
        paymentSystem.addEventListener(PaymentSuccessEvent.CHECK_EXISTING_SUCCESS, checkExistingSuccess);
        paymentSystem.addEventListener(PaymentErrorEvent.CHECK_EXISTING_ERROR, checkExistingError);
  3. In the priceHandler function, declare a variable called info to hold the properties of the digital good that the user selected from the list of digital goods in the UI. The DigitalGoodsInfo object contains the properties of the digital good. Invoke paymentSystem.checkExisting() and pass in the SKU for the digital good as the argument. If the user is subscribed to a digital good, and the current date is before the subscription endDate, paymentSystem.checkExisting() returns true even after the user cancels the subscription.
    private function priceHandler(event:Event):void
    {
        var info:DigitalGoodsInfo = buyList.selectedItem as DigitalGoodsInfo;
        paymentSystem.checkExisting(null, info.sku);
    }
  4. In the checkExistingSuccess function, display the value in the event.subscriptionExists property of the PaymentSuccessEvent object that the function receives. The event.subscriptionExists property contains the details about the subscription.
    private function checkExistingSuccess(event:PaymentSuccessEvent):void
    {
        trace("Check Existing Success - " + event.subscriptionExists);
    }
  5. In the checkExistingError function, display the error ID and error message thrown by PaymentSystem. For details about the error message, see Error messages.
    private function checkExistingError(event:PaymentErrorEvent):void
    {
    trace("Check Existing Error - " + event.errorID + " : " + event.text);
    }

Cancel a subscription

When the user presses the Cancel Subscription button in the sample application, the cancelSubscriptionHandler function initiates a request to cancel the subscription of the selected digital good by invoking paymentSystem.cancelSubscription().

If you don't provide a way for users to cancel a subscription in your application, users can cancel a subscription in BlackBerry App World. After they cancel a subscription, users might need to press the Refresh List button on the My World screen in BlackBerry App World to see an updated list of subscriptions.

  1. In PaymentSystemDemo, import the required classes.
    import flash.events.Event;
    
    import net.rim.blackberry.events.PaymentErrorEvent;
    import net.rim.blackberry.events.PaymentSuccessEvent;
    import net.rim.blackberry.payment.PaymentSystem;
    import net.rim.blackberry.payment.Price;
    import net.rim.blackberry.payment.Purchase;
    
    import qnx.ui.data.DataProvider;
    import qnx.ui.listClasses.List;
  2. In the constructor, add event listeners to listen for successful and unsuccessful attempts to get the price of a digital good.
    public function PaymentSystemDemo()
    {
         .
         .
        paymentSystem.addEventListener(PaymentSuccessEvent.CANCEL_SUBSCRIPTION_SUCCESS, cancelSubscriptionSuccess);
        paymentSystem.addEventListener(PaymentErrorEvent.CANCEL_SUBSCRIPTION_ERROR, cancelSubscriptionError);
  3. In the cancelSubscriptionHandler function, declare a variable called info to hold the properties of the digital good that the user selected from the list of digital goods in the UI. The DigitalGoodsInfo object contains the properties of the digital good. Declare the purchaseID variable to hold the value that getPurchaseID() returns. Invoke paymentSystem.cancelSubscription() and pass in the purchase ID for the digital good as the argument.
    private function priceHandler(event:Event):void   
    {    
        var info:DigitalGoodsInfo = buyList.selectedItem as DigitalGoodsInfo;    
        paymentSystem.getPrice(null, info.sku);   
    }
  4. In getPurchaseID(), search the past purchases array to find the purchase ID that corresponds to the SKU for the digital good, and return the value to the cancelSubscriptionHandler function.
    private function getPriceSuccessHandler(event:PaymentSuccessEvent):void   
        {    
            var price:Price = event.price;    
            trace("Get Price Success - " + price.price + " : " + price.initialPeriod     
                  + " : " + price.renewalPrice + " : " + price.renewalPeriod);
        }
  5. In the cancelSubscriptionSuccess function, display a message to confirm that the subscription was canceled.
    private function cancelSubscriptionSuccess (event:PaymentSuccessEvent):void
    {
        trace("Cancel Subscription Success");
    }
  6. In the cancelSubscriptionError function, display the error ID and error message thrown by PaymentSystem. For details about the error message, see Error messages
    private function cancelSubscriptionError(event:PaymentErrorEvent):void
    {
        trace("Cancel Subscription Error - " + event.errorID + " : " + event.text);
    }

Cancel more than one subscription

You can cancel more than one subscription at a time by invoking paymentSystem.cancelSubscription() without passing in a purchase ID for a digital good as an argument. After the user cancels the subscriptions, you need to invoke getExistingPurchases() to determine which digital goods the user canceled.

  1. Invoke paymentSystem.cancelSubscription() without passing in a purchase ID. The application displays the list of goods that the user is subscribed to. The user can choose the subscriptions to cancel.

    cancel_subscription_air

  2. After the user cancels the subscriptions, invoke paymentSystem.getExistingPurchases(false) to retrieve a list of past purchases. The list contains the purchase objects, and the itemState parameter for each object shows which subscription the user canceled.
    Purchase.OWNED = purchaseOwned
    Purchase.SUBSCRIBED = purchaseSubscribed
    Purchase.CANCELED = purchaseCancelled
    Purchase.REFUNDED = purchaseRefunded
    Purchase.RENEWED = purchaseRenewed
  3. If the itemState is Purchase.OWNED, Purchase.SUBSCRIBED, or Purchase.RENEWED, indicate within your application that the user has already purchased the digital good.
  4. If the itemState is Purchase.CANCELED, invoke paymentSystem.checkExisting() to see if the subscription period is still active for the digital good. You need to do this because a subscription can be canceled, but still remain active. Alternatively, you can determine if the subscription period is still active by comparing the endDate parameter of the purchase object with the current date.