In-App purchasing demo | Qt 6.2

- Qt 6.2
- In-App purchasing demo
- Qt 6.2.4 Reference Documentation

# In-App purchasing demo

A complete mobile application that demonstrates purchasing in-app products.

#### What is this demo?

This demo is a complete mobile application that demonstrates how it is possible to offer in-app products inside a Qt application, in a cross-platform manner. In order to test the in-app purchase functionality in the example, you must first register the application and its products in the external store. For an introduction on how to do this, see the guides for Google Play and App Store respectively.

#### 3rd party app stores

The in-app products must be registered in the target stores, before they can be queried or purchased in an application. We recommend using the same identifiers for the products in each store, as it simplifies the code to query and purchase the products.

- Registering Products in Google Play
- Registering Products in App Store

#### How does the demo work

The demo is a QML application that registers QML types to access information about in-app products, as well as to request purchases for those products. These are registered in the external store for the target platform

In-app purchasing are added to application by first adding a Store object. In the demo the Store object is created by the MainView component that is loaded on application startup.

     Store {
         id: iapStore
     }

The demo defines a component for displaying a store for purchasing in-app products made available. These products must be first registered with the store object we created above in MainView. There are two products available, the first being a consumable type.

     Product {
         id: product100Vowels
         store: iapStore
         type: Product.Consumable
         identifier: "qt.io.demo.hangman.100vowels"

         onPurchaseSucceeded: {
             console.log(identifier + " purchase successful");
             //Add 100 Vowels
             applicationData.vowelsAvailable += 100;
             transaction.finalize();
             pageStack.pop();
         }

         onPurchaseFailed: {
             console.log(identifier + " purchase failed");
             console.log("reason: "
                         + transaction.failureReason === Transaction.CanceledByUser ? "Canceled" : transaction.errorString);
             transaction.finalize();
         }
     }

This consumable product provides 100 additional vowels to be used when guessing words in the game. When it is successfully purchased, we update the state of the application to include 100 additional vowels. Then we call finalize() on the transaction object to confirm to the platform store that the consumable product has been provided.

The second product is a non-consumable type that will unlock vowels permanently in the future. In addition to updating the application state on purchase, we must make sure to provide a way to restore this purchase on other devices used by the end user. In this case we create a signal handler for onPurchaseRestored.

     Product {
         id: productUnlockVowels
         type: Product.Unlockable
         store: iapStore
         identifier: "qt.io.demo.hangman.unlockvowels"

         onPurchaseSucceeded: {
             console.log(identifier + " purchase successful");
             applicationData.vowelsUnlocked = true;
             transaction.finalize();
             pageStack.pop();
         }

         onPurchaseFailed: {
             console.log(identifier + " purchase failed");
             console.log("reason: "
                         + transaction.failureReason === Transaction.CanceledByUser ? "Canceled" : transaction.errorString);
             transaction.finalize();
         }

         onPurchaseRestored: {
             console.log(identifier + " purchase restored");
             applicationData.vowelsUnlocked = true;
             console.log("timestamp: " + transaction.timestamp);
             transaction.finalize();
             pageStack.pop();
         }
     }

In addition to registering the products, the demo also provide an interface to actually purchase the registered product. The demo defines a custom component called `StoreItem` to display and handle the purchasing interaction.

     Product {
         id: productUnlockVowels
         type: Product.Unlockable
         store: iapStore
         identifier: "qt.io.demo.hangman.unlockvowels"

         onPurchaseSucceeded: {
             console.log(identifier + " purchase successful");
             applicationData.vowelsUnlocked = true;
             transaction.finalize();
             pageStack.pop();
         }

         onPurchaseFailed: {
             console.log(identifier + " purchase failed");
             console.log("reason: "
                         + transaction.failureReason === Transaction.CanceledByUser ? "Canceled" : transaction.errorString);
             transaction.finalize();
         }

         onPurchaseRestored: {
             console.log(identifier + " purchase restored");
             applicationData.vowelsUnlocked = true;
             console.log("timestamp: " + transaction.timestamp);
             transaction.finalize();
             pageStack.pop();
         }
     }

