Product QML Type

A product for in-app purchasing. More...

Import Statement: import QtPurchasing 1.14
Since: QtPurchasing 1.0

Properties

Signals

Methods

Detailed Description

Product contains information about a product in the external market place. Once the product's identifier and type are set, the product will be queried from the external market place. Properties such as price will then be set, and it will be possible to purchase the product. The status property holds information on the registration process.

Note: It is not possible to change the identifier and type once they have both been set and the product has been registered.

Property Documentation

description : string

This property holds the description of the product once it has been successfully queried from the external market place. The title is localized if the external market place has defined a description in the current users locale.


identifier : string

This property holds the identifier of the product in the external market place. It must match the identifier used to register the product externally before-hand.

When both the identifier and type is set, the product is queried from the external market place, and its other properties are updated asynchronously. At this point, the identifier and type can no longer be changed.

The following example queries an unlockable product named "myUnlockableProduct" from the external market place.

Store {
    Product {
      identifier: "myUnlockableProduct"
      type: Product.Unlockable

      // ...
    }
}

price : string

This property holds the price of the product once it has been successfully queried from the external market place. The price is a string consisting of both currency and value, and is usually localized to the current user.

For example, the following example displays the price of the unlockable product named "myUnlockableProduct":

Store {
    Product {
        id: myUnlockableProduct
        identifier: "myUnlockableProduct"
        type: Product.Unlockable

        // ...
    }
}

Text {
    text: myUnlockableProduct.status === Product.Registered
          ? "Price is " + myUnlockableProduct.price
          : "Price unknown at the moment"
}

When run in a Norwegian locale, this code could for instance display "Price is kr 6,00" for a one-dollar product.


status : enumeration

This property holds the current status of the product in the registration sequence.

  • Product.Uninitialized - This is initial status, before the identifier property has been set.
  • Product.PendingRegistration - Indicates that the product is currently being queried from the external market place. The product gets this status when its identifier is set.
  • Product.Registered - Indicates that the product was successfully found in the external market place. Its price can now be queried and the product can be purchased.
  • Product.Unknown - The product could not be found in the external market place. This could for example be due to misspelling the product identifier.
Store {
    Product {
        identifier: "myConsumableProduct"
        type: Product.Consumable
        onStatusChanged: {
            switch (status) {
            case Product.PendingRegistration: console.debug("Registering " + identifier); break
            case Product.Registered: console.debug(identifier + " registered with price " + price); break
            case Product.Unknown: console.debug(identifier + " was not found in the market place"); break
            }
        }

        // ...
    }
}

store : object

This property holds the store containing the product. When the product is created as a child of the store, this is set automatically to the parent, as in the following example:

Store {
    Product {
      // No need to set the store explicitly here, as it will automatically be
      // bound to the parent
      identifier: "myConsumableProduct"
      type: Product.Consumable
    }
    Product {
      // No need to set the store explicitly here, as it will automatically be
      // bound to the parent
      identifier: "myUnlockableProduct"
      type: Product.Unlockable
    }
}

However, in some advanced use cases, for example when products are created based on a model, it's also possible to create the product anywhere in the QML document and set the store explicitly, like in the following example:

ListModel {
    id: productModel
    ListElement {
        productIdentifier: "myConsumableProduct"
        productType: Product.Consumable
    }
    ListElement {
        productIdentifier: "myUnlockableProduct"
        productType: Product.Unlockable
    }
}

Store {
    id: myStore
}

Instantiator {
    model: productModel
    delegate: Product {
                    identifier: productIdentifier
                    type: productType
                    store: myStore
              }
}

title : string

This property holds the title of the product once it has been successfully queried from the external market place. The title is localized if the external market place has defined a title in the current users locale.


type : string

This property holds the type of the product in the external market place.

It can hold one of the following values:

  • Product.Consumable The product is consumable and can be purchased more than once by the same user, granted that the transaction for the previous purchase has been finalized.
  • Product.Unlockable The product can only be purchased once per user. If the application is uninstalled and reinstalled on the device (or installed on a new device by the same user), purchases of unlockable products can be restored using the store's restorePurchases() method.

