diff options
Diffstat (limited to 'src/mobileextras/inapppurchase/qinappstore.cpp')
-rw-r--r-- | src/mobileextras/inapppurchase/qinappstore.cpp | 268 |
1 files changed, 268 insertions, 0 deletions
diff --git a/src/mobileextras/inapppurchase/qinappstore.cpp b/src/mobileextras/inapppurchase/qinappstore.cpp new file mode 100644 index 0000000..a1f56ae --- /dev/null +++ b/src/mobileextras/inapppurchase/qinappstore.cpp @@ -0,0 +1,268 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the Qt Mobile Extras Add-on. +** +** $QT_BEGIN_LICENSE$ +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qinappstore.h" +#include "qinappstore_p.h" +#include "qinapppurchasebackend_p.h" +#include "qinapppurchasebackendfactory_p.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QInAppStore + \brief The main entry point for managing in-app purchases + + QInAppStore is used for managing in-app purchases in your application in a + cross-platform way. + + \section1 Using the QInAppStore + In general there are two steps to completing an in-app purchase using the + API: + + \section2 Initialize the store + Upon start-up of your application, connect all signals in QInAppStore to + related slots in your own QObject. Then use the registerProduct() function + to register the ID of each product you expect to find registered in the + external store, as well as its type. + + Registering a product is asynchronous, and will at some point yield one of + the following two signals: + 1. productRegistered() if the product was found in the external store with + a matching type. + 2. productUnknown() if the product was not found in the external store with + the type you specified. + + In addition, a transactionReady() signal may be emitted for any existing + transaction which has not yet been finalized. At this point, you should + check if the transaction has previously been registered. If it hasn't, + register it right away. Finally, call QInAppTransaction::finalize() on + the transaction. + + \section2 Complete a purchase + Once the items have been successfully registered in the store, you can + purchase them. Get the previously registered QInAppProduct using + registeredProduct() and call QInAppProduct::purchase(). This call is + also asynchronous. + + At some point later on, the transactionReady() signal will be emitted for + the purchase. Check QInAppTransaction::status() to see if the purchase was + completed successfully. If it was, then you must save the information about + the purchase in a safe way, so that the application can restore it later. + + When you are done, call QInAppTransaction::finalize(), regardless of its + status. Transactions which are not finalized will be emitted again the next + time your application calls registerProduct() for the same product. + + \note Please mind that QInAppStore does not save the purchased + state of items in the store for you. The application should store this + information in a safe way upon receiving the transactionReady() signal, + before calling QInAppTransaction::finalize(). + + \section1 Types of purchases + There are two types of purchases supported by QInAppStore: + QInAppProduct::Consumable and QInAppProduct::Unlockable. The former will be + consumed when the transaction is completed and QInAppTransaction::finalize() + is called, meaning that it can be purchased again, any number of times. + Unlockable items can only be purchased once. + + Consumable products are temporary and can be purchased multiple times. + Examples could be a day-ticket on the bus or a magic sword in a computer game. + Note that when purchasing the same product multiple times, you should call + QInAppTransaction::finalize() on each transaction before you can purchase the + same product again. + + Unlockable products are products that a user will buy once, and the purchase + of these items will be persistent. It can typically be used for things like + unlocking content or functionality in the application. + + \section1 Restoring purchases + If your application has unlockable products, and does not store the purchase + states of these products in a way which makes it possible to restore them + when the user reinstalls the application, you should provide a way for the + user to restore the purchases manually. + + Call the restorePurchases() function to begin this process. Granted that + the remote store supports it, you will then at some point get transactionReady() + for each unlockable item which has previously been purchased by the current user. + + Save the purchase state of each product and call QInAppTransaction::finalize() as + you would for a regular purchase. + + Since restorePurchases() may, on some platforms, cause the user to be prompted for + their password, it should usually be called as a reaction to user input. For instance + applications can have a button in the UI which will trigger restorePurchases() and + which users can hit manually if they have reinstalled the application (or installed + it on a new device) and need to unlock the features that they have previously paid + for. + + \note This depends on support for this functionality in the remote store. If + the remote store does not save the purchase state of unlockable products for + you, the call will yield no transactionReady() signals, as if no products have + been purchased. Both the Android and iOS backends support restoring unlockable + products. + +*/ + +QInAppStore::QInAppStore(QObject *parent) + : QObject(parent) +{ + d = QSharedPointer<QInAppStorePrivate>(new QInAppStorePrivate); + setupBackend(); +} + +QInAppStore::~QInAppStore() +{ +} + +/*! + * \internal + */ +void QInAppStore::setupBackend() +{ + d->backend = QInAppPurchaseBackendFactory::create(); + + connect(d->backend, SIGNAL(ready()), + this, SLOT(registerPendingProducts())); + connect(d->backend, SIGNAL(transactionReady(QInAppTransaction *)), + this, SIGNAL(transactionReady(QInAppTransaction *))); + connect(d->backend, SIGNAL(productQueryFailed(QInAppProduct::ProductType,QString)), + this, SIGNAL(productUnknown(QInAppProduct::ProductType,QString))); + connect(d->backend, SIGNAL(productQueryDone(QInAppProduct *)), + this, SLOT(registerProduct(QInAppProduct*))); +} + +/*! + * \internal + */ +void QInAppStore::registerProduct(QInAppProduct *product) +{ + d->registeredProducts[product->identifier()] = product; + emit productRegistered(product); +} + +/*! + * \internal + * + * Called when the backend is finished initialized and will create products which were + * registered while the backend was still working. + */ +void QInAppStore::registerPendingProducts() +{ + QHash<QString, QInAppProduct::ProductType>::const_iterator it; + for (it = d->pendingProducts.constBegin(); it != d->pendingProducts.constEnd(); ++it) { + QString identifier = it.key(); + QInAppProduct::ProductType productType = it.value(); + d->backend->queryProduct(productType, identifier); + } + d->pendingProducts.clear(); +} + +/*! + * Requests existing purchases of unlockable items and will yield a transactionReady() + * signal for each unlockable product that the remote store confirms have previously been + * purchased by the current user. + * + * This function can typically be used for restoring unlockable products when the application + * has been reinstalled and lost the saved purchase states. + * + * \note Calling this function may prompt the user for their password on some platforms. + */ +void QInAppStore::restorePurchases() +{ + d->backend->restorePurchases(); +} + +/*! + * Sets the platform specific property given by \a propertyName to \a value. This can be used + * to pass information to the platform implementation. The properties will be silently ignored + * on other platforms. + * + * Currently, the only supported platform property is "AndroidPublicKey" which is used by the Android + * backend to verify purchases. If it is not set, purchases will be accepted with no verification. + * (You can also do the verification manually by getting the signature from the QInAppTransaction object + * for the purchase.) For more information, see + * \l{http://developer.android.com/google/play/billing/billing_integrate.html#billing-security} + * {the Android documentation for billing security}. + * + */ +void QInAppStore::setPlatformProperty(const QString &propertyName, const QString &value) +{ + d->backend->setPlatformProperty(propertyName, value); +} + +/*! + * Registers a product identified by \a identifier and with the given \a productType. + * The \a identifier must match the identifier of the product in the remote store. If + * the remote store differentiates between consumable and unlockable products, the + * \a productType must also match this. + * + * Calling this function will asynchronously yield either a productRegistered() or a + * productUnknown() signal. It may also yield a transactionReady() signal if there is + * a pending transaction for the product which has not yet been finalized. + */ +void QInAppStore::registerProduct(QInAppProduct::ProductType productType, const QString &identifier) +{ + if (!d->backend->isReady()) { + if (!d->hasCalledInitialize) { + d->hasCalledInitialize = true; + d->backend->initialize(); + } + d->pendingProducts[identifier] = productType; + } else { + d->backend->queryProduct(productType, identifier); + } +} + +/*! + * Returns the previously registered product uniquely known by the \a identifier. + */ +QInAppProduct *QInAppStore::registeredProduct(const QString &identifier) const +{ + return d->registeredProducts.value(identifier); +} + +/*! + * \fn QInAppStore::productRegistered(QInAppProduct *product) + * + * This signal is emitted when information about a \a product has been collected from the + * remote store. It is emitted as a reaction to a registerProduct() call for the same + * product. + * + * \sa productUnknown() + */ + +/*! /fn QInAppStore::productUnknown(QInAppProduct::ProductType productType, const QString &identifier) + * + * This signal is emitted when a product was registered using registerProduct() and matching + * information could not be provided by the remote store. + * + * \sa productRegistered() + */ + +/*! + * \fn QInAppStore::transactionReady(QInAppTransaction *transaction) + * + * This signal is emitted whenever there is a \a transaction which needs to be finalized. + * It is emitted either when a purchase request has been made for a product, when restorePurchases() + * has been called and the product was previously purchased, or when registerProduct() was called + * for a product and there was a pending transaction for the product which had not yet been finalized. + */ + +QT_END_NAMESPACE |