The StoreItem component will display the product data that is queried from the platform's store, and will call the purchase() method on the product when it is clicked by the user.

     Text {
         id: titleText
         text: product.title
         font.bold: true
         anchors.right: priceText.left
         anchors.rightMargin: topLevel.globalMargin
         anchors.top: parent.top
         anchors.topMargin: topLevel.globalMargin
         anchors.left: parent.left
         anchors.leftMargin: topLevel.globalMargin
     }

     Text {
         id: descriptionText
         text: product.description
         anchors.right: priceText.left
         anchors.rightMargin: topLevel.globalMargin
         anchors.left: parent.left
         anchors.leftMargin: topLevel.globalMargin
         anchors.top: titleText.bottom
         anchors.topMargin: topLevel.globalMargin / 2
         wrapMode: Text.WordWrap
     }

     Text {
         id: priceText
         text: product.price
         anchors.right: parent.right
         anchors.rightMargin: topLevel.globalMargin
         anchors.verticalCenter: parent.verticalCenter
     }

     MouseArea {
         anchors.fill: parent
         onClicked: {
             pendingRect.visible = true;
             spinBox.visible = true;
             statusText.text = "Purchasing...";
             storeItem.state = "PURCHASING";
             product.purchase();
         }
         onPressed: {
             storeItem.state = "PRESSED";
         }
         onReleased: {
             storeItem.state = "NORMAL";
         }
     }

If you are planning to use QML in your project with purchasing functionality, check out Getting Started with Qt Purchasing in QML.

Android and iOS use the base classes. From base classes there are derivative classes for android and ios:

- Base Classes
- Demo Android Classes
- Demo iOS Classes

#### In-App purchases

In-app purchases are a way to monetize an application. These purchases are made from inside the application and can include anything from unlocking content to virtual items. The demo uses the system APIs for in-app purchases, which means the purchase process is more familiar to the user, and the information already stored by the platform (such as credit card information) can be used to simplify the purchase process.

#### Licenses and attributions

In regards to deploying the demo on Android see Android GNU C++ Run-time Licensing for more information.

Files:

- demos/hangman/CMakeLists.txt
- demos/hangman/hangman.pro
- demos/hangman/hangmangame.cpp
- demos/hangman/hangmangame.h
- demos/hangman/main.cpp
- demos/hangman/main.qml
- demos/hangman/purchasing/android/androidinappproduct.cpp
- demos/hangman/purchasing/android/androidinappproduct.h
- demos/hangman/purchasing/android/androidinapppurchasebackend.cpp
- demos/hangman/purchasing/android/androidinapppurchasebackend.h
- demos/hangman/purchasing/android/androidinapptransaction.cpp
- demos/hangman/purchasing/android/androidinapptransaction.h
- demos/hangman/purchasing/android/androidjni.cpp
- demos/hangman/purchasing/inapp/inappproduct.cpp
- demos/hangman/purchasing/inapp/inappproduct.h
- demos/hangman/purchasing/inapp/inapppurchasebackend.cpp
- demos/hangman/purchasing/inapp/inapppurchasebackend.h
- demos/hangman/purchasing/inapp/inappstore.cpp
- demos/hangman/purchasing/inapp/inappstore.h
- demos/hangman/purchasing/inapp/inapptransaction.cpp
- demos/hangman/purchasing/inapp/inapptransaction.h
- demos/hangman/purchasing/ios/iosinapppurchasebackend.h
- demos/hangman/purchasing/ios/iosinapppurchaseproduct.h
- demos/hangman/purchasing/ios/iosinapppurchasetransaction.h
- demos/hangman/purchasing/qmltypes/inappproductqmltype.cpp
- demos/hangman/purchasing/qmltypes/inappproductqmltype.h
- demos/hangman/purchasing/qmltypes/inappstoreqmltype.cpp
- demos/hangman/purchasing/qmltypes/inappstoreqmltype.h
- demos/hangman/qml/GameView.qml
- demos/hangman/qml/GuessWordView.qml
- demos/hangman/qml/Hangman.qml
- demos/hangman/qml/HowToView.qml
- demos/hangman/qml/Key.qml
- demos/hangman/qml/Letter.qml
- demos/hangman/qml/LetterSelector.qml
- demos/hangman/qml/MainView.qml
- demos/hangman/qml/PageHeader.qml
- demos/hangman/qml/ScoreItem.qml
- demos/hangman/qml/SimpleButton.qml
- demos/hangman/qml/SplashScreen.qml
- demos/hangman/qml/StoreItem.qml
- demos/hangman/qml/StoreView.qml
- demos/hangman/qml/Word.qml
- demos/hangman/resources.qrc