When both the identifier and type is set, the product is queried from the external market place, and its other properties are updated asynchronously. At this point, the identifier and type can no longer be changed.

The following example queries an unlockable product named "myUnlockableProduct" from the external market place.

Store {
    Product {
      identifier: "myUnlockableProduct"
      type: Product.Unlockable

      // ...
    }
}

Signal Documentation

onPurchaseFailed(transaction)

This handler is called when a purchase was requested for a given product, but the purchase failed. This will typically happen if the application calls purchase() on a product, and the user subsequently cancels the purchase. It could also happen under other circumstances, for example if there is no suitable network connection.

All products should have an onPurchaseFailed handler.

After a proper reaction is taken, the finalize() function should be called on the transaction object. If this is not done, the handler may be called again the next time the product is registered.

The following example reacts to a failed purchase attempt by calling a custom function to display a message to the user.

Store {
    Product {
        id: myConsumableProduct
        identifier: "myConsumableProduct"
        type: Product.Consumable

        onPurchaseFailed: {
            myDisplayHelper.message("Product was not purchased. You have not been charged.")
            transaction.finalize()
        }

        // ...
    }
}

onPurchaseRestored(transaction)

This handler is called when a previously purchased unlockable product is restored. This can happen when the restorePurchases() function in the current Store is called. The onPurchaseRestored handler will then be called for each unlockable product which has previously been purchased by the user.

Applications which uses the restorePurchases() function should include this handler in all unlockable products. In the handler, the application should make sure information about the purchase is stored and call finalize() on the transaction object if the information has been successfully stored (or has been verified to already be stored).

The following example calls a custom function which either saves the information about the purchase or verifies that it is already saved. When the data has been verified, it finalizes the transaction. If it could not be verified, it calls another custom function to display an error message to the user. If the transaction is not finalized, the handler will be called again for the same transaction the next time the product is registered (on application start-up).

Store {
    Product {
        id: myUnlockableProduct
        identifier: "myUnlockableProduct"
        type: Product.Unlockable

        onPurchaseRestored: {
            if (myStorage.savePurchaseInformation(identifier)) {
                transaction.finalize()
            } else {
                myDisplayHelper.message("Failed to store purchase information. Is there available storage?")
            }
        }

        // ...
    }
}

onPurchaseSucceeded(transaction)

This handler is called when a product has been purchased successfully. It is triggered when the application has called purchase() on the product and the user has subsequently confirmed the purchase, for example by entering their password.

All products should have a handler for onPurchaseSucceeded. This handler should in turn save information about the purchased product and when the information has been stored and verified, it should call finalize() on the transaction object.

The handler should support being called multiple times for the same purchase. For example, the application execution might by accident be interrupted after saving the purchase information, but before finalizing the transaction. In this case, the handler should verify that the information is already stored in the persistent storage and then finalize the transaction.

The following example attempts to store the purchase state of a consumable product using a custom made function. It only finalizes the transaction if saving the data was successful. Otherwise, it calls another custom function to display an error message to the user.

Store {
    Product {
        id: myConsumableProduct
        identifier: "myConsumableProduct"
        type: Product.Consumable

        onPurchaseSucceeded: {
            if (myStorage.savePurchaseInformation(identifier)) {
                transaction.finalize()
            } else {
                myDisplayHelper.message("Failed to store purchase information. Is there available storage?")
            }
        }

        // ...
    }
}

If the transaction is not finalized, the onPurchaseSucceeded handler will be called again the next time the product is registered (on application startup.) This means that if saving the information failed, the user will have the opportunity of rectifying the problem (for example by deleting something else to make space for the data) and the transaction will be completed once they restart the application and the problem has been solved.

Note: A purchased, consumable product can not be purchased again until its previous transaction is finalized.


Method Documentation

purchase()

Launches the purchasing process for this product. The purchasing process is asynchronous. When it completes, either the onPurchaseSucceeded or the onPurchaseFailed handler in the object will be called with the resulting transaction.


resetStatus()

Resets the status of this product and retries querying it from the external market place.

This method can be used when querying the product failed for some reason (such as network timeouts).

This method was introduced in QtPurchasing 1.0.2.


© 2020 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.