summaryrefslogtreecommitdiffstats
path: root/src/purchasing/doc/src/gettingstarted-qml.qdoc
blob: 4b25d912381bb9cdb9633df1e5f923a1e9772080 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the documentation of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:FDL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Free Documentation License Usage
** Alternatively, this file may be used under the terms of the GNU Free
** Documentation License version 1.3 as published by the Free Software
** Foundation and appearing in the file included in the packaging of
** this file. Please review the following information to ensure
** the GNU Free Documentation License version 1.3 requirements
** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
** $QT_END_LICENSE$
**
****************************************************************************/

/*!

  \page qtpurchasing-gettingstarted-qml.html
  \title Getting Started with Qt Purchasing in QML
  \brief Guide to getting started with Qt Purchasing using QML.

  This guide assumes that you have registered the in-app products for your
  application in the external store. For more information about registering
  products, see \l{Registering Products in Google Play} and
  \l{Registering Products in App Store}

  \section1 Preparing The Application

  Use the following \c import statement in the QML files to access the Qt
  Purchasing QML types:

  \qml
  import QtPurchasing 1.0
  \endqml

  Add the following statement to your \c .pro file to link against the Qt
  Purchasing library:

  \code
  QT += purchasing
  \endcode


  \section1 Registering Products

  Before you can operate on the products in your code, they must be
  registered in the QML graph. You start by making a \l{Store} item,
  and then create each product as a child of this.

  \qml
  Store {
      Product {
          identifier: "consumableProduct"
          type: Product.Consumable

          // ...
      }

      Product {
          identifier: "unlockableProduct"
          type: Product.Unlockable

          // ...
      }
  }
  \endqml

  As you can see, there are consumable products and unlockable products. The former
  can be purchased any number of times by the same user, while the latter can only
  be purchased once.

  \section1 The Product Declaration

  For each product you must fill out the \c identifier, before the product can
  be queried from the external store. You should also always add a \l{QtPurchasing::Product::onPurchaseSucceeded}{onPurchaseSucceeded}
  and a \l{QtPurchasing::Product::onPurchaseFailed}{onPurchaseFailed} handler if you intend to provide the option to purchase
  the products. If you are also using the restore functionality, you should add a
  \l{QtPurchasing::Product::onPurchaseRestored}{onPurchaseRestored} handler to your unlockable products.

  The signal handlers should handle the incoming transaction. Once the transaction
  has been handled appropriately, it should be finalized. For instance, when a purchase
  has succeeded, it's appropriate to save information about the purchased product in
  persistent storage, so that this product can still be available the next time the
  application launches.

  The following example calls custom methods to save data about a succeeded purchase so that
  it survives across application runs. After verifying that the data has been stored, it finalizes
  the transaction. When the transaction has failed, it displays information about the failure
  to the user and finalizes the transaction.

  \qml
  Store {
      id: store
      Product {
          id: healthPotionProduct
          identifier: "healthPotion"
          type: Product.Consumable

          property bool purchasing: false

          onPurchaseSucceeded: {
              if (!hasAlreadyStoredTransaction(transaction.orderId)) {
                  ++healthPotions
                  if (!addHealthPotionToPersistentStorage(transaction.orderId)) {
                      popupErrorDialog(qsTr("Unable to write to persistent storage. Please make sure there is sufficient space and restart."))
                  } else {
                      transaction.finalize()
                  }
              }

              // Reset purchasing flag
              purchasing = false
          }

          onPurchaseFailed: {
              popupErrorDialog(qsTr("Purchase not completed."))
              transaction.finalize()

              // Reset purchasing flag
              purchasing = false
          }
      }
  }
  \endqml

  If a transaction is not finalized, it will be called again for the same transaction the next time the application
  starts up, providing another chance to store the data. The transaction for a consumable product has
  to be finalized before the product can be purchased again.

  \section1 Purchasing A Product

  In order to purchase a product, call the object's purchase() method. This launches a platform-specific, asynchronous
  process to purchase the product, for example by requesting the user's password and confirmation of the purchase.
  In most cases, you should make sure that the application UI is not accepting input while the purchasing request
  is being processed, as this is not handled automatically on all platforms.

  The following example adds a button to be used with the example product in the previous section:
  \qml
  Rectangle {
      id: button
      width: 100
      height: 50

      Text {
          anchors.centerIn: parent
          text: qsTr("Buy health potion for only " + healthPotionProduct.price + "!")
      }

      MouseArea {
          enabled: !healthPotionProduct.purchasing && healthPotionProduct.status === Product.Registered
          anchors.fill: parent
          onClicked: {
              healthPotionProduct.purchasing = true
              healthPotionProduct.purchase()
          }
      }
  }
  \endqml

  When the button is clicked, the purchase process is started. At some point in the future, either the
  \l{QtPurchasing::Product::onPurchaseFailed}{onPurchaseFailed} handler will be called (for example if the user cancels the transaction), or the
  \l{QtPurchasing::Product::onPurchaseSucceeded}{onPurchaseSucceeded} handler will be called.

  \note The button is only enabled if the product's status is set to Registered. The registration process
  for a product is asynchronous, so purchases attempted on a product before it has been successfully registered
  will always fail.

  \section1 Restoring Previously Purchased Products

  If the application is uninstalled and subsequently reinstalled (or installed by the same user on
  a different device) you should provide a way to restore the previously purchased unlockable products
  in the external market place.

  To start the process of restoring purchases, you should call the restorePurchases() method in the
  \l Store object. This will cause the onPurchaseRestored handler to be called in each of the application's
  unlockable products that has previously been purchased by the current user.

  Continuing on the example from before, which could be some sort of role-playing computer game, lets imagine
  that the game has downloadable content that you can buy to expand the game further. This should be an unlockable product,
  because the user should not have to purchase it more than once.

  \qml
  Store {
      id: store

      // ... other products

      Product {
          id: dlcForestOfFooBarProduct
          identifier: "dlcForestOfFooBar"
          type: Product.Unlockable

          property bool purchasing: false

          onPurchaseSucceeded: {
              if (!hasMap("forestOfFooBar.map")) {
                  if (!downloadExtraMap("forestOfFooBar.map")) {
                      popupErrorDialog(qsTr("Unable to download The Forest of FooBar map. Please make sure there is sufficient space and restart."))
                  } else {
                      transaction.finalize()
                  }
              }

              // Reset purchasing flag
              purchasing = false
          }

          onPurchaseFailed: {
              popupErrorDialog(qsTr("Purchase not completed."))
              transaction.finalize()

              // Reset purchasing flag
              purchasing = false
          }

          onPurchaseRestored: {
              if (!hasMap("forestOfFooBar.map")) {
                  if (!downloadExtraMap("forestOfFooBar.map")) {
                      popupErrorDialog(qsTr("Unable to download The Forest of FooBar map. Please make sure there is sufficient space and restart."))
                  } else {
                      transaction.finalize()
                  }
              }
          }
      }
  }
  \endqml

  If a user buys the downloadable content and later either installs the game on another device or uninstalls and reinstalls the game,
  you can provide a way to restore the purchase, such as the following button:

  \qml
  Rectangle {
      id: restoreButton
      width: 100
      height: 50

      Text {
          anchors.centerIn: parent
          text: "Restore previously purchased content"
      }

      MouseArea {
          anchors.fill: parent
          onClicked: {
              store.restorePurchases()
          }
      }
  }
  \endqml

  Restoring purchases should always be done as a reaction to user input, as it may present a password dialog on some platforms.
  Calling the restorePurchases() method launches the restore process asynchronously. At some point in the future the onPurchaseRestored
  handler will be called if the product has previously been purchased.

  \note While the function behaves as documented on Android, this functionality is technically not needed there. The reason for this
  is that the Android device manages all unlockable purchases with no intervention from the application. If an application is
  uninstalled and reinstalled (or installed on a different device) on Android, then onPurchaseSucceeded will be called for each previously
  purchased, unlockable product when the application starts up.
*/