From 2eff5e431435f2b5be3511823400080d4029a6c1 Mon Sep 17 00:00:00 2001 From: Jani Korteniemi Date: Mon, 26 Jul 2021 13:42:14 +0300 Subject: Add QtPurchasing module as an example under Qt demos QtPurchasing module is deprecated in Qt6. However, the purchasing code is moved as example/demo under qtdoc to demonstrate the use of in-app purchases in Android/iOS. The demo is under demos\hangman. Few fixes done to the original code: * Ported the code to Qt 6. * Removed reinterpret_casts and QQmlListPropertys. * Fixed few QML warnings. * Added documentation * Fixed documentation * Added CMake port * Fixed Cmake for iOS * Modified Fonts in qml file * project name changed from qthangmanpurchasing to hangman Task-number: QTBUG-84776 Pick-to: 6.2 Change-Id: I86051b29d54cfb4a48b310ebc8d538c806fbf8da Reviewed-by: Qt CI Bot Reviewed-by: Nicholas Bennett Reviewed-by: Assam Boudjelthia --- .../demos/hangman/doc/images/qthangman-example.png | Bin 0 -> 41985 bytes .../hangman/doc/images/qthangman-store-example.png | Bin 0 -> 37374 bytes examples/demos/hangman/doc/src/androidclasses.qdoc | 100 ++++++++ examples/demos/hangman/doc/src/appstore.qdoc | 189 ++++++++++++++ examples/demos/hangman/doc/src/baseclass.qdoc | 160 ++++++++++++ .../demos/hangman/doc/src/gettingstarted-qml.qdoc | 275 +++++++++++++++++++++ examples/demos/hangman/doc/src/googleplay.qdoc | 112 +++++++++ examples/demos/hangman/doc/src/iosclasses.qdoc | 92 +++++++ .../hangman/doc/src/qtpurchasing-overview.qdoc | 129 ++++++++++ 9 files changed, 1057 insertions(+) create mode 100644 examples/demos/hangman/doc/images/qthangman-example.png create mode 100644 examples/demos/hangman/doc/images/qthangman-store-example.png create mode 100644 examples/demos/hangman/doc/src/androidclasses.qdoc create mode 100644 examples/demos/hangman/doc/src/appstore.qdoc create mode 100644 examples/demos/hangman/doc/src/baseclass.qdoc create mode 100644 examples/demos/hangman/doc/src/gettingstarted-qml.qdoc create mode 100644 examples/demos/hangman/doc/src/googleplay.qdoc create mode 100644 examples/demos/hangman/doc/src/iosclasses.qdoc create mode 100644 examples/demos/hangman/doc/src/qtpurchasing-overview.qdoc (limited to 'examples/demos/hangman/doc') diff --git a/examples/demos/hangman/doc/images/qthangman-example.png b/examples/demos/hangman/doc/images/qthangman-example.png new file mode 100644 index 000000000..df54b8d4e Binary files /dev/null and b/examples/demos/hangman/doc/images/qthangman-example.png differ diff --git a/examples/demos/hangman/doc/images/qthangman-store-example.png b/examples/demos/hangman/doc/images/qthangman-store-example.png new file mode 100644 index 000000000..99583b520 Binary files /dev/null and b/examples/demos/hangman/doc/images/qthangman-store-example.png differ diff --git a/examples/demos/hangman/doc/src/androidclasses.qdoc b/examples/demos/hangman/doc/src/androidclasses.qdoc new file mode 100644 index 000000000..8e4224438 --- /dev/null +++ b/examples/demos/hangman/doc/src/androidclasses.qdoc @@ -0,0 +1,100 @@ +/**************************************************************************** +** +** Copyright (C) 2021 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-androidclasses.html + \title Demo Android Classes + \brief Android classes are used in the purchasing demo to enable purchasing in Android. + \ingroup qtpurchasing-examples + + \section1 Classes + \table + \row + \li \l AndroidInAppProduct + \li A product registered in the store. + \row + \li \l AndroidInAppTransaction + \li Contains information about a transaction in the external app store. + \row + \li \l AndroidInAppPurchaseBackend + \li Comminucates with external store. + \row + \li \l androidjni.cpp and InAppPurchase.java + \li Communication between Google Play's billing system and C++. + \endtable + + Check out \l {Base Classes} + + \section1 AndroidInAppProduct + + AndroidInAppProduct adds purchase() for initializing purchasing process. + + \section1 AndroidInAppTransaction + + AndroidInAppTransaction is created in the AndroidInAppPurchaseBackend using + purchaseSucceeded(), purchaseFailed() and checkFinalizationStatus(). + + AndroidInAppTransaction adds new parameters and return types. + Class has finalize() function that separates Consumable and Unlockable + products to be either acknowledged or consumed in the InAppPurchase.java. + + \section1 AndroidInAppPurchaseBackend + + AndroidInAppPurchaseBackend makes and receives calls from InAppPurchase.java. + This class is one of the back end components in the application. + + \section2 Initialize + + Shows the products information on the store page. + + \list 1 + \li AndroidInAppPurchaseBackend is called from InAppStore::setupBackend(). + \li At initialization AndroidInAppPurchaseBackend will give \l {https://developer.android.com/reference/android/content/Context} {Context} and + pointer of its self to the Java in the calls constructor and then + initializes the connection to the Google Play store using the initialize() + function. + \li When the connection is successful, androidjni will call registerRedy() which + emits the ready() singnal to InAppStore and starts queryProducts() function to get + the information of the purchasable items. + \li When the query is done, productQueryDone() signal is emitted and + the item's information will be visible on the application's store page. + \endlist + + \section2 Purchasing + + When pressing one of the products on the applications store page a call is routed + through \c AndroidInAppProduct::purchase() to purchaseProduct() function. This then calls + the Java method launchBillingFlow() which opens Goole Plays billing flow to the user. + + \section1 InAppPurchase.java and androidjni.cpp + + AndroidInAppPurchaseBackend makes calls directly to InAppPurchase.java and + receives Java calls from androidjni. The demo application communicates + with Java function using \l QJniObjects. + + \sa \l {https://developer.android.com/google/play/billing/integrate#java}{Integrate the Google Play Billing Library}, \l QJniObjects and \l QJniEnvironment. +*/ diff --git a/examples/demos/hangman/doc/src/appstore.qdoc b/examples/demos/hangman/doc/src/appstore.qdoc new file mode 100644 index 000000000..86d466bb2 --- /dev/null +++ b/examples/demos/hangman/doc/src/appstore.qdoc @@ -0,0 +1,189 @@ +/**************************************************************************** +** +** Copyright (C) 2021 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-appstore.html + \title Registering Products in App Store + \brief A short guide to registering in-app products in the iOS App Store. + + To take advantage of in-app purchasing functionality on iOS, register your + application and all the available products in + \l{https://appstoreconnect.apple.com/login}{App Store Connect}. + This guide provides a brief introduction on how to register an application + and it's in-app products on App Store. + + In-App purchasing can only be tested on the actual hardware for the iOS + platform. For more information refer to the + \l{http://developer.apple.com/in-app-purchase/}{iOS documentation}. + + + \section1 Register a unique app ID + + One of the requirements to support in-app purchases on iOS is to have + a registered unique App ID. This means that it is not possible to use + an App ID that contains a wildcard character. You can check the existing App + IDs and create new ones from the + \l{https://developer.apple.com/account/ios/identifiers/bundle/bundleList.action}{Apple Developer Certificate, Identifiers, and Profiles manager}. + + In the \uicontrol{Identifiers} tab of the + \uicontrol{Developer Certificate, Identifiers, and Profiles} manager, click + the \uicontrol{+} button to create a New App ID. This will open up the page + to register a new iOS App ID. + + Give your App a relevant ID description and prefix. Your App ID Suffix + should be an Explicit App ID type. Enter a unique App ID in the Bundle ID + field. It is recommended to use the com.mycompany.myappname convention for + App ID. Where, the "com.mycompany" is the Internet domain name of the + publisher. + + In the \uicontrol{App Services} area make sure that the + \uicontrol{In-App Purchases} is checked. Click \uicontrol{continue} your to + complete the App ID registration. + + \section1 Create a provisioning profile + + To be able to use your new App ID, generate a new provision profile that + includes the new ID to sign and run your app. Provisioning Profiles are also + managed through the + \uicontrol{Apple Developer Certificate, Identifiers, and Profiles} manager. + + Navigate to the \uicontrol{Provisioning Profiles} tab of the manager and + click the \uicontrol{+} button to create a new Provisioning Profile. Make + sure that the \uicontrol{iOS App Development} is selected and click the + \uicontrol{Continue} button. + + You are now given an option to choose the App ID to use for this profile, + which will be the unique App ID you created in the previous section. Once + again make sure that the App ID does not contain any wildcard characters + (“*”) as it is not be possible to use the In-App Purchasing service with + such an App ID. + + On the next page you will need to select the certificates that will be + distributed with your Provisioning Profile. You would have needed to uploaded + a certificate on your local development machine to the Apple Developer + Certificate, Identifiers, and Profiles manger previously. Generally you will + want to add any certificates of the members of your team who will need to build + your App. + + On the next page you will need to select the devices you will be developing and + testing your app on. You must register your devices to the Apple Developer + Certificate, Identifiers, and Profiles manger previously. The devices you + select here are the only ones capable of running apps signed against this + provisioning profile, so select all the devices you intend use during the + development and testing phase. + + Give your Provisioning Profile a descriptive display name, and click + \uicontrol{Generate} to create the actual profile. When this process is + completed you’ll be given a choice to download the Provisioning Profile. + + Open the downloaded file in XCode to install. Now the next time you plug in + one of the registered devices, your Provisioning Profile should be installed + to it automatically. + + \section1 Register your application + + Before you can register new products available to the in-app purchasing service, + you need to register your application in App Store Connect. App Store Connect is the + place where you register an app when you want to submit it to the Apple iOS + App Store. + + Start by going to \l{https://appstoreconnect.apple.com/login}{App Store Connect} and + logging in. Once logged in open the \uicontrol{My Apps} link that will take you + to \uicontrol{Apps} page. If you have already registered your app here, you can + skip the registration step, otherwise click the plus button and select + \uicontrol{New App} in the top left corner of the page. + + Select iOS App and then proceed to fill out the required information on the + next page. When you get to the \uicontrol{Bundle ID} section select the + unique App ID we created in the previous steps. + + It is likely at this point that you do not have all the necessary details to + complete the information required to register your app. For now, just fill + out the forms with stub data as everything except the \uicontrol{SKU} and + \uicontrol{Version} fields are editable later. + + \section1 Archive and uploading application + + When you build application for iOs device Qt Creator creates XCode project + that will be used for uploading your application to the App Store. Open the + XCode project and go to \c {signing and Capabilities} from your project + properties and make sure that the Apple ID is selected what you use on App + Store Connect. Make Sure that the \c {Bundle Identifier} is the same as that you + created on the \uicontrol{Developer Certificate, Identifiers, and Profiles} page. + + Next select \c {Set the active scheme} from the top bar of the XCode window and + select \c {Generic iOS Device}. Afte that select \c Product on the menu bar and + click \c Archive. On the pop-up window select \c {Distribute App} go through the + wizard and the build will show up to the App Store Connect. + + \section1 Setting up application testing + + From the App Store Connect select your application and go to \TestFlight page. + You should see at least one build of your application in the page. there are two + type of testing groups internal and external. In internal testing group you can + select developer who has access to your application on the App Store Connect. In + external group you can share your application with public link or you can invite + specific people to test your application. + + \section1 Register the products + + Once your app is registered in App Store Connect you will have additional options + available to manage that App. In the \uicontrol{Apps} page of App Sotre + Connect, click the icon representing your app to manage its details. Within this + menu you can select the \uicontrol{Manage In-App Purchases} from list on the right + to register in-app products you wish to offer. + + To register a new product, click the \uicontrol{Plus icon} button in the right + of the "In-App Purchase" header. The first choice you will be given is the type of + in-app purchase you would like to create. + + On the next page, you must fill out the details about your product. The + \uicontrol{Reference Name} field refers to how the product will be + displayed in App Store Connect and in sales reports, but not in the + App Store itself. The \uicontrol{Product ID} field is very important + as it is the unique ID that will be used to query for the product from your + app itself. If possible make this the same ID as the corresponding products + in the other platform’s stores, otherwise you will have to conditional logic + in your app for each platform when specifying product identifiers. + + Select the pricing and availability details for you product next. For the iOS + App Store, pricing is set via a tier system. Each tier represents a price + level in each iOS App Store region. Your end users will be given the actual + price expected for a product in terms of what region their App Store is in. + + In the next section \uicontrol{In-App Purchase Details} you specify the details + for at least one language. When the app requests the product details like + \c title and \c description, they will be provided in the language of their + locale if they are available. Create language details for the regions you + expect to distribute app in. + + Finally, you will need to attach a screenshot that will be used for review + purposes. This again can be a stub for now, but your product will need to + pass the review before it can go live to be sold in your published app. Click + \uicontrol{save} to complete the product registration. +*/ diff --git a/examples/demos/hangman/doc/src/baseclass.qdoc b/examples/demos/hangman/doc/src/baseclass.qdoc new file mode 100644 index 000000000..ef71f6b69 --- /dev/null +++ b/examples/demos/hangman/doc/src/baseclass.qdoc @@ -0,0 +1,160 @@ +/**************************************************************************** +** +** Copyright (C) 2021 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-baseclasses.html + \title Base Classes + \brief Base classes are used in purchasing demo to enable cross-platform for Android and iOS. + \ingroup qtpurchasing-examples + + \section1 Classes + \table + \header + \li Class + \li Description + \row + \li \l InAppProduct + \li A product registered in the store. + \row + \li \l InAppStore + \li Main entry point for managing in-app purchases. + \row + \li \l InAppTransaction + \li Contains information about a transaction in the external app store. + \row + \li \l InAppPurchaseBackend + \li Communicates with the external store. + \endtable + + \section1 InAppProduct + + InAppProduct encapsulates a product in the external store after it has been registered in + InAppStore and confirmed to exist. It has an identifier which matches the identifier of the + product in the external store, it has a price which is retrieved from the external store, + and it has a product type. + + The product type can be \c Consumable or \c Unlockable. Consumable products can be + purchased any number of times as long as each transaction is finalized explicitly by the + application. Unlockable types can only be purchased once. + + InAppProduct has 5 returnable variables \c price, \c title, \c description \c identifier and + \c productType. All return a QString except productType. + + ProductType is an enum type and returns \c 0 if it is Consumable and \c 1 if Unlockable. + \code + enum ProductType + { + Consumable, + Unlockable + }; + \endcode + + Check out the derived classes \l AndroidInAppProduct for Android and \l IosInAppProduct for iOS. + + \section1 InAppStore + + The main entry point for managing in-app purchases. It is the base class for AndroidInAppProduct and + IosInAppProduct. + + InAppStore is used for managing in-app purchases in the application in a cross-platform way. + Depending on the compiler, InAppStore checks what platform is available using \c Macros. + + \code + void InAppStore::setupBackend() + { + #ifdef Q_OS_ANDROID + d->backend = new AndroidInAppPurchaseBackend; + #endif + + #ifdef Q_OS_IOS + d->backend = new IosInAppPurchaseBackend; + #endif + + d->backend->setStore(this); + + ... + \endcode + + \section2 Initializing the store + + Upon going to the store page in the demo, InAppStore connects all signals to related slots in + setupBackend() function. Then uses the registerProduct() function to register product ID and + productType of each product registered in the external store to a QHash registeredProducts. + + Registering a product is asynchronous, and will at some point yield productRegistered() + signals when its found from external store. + + \code + void InAppStore::registerProduct(InAppProduct *product) + { + d->registeredProducts[product->identifier()] = product; + emit productRegistered(product); + } + \endcode + + \section2 Completing a purchase + + Once the items have been successfully registered in the store, The user can purchase them by + pressing on of the products on the apps store page. QML will call product.purchase() + function in AndroidInAppProduct or IosInAppProduct which will open the external store's + purchasing flow. + + When a purchase has been completed regardless of success, the transactionRedy signal will be + sent to \c InAppProductQmlType, to notify QML to start finalize the transaction. + + section2 Restoring purchases + + In the demo unlockable purchases will be saved on the apps storage. By clearing the storage + the user will lose the unlockable purchase and it cannot be purchased again, as according to + the external store it is already owned. + + You can use the \c{restore purchases} button in the apps store page to restore your unlockable purchases. + The restore purchases button calls the restorePurchases() function and will check the external store for already owned + purchases. It emits the transactionRedy() signal to finalize and restore the purchase. + + InAppStore has no derived classes. + + \section1 InAppTransaction + + InAppTransaction contains information about a transaction in the external app store and is + usually provided as a result of calling InAppProduct::purchase(). When the purchase flow has + been completed by the user (confirming the purchase, for instance by entering their password), + the InAppStore instance containing the product will emit a InAppStore::transactionReady() + signal with data about the transaction. + + The status() function provides information on if the transaction was successful or not. If it was + successful, then the application should take appropriate action. When the necessary action has + been performed, finalize() should be called. The finalize() function should be called regardless + of the status of the transaction. + + Check out the derived classes \l {AndroidInAppTransaction}{AndroidInAppTransaction} for android and \l {IosInAppTransaction}{IosInAppTransaction} for iOS. + + \section1 InAppPurchaseBackend + + InAppPurchaseBackend is used to create derived classs for + AndroidInAppPurchaseBackend and IosInAppPurchaseBackend +*/ diff --git a/examples/demos/hangman/doc/src/gettingstarted-qml.qdoc b/examples/demos/hangman/doc/src/gettingstarted-qml.qdoc new file mode 100644 index 000000000..63d6f1629 --- /dev/null +++ b/examples/demos/hangman/doc/src/gettingstarted-qml.qdoc @@ -0,0 +1,275 @@ +/**************************************************************************** +** +** Copyright (C) 2021 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 + + Register and import your QML types. The QML types can be imported into your + application for example using the following import statement: + + \qml \QtMinorVersion + import com.mycompany.myappname + \endqml + + And by adding following statements in the \c .pro file to link against defined QML types: + + \code + CONFIG += qmltypes + QML_IMPORT_NAME = com.mycompany.myappname + QML_IMPORT_MAJOR_VERSION = 1 + \endcode + + For more information check out \l{https://doc.qt.io/qt-5/qtqml-cppintegration-definetypes.html}{Defining QML Types from C++}. + + \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. +*/ + diff --git a/examples/demos/hangman/doc/src/googleplay.qdoc b/examples/demos/hangman/doc/src/googleplay.qdoc new file mode 100644 index 000000000..83b0a1168 --- /dev/null +++ b/examples/demos/hangman/doc/src/googleplay.qdoc @@ -0,0 +1,112 @@ +/**************************************************************************** +** +** Copyright (C) 2021 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-googleplay.html + \title Registering Products in Google Play + \brief A short guide to registering in-app products in Google Play Store. + + The Google Play market place allows you to register your application, as well + as the in-app products you want to make available to it, without publishing + it. The following \l{https://developer.android.com/studio/publish}{this guide} gives a brief introduction on uploading your + application to Google Play and registering products. + + \section1 Preparing your application for submission + + Before you can upload your application to Google Play, you must prepare it + for submission. + + \section2 Adding a Manifest XML + + The default \c AndroidManifest.xml generated for applications by Qt is + suitable for development testing, but cannot be used when submitting the + application to Google Play. + + Create your own manifest by clicking the + \uicontrol{Create Templates} button in Qt Creator. You can find the + button under \uicontrol{Projects} > \uicontrol{Build} tab. Expand + \uicontrol{Build Android APK} to see it. + + Once the manifest is added to your project, you can modify it. The most + important parts are the \c{application name} and the \c{package name}. The + package name must be unique, and it is recommended to follow the + \b {com.mycompany.myappname} naming convention. The "com.mycompany" + namespace is based on the internet domain ownership to avoid naming + collisions with other applications. + + Other important parts of the manifest include the \c{versionCode}, which must + be incremented every time you upload a new version of the application. Other + properties will decide how your application package + is presented in the store listing, such as the \c{application name} and the \c{version name}. + + For more information on the \c AndroidManifest.xml, see the + \l{http://developer.android.com/guide/topics/manifest/manifest-element.html}{Android documentation}. + + For more information, refer to the + \l{https://doc.qt.io/qt-5/android-3rdparty-libs.html}{Third-party Android Libraries}. + + \section2 Signing the application + + Qt uses the default debug key to sign your application to enable running the + application on a device. Same key cannot be used to sign the Android Application Bundles + that is meant to be published on Google Play. + + See \l{https://doc.qt.io/qtcreator/creator-deploying-android.html#signing-android-packages}{Signing Android Packages} + + \section1 Registering your application + + Once the application is prepared for publishing, you can create a listing for + it in Google Play. + + The first step is to get a publisher account, if you do not already have one. + Go to \l{https://play.google.com/apps/publish/}{the Google Play developer console}, + log in with the Google account of your choice, and follow the steps as + directed. + + When you have set up your account, click on \uicontrol{Add new application} + in Google Play's developer console. + + Fill out as much information as you want in the store listing, and also the + \uicontrol{Pricing and distribution} page. + + \section2 Publishing your application + + In order to test in-app purchases in your application, you first have to + publish it. + + See \l{https://developer.android.com/studio/publish}{Publish your app} + + \section2 Adding in-app products + + In order to access in-app products from your application, you must register + them in Google Play. + + See \l{https://developer.android.com/google/play/billing/getting-ready#products}{Create and configure your products} + +*/ + diff --git a/examples/demos/hangman/doc/src/iosclasses.qdoc b/examples/demos/hangman/doc/src/iosclasses.qdoc new file mode 100644 index 000000000..f717352ed --- /dev/null +++ b/examples/demos/hangman/doc/src/iosclasses.qdoc @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2021 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-iosclasses.html + \title Demo iOS Classes + \brief IOS classes are used in the purchasing demo to enable purchasing in iOS. + \ingroup qtpurchasing-examples + + \section1 Classes + \table + \row + \li \l IosInAppPurchaseProduct + \li A product registered in the store. + \row + \li \l IosInAppPurchaseTransaction + \li Contains information about a transaction in the external app store. + \row + \li \l IosInAppPurchaseBackend + \li Comminucates with external store. + \endtable + + Check out \l {Base Classes} which include InAppProduct, InAppStore, + InAppTransaction and InAppPurchaseBackend + + \section1 IosInAppPurchaseProduct + + IosInAppPurchaseProduct adds purchase() for initializing purchasing process. + + \section1 IosInAppPurchaseTransaction + + IosInAppPurchaseTransaction adds new parameters and return types. + Transaction error handling is implemented on IosInAppPurchaseTransaction's + constructor. The class has the finalize() function that finalizes the transaction. + + \section1 IosInAppPurchaseBackend + + IosInAppPurchaseBackend uses \b Objective-C language to communicate with the App + Store. + + \section2 Initializing the products + + This class shows the product's information on the store page. + + \list 1 + \li IosInAppPurchaseBackend is called from InAppStore::setupBackend(). + \li At initialization IosInAppPurchaseBackend creates InAppPurchaseManager with + Objective-C. + \li InAppStore::registerProduct(productType, &identifier) function is called and + queryProduct() is executed in the back end. + \li Objective-C function requestProductData:() is called and will make \l{https://developer.apple.com/documentation/storekit/skproductsrequest}{SKProductRequest}. + \li After SKProductRequest is finished and product objects has been + created in Objective-C productsRequest:(), products will be registered + by the IosInAppPurchaseBackend::registerProduct() function. + \li Signal productQueryDone() will be emitted and the item's information will be + visible on the application's store page. + \endlist + + \section2 Purchasing process + + \list 1 + \li The user presses one of the products on the applications store page. + \li \c IosInAppPurchaseProduct::purchase() function is called and payment is added to + the \c SKPaymentQueue in the Objective-C function paymentQueue:() in + IosInAppPurchaseBackend. + \li Purchase confirmation pop-up is launched for the user. + \endlist +*/ diff --git a/examples/demos/hangman/doc/src/qtpurchasing-overview.qdoc b/examples/demos/hangman/doc/src/qtpurchasing-overview.qdoc new file mode 100644 index 000000000..33790c8b2 --- /dev/null +++ b/examples/demos/hangman/doc/src/qtpurchasing-overview.qdoc @@ -0,0 +1,129 @@ +/**************************************************************************** +** +** Copyright (C) 2021 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$ +** +****************************************************************************/ + +/*! + \example demos/hangman + \title In-App purchasing demo + \brief A complete mobile application that demonstrates purchasing in-app products. + \ingroup qtpurchasing-examples + \ingroup android-examples + + + \section1 What is this demo? + \image qthangman-example.png + + 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 + \l{Registering Products in Google Play}{Google Play} and + \l{Registering Products in App Store}{App Store} respectively. + + \section1 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. + + \list + \li \l{Registering Products in Google Play} + \li \l{Registering Products in App Store} + \endlist + + \section1 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. + \snippet demos/hangman/qml/MainView.qml 0 + + 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. + + \snippet demos/hangman/qml/StoreView.qml 0 + + 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. + + \snippet demos/hangman/qml/StoreView.qml 1 + + \image qthangman-store-example.png + + 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 \c StoreItem to display and handle the purchasing interaction. + + \snippet demos/hangman/qml/StoreView.qml 1 + + 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. + + \snippet demos/hangman/qml/StoreItem.qml 0 + + If you are planning to use QML in your project with purchasing functionality, + check out + \l{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: + + \list + \li \l{Base Classes} + \li \l{Demo Android Classes} + \li \l{Demo iOS Classes} + \endlist + + \section1 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. + + \section1 Licenses and attributions + + In regards to deploying the demo on Android see + \l Android GNU C++ Run-time Licensing for more information. +*/ -- cgit v1.2.3