1/****************************************************************************
2**
3** Copyright (C) 2015 The Qt Company Ltd.
4** Contact: http://www.qt.io/licensing/
5**
6** This file is part of the Purchasing module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL3-COMM$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see http://www.qt.io/terms-conditions. For further
15** information use the contact form at http://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPLv3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl.html.
24**
25** $QT_END_LICENSE$
26**
27****************************************************************************/
28
29#include "qinappstore.h"
30#include "qinappstore_p.h"
31#include "qinapppurchasebackend_p.h"
32#include "qinapppurchasebackendfactory_p.h"
33#include "qinapptransaction.h"
34
35namespace
36{
37class IAPRegisterMetaTypes
38{
39public:
40 IAPRegisterMetaTypes()
41 {
42 qRegisterMetaType<QInAppProduct::ProductType>(typeName: "QInAppProduct::ProductType");
43 }
44} _registerIAPMetaTypes;
45}
46
47QT_BEGIN_NAMESPACE
48
49/*!
50 \class QInAppStore
51 \inmodule QtPurchasing
52 \brief The main entry point for managing in-app purchases.
53
54 QInAppStore is used for managing in-app purchases in your application in a
55 cross-platform way.
56
57 \section1 Using the QInAppStore
58 In general there are two steps to completing an in-app purchase using the
59 API:
60
61 \section2 Initialize the store
62 Upon start-up of your application, connect all signals in QInAppStore to
63 related slots in your own QObject. Then use the registerProduct() function
64 to register the ID of each product you expect to find registered in the
65 external store, as well as its type.
66
67 Registering a product is asynchronous, and will at some point yield one of
68 the following two signals:
69 1. productRegistered() if the product was found in the external store with
70 a matching type.
71 2. productUnknown() if the product was not found in the external store with
72 the type you specified.
73
74 In addition, a transactionReady() signal may be emitted for any existing
75 transaction which has not yet been finalized. At this point, you should
76 check if the transaction has previously been registered. If it hasn't,
77 register it right away. Finally, call QInAppTransaction::finalize() on
78 the transaction.
79
80 \section2 Complete a purchase
81 Once the items have been successfully registered in the store, you can
82 purchase them. Get the previously registered QInAppProduct using
83 registeredProduct() and call QInAppProduct::purchase(). This call is
84 also asynchronous.
85
86 At some point later on, the transactionReady() signal will be emitted for
87 the purchase. Check QInAppTransaction::status() to see if the purchase was
88 completed successfully. If it was, then you must save the information about
89 the purchase in a safe way, so that the application can restore it later.
90
91 When you are done, call QInAppTransaction::finalize(), regardless of its
92 status. Transactions which are not finalized will be emitted again the next
93 time your application calls registerProduct() for the same product.
94
95 \note Please mind that QInAppStore does not save the purchased
96 state of items in the store for you. The application should store this
97 information in a safe way upon receiving the transactionReady() signal,
98 before calling QInAppTransaction::finalize().
99
100 \section1 Types of purchases
101 There are two types of purchases supported by QInAppStore:
102 QInAppProduct::Consumable and QInAppProduct::Unlockable. The former will be
103 consumed when the transaction is completed and QInAppTransaction::finalize()
104 is called, meaning that it can be purchased again, any number of times.
105 Unlockable items can only be purchased once.
106
107 Consumable products are temporary and can be purchased multiple times.
108 Examples could be a day-ticket on the bus or a magic sword in a computer game.
109 Note that when purchasing the same product multiple times, you should call
110 QInAppTransaction::finalize() on each transaction before you can purchase the
111 same product again.
112
113 Unlockable products are products that a user will buy once, and the purchase
114 of these items will be persistent. It can typically be used for things like
115 unlocking content or functionality in the application.
116
117 \section1 Restoring purchases
118 If your application has unlockable products, and does not store the purchase
119 states of these products in a way which makes it possible to restore them
120 when the user reinstalls the application, you should provide a way for the
121 user to restore the purchases manually.
122
123 Call the restorePurchases() function to begin this process. Granted that
124 the remote store supports it, you will then at some point get transactionReady()
125 for each unlockable item which has previously been purchased by the current user.
126
127 Save the purchase state of each product and call QInAppTransaction::finalize() as
128 you would for a regular purchase.
129
130 Since restorePurchases() may, on some platforms, cause the user to be prompted for
131 their password, it should usually be called as a reaction to user input. For instance
132 applications can have a button in the UI which will trigger restorePurchases() and
133 which users can hit manually if they have reinstalled the application (or installed
134 it on a new device) and need to unlock the features that they have previously paid
135 for.
136
137 \note This depends on support for this functionality in the remote store. If
138 the remote store does not save the purchase state of unlockable products for
139 you, the call will yield no transactionReady() signals, as if no products have
140 been purchased. Both the Android and OS X / iOS backends support restoring unlockable
141 products.
142
143*/
144
145/*!
146 * Constructs a QInAppStore with the given \a parent.
147 */
148QInAppStore::QInAppStore(QObject *parent)
149 : QObject(parent)
150{
151 d = QSharedPointer<QInAppStorePrivate>(new QInAppStorePrivate);
152 setupBackend();
153}
154
155/*!
156 * Destroys the QInAppStore.
157 */
158QInAppStore::~QInAppStore()
159{
160}
161
162/*!
163 * \internal
164 */
165void QInAppStore::setupBackend()
166{
167 d->backend = QInAppPurchaseBackendFactory::create();
168 d->backend->setStore(this);
169
170 connect(sender: d->backend, signal: &QInAppPurchaseBackend::ready,
171 receiver: this, slot: &QInAppStore::registerPendingProducts);
172 connect(sender: d->backend, signal: &QInAppPurchaseBackend::transactionReady,
173 receiver: this, slot: &QInAppStore::transactionReady);
174 connect(sender: d->backend, signal: &QInAppPurchaseBackend::productQueryFailed,
175 receiver: this, slot: &QInAppStore::productUnknown);
176 connect(sender: d->backend, signal: &QInAppPurchaseBackend::productQueryDone,
177 receiver: this, slot: static_cast<void (QInAppStore::*)(QInAppProduct *)>(&QInAppStore::registerProduct));
178}
179
180/*!
181 * \internal
182 */
183void QInAppStore::registerProduct(QInAppProduct *product)
184{
185 d->registeredProducts[product->identifier()] = product;
186 emit productRegistered(product);
187}
188
189/*!
190 * \internal
191 *
192 * Called when the backend is finished initialized and will create products which were
193 * registered while the backend was still working.
194 */
195void QInAppStore::registerPendingProducts()
196{
197 QList<QInAppPurchaseBackend::Product> products;
198 products.reserve(alloc: d->pendingProducts.size());
199
200 QHash<QString, QInAppProduct::ProductType>::const_iterator it;
201 for (it = d->pendingProducts.constBegin(); it != d->pendingProducts.constEnd(); ++it)
202 products.append(t: QInAppPurchaseBackend::Product(it.value(), it.key()));
203 d->pendingProducts.clear();
204
205 d->backend->queryProducts(products);
206 if (d->pendingRestorePurchases)
207 restorePurchases();
208}
209
210/*!
211 * Requests existing purchases of unlockable items and will yield a transactionReady()
212 * signal for each unlockable product that the remote store confirms have previously been
213 * purchased by the current user.
214 *
215 * This function can typically be used for restoring unlockable products when the application
216 * has been reinstalled and lost the saved purchase states.
217 *
218 * \note Calling this function may prompt the user for their password on some platforms.
219 */
220void QInAppStore::restorePurchases()
221{
222 if (d->backend->isReady()) {
223 d->pendingRestorePurchases = false;
224 d->backend->restorePurchases();
225 } else {
226 d->pendingRestorePurchases = true;
227 }
228}
229
230/*!
231 * Sets the platform specific property given by \a propertyName to \a value. This can be used
232 * to pass information to the platform implementation. The properties will be silently ignored
233 * on other platforms.
234 *
235 * Currently, the only supported platform property is "AndroidPublicKey" which is used by the Android
236 * backend to verify purchases. If it is not set, purchases will be accepted with no verification.
237 * (You can also do the verification manually by getting the signature from the QInAppTransaction object
238 * for the purchase.) For more information, see
239 * \l{http://developer.android.com/google/play/billing/billing_integrate.html#billing-security}
240 * {the Android documentation for billing security}.
241 *
242 */
243void QInAppStore::setPlatformProperty(const QString &propertyName, const QString &value)
244{
245 d->backend->setPlatformProperty(propertyName, value);
246}
247
248/*!
249 * Registers a product identified by \a identifier and with the given \a productType.
250 * The \a identifier must match the identifier of the product in the remote store. If
251 * the remote store differentiates between consumable and unlockable products, the
252 * \a productType must also match this.
253 *
254 * Calling this function will asynchronously yield either a productRegistered() or a
255 * productUnknown() signal. It may also yield a transactionReady() signal if there is
256 * a pending transaction for the product which has not yet been finalized.
257 */
258void QInAppStore::registerProduct(QInAppProduct::ProductType productType, const QString &identifier)
259{
260 if (!d->backend->isReady()) {
261 d->pendingProducts[identifier] = productType;
262 if (!d->hasCalledInitialize) {
263 d->hasCalledInitialize = true;
264 d->backend->initialize();
265 }
266 } else {
267 d->backend->queryProduct(productType, identifier);
268 }
269}
270
271/*!
272 * Returns the previously registered product uniquely known by the \a identifier.
273 */
274QInAppProduct *QInAppStore::registeredProduct(const QString &identifier) const
275{
276 return d->registeredProducts.value(akey: identifier);
277}
278
279/*!
280 * \fn QInAppStore::productRegistered(QInAppProduct *product)
281 *
282 * This signal is emitted when information about a \a product has been collected from the
283 * remote store. It is emitted as a reaction to a registerProduct() call for the same
284 * product.
285 *
286 * \sa productUnknown()
287 */
288
289/*! \fn QInAppStore::productUnknown(QInAppProduct::ProductType productType, const QString &identifier)
290 *
291 * This signal is emitted when the product named \a identifier was registered using registerProduct()
292 * and matching information could not be provided by the remote store. The \a productType matches
293 * the product type which was originally passed to registerProduct().
294 *
295 * \sa productRegistered()
296 */
297
298/*!
299 * \fn QInAppStore::transactionReady(QInAppTransaction *transaction)
300 *
301 * This signal is emitted whenever there is a \a transaction which needs to be finalized.
302 * It is emitted either when a purchase request has been made for a product, when restorePurchases()
303 * has been called and the product was previously purchased, or when registerProduct() was called
304 * for a product and there was a pending transaction for the product which had not yet been finalized.
305 */
306
307QT_END_NAMESPACE
308

source code of qtpurchasing/src/purchasing/inapppurchase/qinappstore.cpp