Class TInAppPurchases

Unit

Declaration

type TInAppPurchases = class(TComponent)

Description

Manage in-app purchases in your game.

Typical usage:

  1. Construct one instance of this class. Or a subclass – it is useful to override some methods of this class for a particular game.

  2. Early (e.g. from TCastleApplication.OnInitialize) call SetAvailableProducts, and wait for OnRefreshedPrices to know the prices about products (in user's local currency).

  3. Query the product information using Product method, and looking at various TInAppProduct properties.

  4. Buy products using Purchase, consume products using Consume, refresh the ownership information using RefreshPurchases.

You need to add a "service" to include the necessary integration code on Android and iOS. For Android, set project type as "integrated" and add the "google_in_app_purchases" service (see https://github.com/castle-engine/castle-engine/wiki/Android-Project-Services-Integrated-with-Castle-Game-Engine ). For iOS, add the "in_app_purchases" service (see https://github.com/castle-engine/castle-engine/wiki/iOS-Services ).

You need to define the products you want sell in the Google Play Developer Console ( https://developer.android.com/distribute/console/index.html ) for Android, or iTunes Connect ( https://itunesconnect.apple.com/ ) for iOS. The names of products you provide to SetAvailableProducts or Product methods must correspond to product names you set on these websites.

Hierarchy

  • TObject
  • TPersistent
  • TComponent
  • TInAppPurchases

Overview

Methods

Protected procedure KnownCompletely; virtual; deprecated 'use RefreshedPrices or RefreshedPurchases';
Protected procedure RefreshedPrices; virtual;
Protected procedure RefreshedPurchases; virtual;
Protected procedure SuccessfullyConsumed(const AProduct: TInAppProduct); virtual;
Protected procedure Owns(const AProduct: TInAppProduct); virtual;
Public constructor Create(AOwner: TComponent); override;
Public destructor Destroy; override;
Public procedure SetAvailableProducts(const Names: array of string);
Public procedure SetAvailableProducts(const Products: array of TAvailableProduct);
Public procedure Purchase(const AProduct: TInAppProduct);
Public procedure Consume(const AProduct: TInAppProduct);
Public function Product(const ProductName: string): TInAppProduct;
Public procedure RefreshPurchases;

Properties

Public property DebugMockupBuying: boolean read FDebugMockupBuying write FDebugMockupBuying default false;
Published property OnRefreshedPrices: TNotifyEvent read FOnRefreshedPrices write FOnRefreshedPrices;
Published property OnRefreshedPurchases: TNotifyEvent read FOnRefreshedPurchases write FOnRefreshedPurchases;

Description

Methods

Protected procedure KnownCompletely; virtual; deprecated 'use RefreshedPrices or RefreshedPurchases';

Warning: this symbol is deprecated: use RefreshedPrices or RefreshedPurchases

Called when the knowledge about what do we own is complete.

Protected procedure RefreshedPrices; virtual;

See OnRefreshedPrices for information when is this called. The default implementation of this method in this class just calls OnRefreshedPrices.

Protected procedure RefreshedPurchases; virtual;

See OnRefreshedPurchases for information when is this called. The default implementation of this method in this class just calls OnRefreshedPurchases.

Protected procedure SuccessfullyConsumed(const AProduct: TInAppProduct); virtual;

Called when the product is successfully consumed, in response to the Consume call.

In this class, this simply sets Product.SuccessfullyConsumed flag to True, and waits for some other code (maybe overridden SuccessfullyConsumed implementation, maybe something else) will handle it and reset the Product.SuccessfullyConsumed flag to False.

Protected procedure Owns(const AProduct: TInAppProduct); virtual;

Called when we know the product is owned, in particular when it's successfully bought.

If the product is not consumable (which means that it can be owned only once, and it's owned forever once bought): Note that this method may be called multiple times, because there are various situations in which we may "gain knowledge" that user owns this item (e.g. each RefreshPurchases call). Write your code to react gracefullly to this, such that calling this method on an already-owned item is handled correctly.

E.g. if you increase some stat (e.g. "gold owned") when user buys a "chest of gold", and "chest of gold" is non-consumable (you can only own it once, and then you just own it forever), then store the fact that you "already increased gold because of the chest ownership" in the user persistent data (see https://castle-engine.io/manual_user_prefs.php). Do not just increase the "gold owned" at every call of this method.

If the product is a consumable, which means it has a one-time use (and should disappear afterwards, until user will buy it again), then:

  1. Call the Consume method once you know the item is owned. You can call Consume directly from the overridden implementation of Owns, this is often the simplest approach.

  2. Actually perform the consumption (bump the player gold, grant extra life and so on) only when the item is successfully consumed. You are notified about this by the SuccessfullyConsumed call (you can override it), or you can watch if the TInAppProduct.SuccessfullyConsumed flag is set.

    Do not give any one-time gain as a response to the Owns call. Always wait for SuccessfullyConsumed call.

    This protects you from the scenario when you're notified that you own the item multiple times (which may happen, since purchases may be resumed asynchronously while other code is executing), and you call Consume twice. The SuccessfullyConsumed will only fire once, if user bought item once.

Public constructor Create(AOwner: TComponent); override;
 
Public destructor Destroy; override;
 
Public procedure SetAvailableProducts(const Names: array of string);

Initialize a list of products for which to query prices from server. The overloaded version with TAvailableProduct allows to provide additional information to the in-app payment system, see TAvailableProduct docs.

Public procedure SetAvailableProducts(const Products: array of TAvailableProduct);
 
Public procedure Purchase(const AProduct: TInAppProduct);

Initiate a purchase of given item.

Public procedure Consume(const AProduct: TInAppProduct);

Initiate a consumption of a consumable item. You should listen on a "successful consumption" (override SuccessfullyConsumed method and/or watch TInAppProduct.SuccessfullyConsumed) until you actually act on the consumption (increase player gold or such).

Public function Product(const ProductName: string): TInAppProduct;

Find product with given name.

Creates and adds new product, if not found (useful in case you asked for a product before information about it arrived from the net, or before you even called SetAvailableProducts with it).

Public procedure RefreshPurchases;

Call to refresh the state of owned (purchased) items from server. This will call Owns on the owned items, and then RefreshedPurchases or OnRefreshedPurchases.

This is necessary to be called explicitly on iOS (for AppStore), as it will ask user to login to AppStore. On Android, this is done automatically at app start, and doesn't ask user anything.

Properties

Public property DebugMockupBuying: boolean read FDebugMockupBuying write FDebugMockupBuying default false;

Purely for debug purposes, mockup buying (pretend that all purchases succeed).

Published property OnRefreshedPrices: TNotifyEvent read FOnRefreshedPrices write FOnRefreshedPrices;

Called when the prices (and other shop-related information) are known about the products. The information is stored inside TInAppProduct instances, e.g. query TInAppProduct.Price, TInAppProduct.Title and so on. Get the TInAppProduct instance by Product method.

This signals that we queried the shop for the product information like TInAppProduct.Price and TInAppProduct.Title and TInAppProduct.Description. This is automatically done always when launching the application, and sometimes later too.

It does not mean that we have queried the ownership status of the products, for this see OnRefreshedPurchases.

See also RefreshedPrices method. Instead of assigning this event, you cal override RefreshedPrices method in descendants.

Published property OnRefreshedPurchases: TNotifyEvent read FOnRefreshedPurchases write FOnRefreshedPurchases;

Called when the ownership status of all products is known. The information is stored inside TInAppProduct.Owns, you can get the TInAppProduct instance using the Product method.

The ownership status is automatically queried when the application starts on Android. On iOS, it must be explicitly invoked using RefreshPurchases (this is a limitation of iOS user-interface around this, so it cannot be hidden / workarounded by us).


Generated by PasDoc 0.15.0.