summaryrefslogtreecommitdiffstats
path: root/src/mobileextras/inapppurchase/qinappstore.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mobileextras/inapppurchase/qinappstore.cpp')
-rw-r--r--src/mobileextras/inapppurchase/qinappstore.cpp268
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