Initiating a purchase

You can initiate a purchase in your app using the requestPurchase() function. You receive a response to this function when a user completes the purchase process (which may include steps such as signing in to a BlackBerry ID and setting up a preferred payment method).

When you call the requestPurchase() function, only the ID or SKU of the digital good to be purchased is required; you don't need to provide both. If the ID and SKU are both provided, then the ID is used. To use the SKU, you must pass an empty string for the digitalGoodId.

When requestPurchase() finishes, the  PaymentManager::purchaseFinished() signal is emitted for your PaymentManager instance and the PaymentReply::finished()  signal is emitted on the PurchaseReply instance.

The PurchaseReply class inherits the finished() signal from the PaymentReply class.

To analyze the results of the requestPurchase(), you can use PaymentReply::isError() to check if the request was successful.

If isError() returns true, you can use errorCode and errorText to present a dialog box or toast to your user. If isError() returns false, you can use the PurchaseReply class and the receipt() function or the purchaseMetadata() function to present information about the successful purchase to the user.

Initiating a purchase in QML

The following QML code sample uses a Container to represent a digital good that can be sold. A PaymentManager object is attached to the Container to handle purchase requests and a TapHandler is attached to the Container to trigger purchases.

When the user taps the control that represents the digital good, the tapped() signal is emitted and requestPurchase() is called, passing in the SKU and the name of the digital good. When the purchase is complete, the purchaseFinished() signal is emitted and the purchase is stored locally to track digital goods that the user already owns.

import bb.cascades 1.0
import bb.platform 1.2

// This Container represents a DigitalGood that can be sold. 

Container {
    attachedObjects: [
        PaymentManager {
            id: digitalGoodPaymentManager
            onPurchaseFinished: {
                if (reply.errorCode == 0) {
                    // Store this purchase to keep track
                    // of the purchases made by the user.
                } else {
                    console.log("Error: " + reply.errorInfo);
                }
            }
        }
    ]

    // Giving this control an ID allows it to be referenced
    // explicitly from methods where context is lost.

    id: digitalGood

    // Handle taps by the user as a purchase attempt.
    gestureHandlers: TapHandler {
        onTapped: {
            if (digitalGood.owned) {
                // Display a message to the user, or display details
                // about the digital good that they already own.
            } else {
                digitalGoodPaymentManager.requestPurchase("", 
                    digitalGood.sku, 
                    digitalGood.name);
            }
        }
    }
}

Initiating a purchase in C++

The following C++ code sample requests a purchase, passing in an ID and a SKU to requestPurchase(). The response is returned as a PurchaseReply. The function connects the finished() signal to a handlePurchase() function that is declared in your MyPaymentApp.hpp file and implemented in your MyPayment.cpp file.

void MyPaymentApp::purchase(const QString &id, const QString &sku)
{
    // Request a purchase using the ID and SKU of the digital good.
    // Only one is required, but the ID may be empty and the SKU 
    // will be used. 
    const PurchaseReply *reply = 
        m_paymentManager->requestPurchase(id, sku);
    
    // Connect the finished() signal to a 
    // slot to handle the purchase.

    bool success = QObject::connect(reply, 
         SIGNAL(finished()),
         this, 
         SLOT(handlePurchase()));

    if (success) {
       // Signal was successfully connected.

    } else {
       // Failed to connect to signal.
    }
}

You need a handlePurchase() function, also known as a slot, that checks if the purchase finished and succeeded, and emits the appropriate signals.

void MyPaymentApp::handlePurchase()
{
    bb::platform::PurchaseReply *reply = 
        qobject_cast<bb::platform::PurchaseReply*>(sender());
    Q_ASSERT(reply);

    // Check to see if the request finished. 
    if (reply->isFinished()) {
    	
    	// Emit an error signal if there were errors.
        if (reply->isError()) {

            emit infoResponseError(reply->errorCode(), 
                    reply->errorText());

        // Emit a success signal if there were no errors. 
        } else {
            const QString displayString = 
                receiptToString(reply->receipt());

            emit purchaseResponseSuccess(displayString);
        }
    } else {
        qDebug() << "Purchase request did not finish.";
    }

    reply->deleteLater();
}

You should not delete the PurchaseReply object in the slot connected to the finished() signal because you won't be able to access the receipt and metadata in the calling function. You can use QObject::deleteLater() to schedule the PurchaseReply for deletion later.

When you call requestPurchase(), the digital good name and the purchase metadata are also optional parameters, and you might use them in the following scenarios.

Displaying a specific name when a single ID or SKU represents multiple digital goods

If it is impractical to create a unique name and SKU for each of your digital goods, you can use the same name and SKU for multiple digital goods. Any digital good that is part of a group of digital goods with the same name and SKU must be registered as consumable in the BlackBerry World vendor portal. Static digital goods can be sold only once, consumable digital goods can be sold many times. For more information about registering different types of digital goods, seeRegistering with BlackBerry World.

Information that differentiates each digital good in the group (for example, which level was purchased) must be placed in the metadata field.

The technique of creating a single name and SKU for multiple digital goods lets you update the purchase options without submitting a new version of your application. When you call the  PaymentManager::requestPurchase() function in your app, you must pass a metadata argument that allows you to differentiate between digital goods that reference the same SKU.

For example, if a game sells additional levels at a single price point, you can use a generic digital good called "My game level" for all such levels. When a user makes a purchase, the game app should override "My game level" with the name of the level that the user purchased. This approach makes sure that the users are aware of exactly what they are purchasing on the purchase confirmation screen.

Displaying specific purchase metadata

You can use the same name and SKU for multiple digital goods and use the metadata to handle purchases of this digital good. When you call the PaymentManager::requestPurchase() function in your app, you can pass a metadata argument that allows you to differentiate between digital goods that reference the same SKU.

For example, if a book vendor offers multiple titles at a single price point ($4.99) and represents the titles on the vendor portal as a single digital good ("Romance novel"), the ISBN of the book can be retrieved as purchase metadata and displayed on the purchase confirmation screen.

Last modified: 2013-12-21

comments powered by Disqus