Library Integration

This section explains the steps to integrate the now.gg Payments SDK with your development environment.

This document features various code samples based on the official now.gg sample apps and games. You can check the in-line references throughout the document to better understand and implement the now.gg Payments SDK resources.


Add SDK Libraries

The first step is to download the Payments SDK libraries and add them to your development environment.

The SDK package contains the Payments SDK files and the SDK billing service.

1. Extract the compressed now.gg Payments SDK file and locate the .aar file in the package:

 billingclient-release.aar

2. Add the following dependency to the build.gradle file of your game:

dependencies {
         implementation fileTree(dir: 'libs', include: ['*.aar'])
 }

Using the Billing Client

Purchase Lifecycle

The Purchase Lifecycle flow for now.gg Payments SDK is as follows:

  • List the available products that the user can buy.
  • Purchase flow initiation for the user to buy the listed in-app products.
  • Processing the purchase:
    • Purchase verification.
    • Delivery of product/content to the user
    • Marking purchase as consumed/delivered to allow re-purchase of the product.

Understanding Some Terms

now.gg Payments SDK makes use of Purchase Tokens and Order IDs to track the products and transactions within your game or App.

Purchase Tokens

  • Purchase Token(s) represent the buyer’s ownership/entitlement of a product.
  • They are associated with a specific product and related product SKU.
  • Purchase Token(s) is only generated after successful in-app purchase by the user.
  • In the case of a one-time purchase product, a new purchase token is generated for every
    transaction.

Order IDs

  • An Order ID is a reference to a financial transaction with the now.gg Billing Service.
  • Order IDs are used as references to track purchases, refunds, or any disputes.
  • Unique Order IDs are created for every financial transaction.

Entitlement

The term entitlement or granting of entitlement is used to signify ‘delivery of in-app product’ to the user after a product purchase.

Error Handling

The errors and responses encountered within your app/game are categorized using Billing Response codes.
Example: A SERVICE_DISCONNECTED error code suggests the connection between the now.gg payments service and your game is disconnected. The solution to this is to reinitialize your app/game to re-establish the connection with now.gg payments service.

1. Create and Initialize a BillingClient

The BillingClient interface acts as the primary communication mechanism between the now.gg Payments SDK and your game/app. It is responsible for providing both synchronous and asynchronous methods for general billing operations.

Flow

BillingClient Creation                 --> Use newBuilder()

 Setup Updates of Purchase              --> Call setListener()

 Receive updates throughout app/game    --> PurchasesUpdatedListener

 Set your APP ID for billing            --> use setAppId(APP_ID)

References

private PurchasesUpdatedListener purchasesUpdatedListener = new PurchasesUpdatedListener() {
    @Override
    public void onPurchasesUpdated(int billingResult, List<Purchase> purchases) {
        // To be implemented in a later section.
    }
 };

 private BillingClient billingClient = BillingClient.newBuilder(activity)
    .setListener(purchasesUpdatedListener)
    .setAppId(APP_ID)
    .build();
private val purchasesUpdatedListener =
    PurchasesUpdatedListener { billingResult, purchases ->
        // To be implemented in a later section.
    }

 private var billingClient = BillingClient.newBuilder(activity)
 .setListener(purchasesUpdatedListener)
 .setAppId(APP_ID)
 .build()

Note: The corresponding APP_ID can be found on the now.gg Developer Portal. The APP_ID will be available only after you have added your app/game within the developer portal.

2. Establish Connection

now.gg Payments service has an asynchronous connection process and requires you to implement a BillingClientStateListener to capture callback on completion of client setup.

  • To establish a connection with now.gg Payments Service, you need to call startConnection().
  • To handle lost connections, you need to define a retry logic. The retry logic implementation will require you to override the callback method onBillingServiceDisconnected().
  • While overriding the callback method onBillingServiceDisconnected(), ensure that your BillingClient is calling the startConnection() method to re-establish connection with now.gg Payments Service.
  • Maintain the connection with the BillingClient, before executing any methods.

Note: You may choose to write your own retry logic. However, we have also provided a retry logic that you may choose to implement.

References

Example

billingClient.startConnection(new BillingClientStateListener() { 
         @Override 
     public void onBillingSetupFinished(int billingResult) { 
             if (billingResult ==  0) { 
                 // The BillingClient is ready. You can query purchases here. 
         } 
     } 
     @Override 
     public void onBillingServiceDisconnected() { 
             // Try to restart the connection on the next request to 
         // Billing SDK by calling the startConnection() method. 
     } 
 });
billingClient.startConnection(object: BillingClientStateListener { 
    override fun onBillingSetupFinished(billingResult: int) { 
         if (billingResult == 0) { 
             // The BillingClient is ready. You can query purchases here. 
         } 
     } 
     override fun onBillingServiceDisconnected() { 
         // Try to restart the connection on the next request to 
         // Billing SDK by calling the startConnection() method. 
     } 
 });

Products and Purchases

This section walks you through the process of querying and listing the available in-app products in your app/game and handling the purchases.

The steps for this flow are:

  1. List Available Products.
  2. Purchase Flow Initiation.
  3. Processing the Purchases.

Before you begin, check that you have:

1. List Available Products

The first step here is to query for available products and list them to your users. To perform a query for in-app product details, you need to call querySkuDetailsAsync(). When you query for SKU details, the now.gg Payments SDK will return localized product information to be displayed to your users.

Note: Before displaying the in-app products to the user, you should query the SKU details, as it returns updated and relevant product information.

SKU Types and Order Strings

Below are the SKUType associated with now.gg Payments SDK:

  • SkuType.SUBS – Subscriptions (coming soon)
  • SkuType.INAPP – in-app purchases

While you call querySkuDetailsAsync(), remember to pass an instance of SkuDetailsParams, which specifies the SKUType along with the product ID that you configured in the now.gg developer portal.

Results

After querying for available products, you will need to assign a listener to capture the results of the Asynchronous operation you passed.

The following example will showcase the implementation of a SkuDetailsResponseListener interface and will allow you to override the onSkuDetailsResponse(), to notify the listener when the query is finished.

References

List<String> skuList = new ArrayList<> (); 
 skuList.add("premium_upgrade"); 
 skuList.add("gas"); 
 SkuDetailsParams.Builder params = SkuDetailsParams.newBuilder(); 
 params.setSkusList(skuList).setType(SkuType.INAPP); 
 billingClient.querySkuDetailsAsync(params.build(), 
     new SkuDetailsResponseListener() { 
             @Override 
         public void onSkuDetailsResponse(int billingResult, 
                 List<SkuDetails> skuDetailsList) { 
                 // Process the result. 
         } 
     });
fun querySkuDetails() { 
 val skuList = ArrayList<String>() 
 skuList.add("premium_upgrade") 
 skuList.add("gas") 
 val params = SkuDetailsParams.newBuilder() 
 params.setSkusList(skuList).setType(SkuType.INAPP) 
    withContext(Dispatchers.IO) { 
            billingClient.querySkuDetailsAsync(params.build()) { billingResult, skuDetailsList -> 
            // Result Processing 
        } 
    } 
 }

More Information

  • A user can re-purchase a consumable item only after the first purchase order has been completed and the product is delivered to the user.
  • The SkuDetails object can be called using various methods to list information about the in-app products.
  • now.gg Payments SDK stores all the query results in a list of SkuDetails object.

2. Purchase Flow Initiation

After you have listed the available products for the user to buy, you are required to initiate the purchase flow from the app/game.

To start the purchase flow, you will need to call the launchBillingFlow() method from the App’s main thread.

Here, the BillingFlowParams object is called for a reference, as it contains relevant details stored within the SkuDetails object. The SkuDetails object is obtained by calling querySkuDetailsAsync().

Creating the BillingFlowParams object

To start the purchase flow, you need to create the BillingFlowParams object using the BillingFlowParams.Builder class. Use the following code snippets as reference:

References:

// An activity reference for billing flow initiation 
 Activity activity = ...; 
      
 // Call querySkuDetailsAsync() to retrieve a value for 'skuDetails'. 
 BillingFlowParams billingFlowParams = BillingFlowParams.newBuilder() 
    .setSkuDetails(skuDetails) 
    .build(); 
 billingClient.launchBillingFlow(activity, billingFlowParams); 
      
     //Result
// An activity reference for billing flow initiation 
 val activity : Activity = ...; 
  
 // Call querySkuDetailsAsync() to retrive a value for 'skuDetails'. 
 val flowParams = BillingFlowParams.newBuilder() 
         .setSkuDetails(skuDetails) 
         .build() 
 billingClient.launchBillingFlow(activity, flowParams)
 //Result

Result Assessment

You can use BillingClient.BillingResponse as a reference for the return response codes.

  • A response code OK (0) indicates a successful launch.
  • A Purchase Screen is displayed by the system after a successful call to launchBillingFlow().
  • now.gg Payments SDK calls onPurchasesUpdated() to communicate the purchase result to a listener that implements the PurchasesUpdatedListener interface.
  • This listener is specified while you initialize the billing client using the setListener() method.

The following example outlines the process to override the onPurchasesUpdated() method:

Note: The onPurchasesUpdated method should be implemented to handle possible response codes.

References:

@Override 
 void onPurchasesUpdated(int billingResult, List<Purchase>) { 
     if (billingResult == 0 && purchases != null) { 
         for (Purchase purchase : purchases) { 
             handlePurchase(purchase); 
         } 
     } else if (billingResult == 1) { 
             // Error Handling - Caused due to user terminating the purchase flow 
     } else { 
             // Error Handling - Any other causes (based on error code) 
     } 
 }
override fun onPurchasesUpdated(billingResult: int, purchases: List<Purchase>?) { 
     if (billingResult == 0 && purchases != null) { 
         for (purchase in purchases) { 
                 handlePurchase(purchase)
         } 
     } else if (billingResult == 1) { 
             // Error Handling - Caused due to user terminating the purchase flow. 
     } else { 
             // Error Handling - Any other causes (based on error code) 
     } 
 }

More Information

  • A Purchase Token is generated after a successful purchase.
  • This purchase token is also a Unique Identifier.
  • This unique identifier represents the in-app purchased product and the corresponding user who made the purchase.
  • An order ID is generated for every subsequent order and can be used for any disputes or refund references with the now.gg Payments Service.
  • A copy of every purchase with the order id and other relevant information is also emailed to the user.

3. Processing the Purchases

This section focuses on processing the purchases. After you have started the purchase flow, you are required to process the purchases in the following manner:

  1. Purchase Verification
  2. Granting Entitlement
  3. Purchase Results

1. Purchase Verification

Verifying the purchase enables you to establish the authenticity of a purchase. now.gg Payments SDK utilizes a public key to verify the in-app purchases.

Verify the purchase with your Public Key

An implementation for verifying purchases using the public key has been illustrated in the demo’s billingManager.java.

  • Open billingManager.java
  • Locate the verifyValidSignature function and then locate verifyPurchase.

By referring to the implementation using the above-mentioned functions in our SDK demo’s billingManager.java, you can implement the purchase verification in your App.

Note:

  • You can generate your public key by following the steps listed here.
  • If your app has a backend server, we recommend that you validate the purchase on your backend server.
  • It is recommended to authenticate every purchase before granting the entitlement of the product to the user.

2. Granting Entitlement

After you have verified the purchase, your App can now grant the entitlement of the purchased product to the user and mark the product as consumed.

To grant the entitlement call the consumeAsync() method. This method will grant the entitlement of a product to the user and make the product available for re-purchase once it has been consumed/delivered to the user.

Using consumeAsync():

  • Include the purchase token with consumeAsync() to update the status of the purchased product toconsumed, allowing the now.gg billing service to make it available for re-purchase.
  • To update the result of the consumption operation, you should pass an object that implements the ConsumeResponseListener interface.
  • When the consumption operation is complete, now.gg Billing Service calls onConsumeResponse(), which you can override.

Important Information:

  • You should keep a check on multiple entitlement grants for the same purchase using purchase tokens. This may occur if the consumption request fails and the object that updates the ConsumeResponseListener interface is not updated.

The following code snippet demonstrates purchase verification and consumption operation:

References:

void handlePurchase(Purchase purchase) {
    // Purchase retrieved from BillingClient#queryPurchases or your PurchasesUpdatedListener.
    Purchase purchase = ...;

    // Verify the purchase.
    // Ensure entitlement was not already granted for this purchaseToken.
    // Grant the entitlement to the user.

    ConsumeResponseListener listener = new ConsumeResponseListener() {
        @Override
        public void onConsumeResponse(int billingResult, String purchaseToken) {
            if (billingResult == 0) {
                // Handle the success of the consume operation.
            }
        }
    };

    billingClient.consumeAsync(purchase.getPurchaseToken(), listener);
}
fun handlePurchase(purchase: Purchase) {
    // Purchase retrieved from BillingClient#queryPurchases or your PurchasesUpdatedListener.
    val purchase: Purchase = ...;

    // Verify the purchase.
    // Ensure entitlement was not already granted for this purchaseToken.
    // Grant the entitlement to the user.


    billingClient.consumeAsync(purchase.getPurchaseToken(), {
        billingResult,
        outToken - >
        if (billingResult == 0) {
            // Handle the success of the consume operation.
        }
    })
}

3. Purchase Results

The PurchasesUpdatedListener provides you with the purchase results. However, in some scenarios, your app/game might not be updated with all the successful purchases a user has made.

Some of these scenarios include:

  • Multiple devices
    In this scenario, the user purchased an item on one device and wants to use it on another device where the purchased product is not updated.
  • Connectivity/Network loss
    The app/game may fail to receive a successful purchase notification from PurchasesUpdatedListener, due to connectivity/network loss.
  • Purchases made outside the App
    In this scenario, the purchases made outside your app/game need to be handled for the user to be able to use them.

To successfully process purchases related to the scenarios listed above:

  •  In your onResume() and onCreate() methods, make sure that your app calls mBillingClient.queryPurchases(SkuType.INAPP).
Getting Unconsumed Purchases

You can use the queryPurchases method to return the list of unconsumed purchases for a user, as illustrated below:

Purchase.PurchasesResult result = mBillingClient.queryPurchases(BillingClient.SkuType.INAPP);
 if (result.getResponseCode() == BillingClient.BillingResponse.OK) {
     List < Purchase > purchases = result.getPurchasesList();
 }
val result = mBillingClient.queryPurchases(BillingClient.SkuType.INAPP)
 if (result.responseCode == BillingClient.BillingResponse.OK) {
     val purchases = result.purchasesList
 }

 

×
Text copied to clipboard
Questions? Please reach out to us at dev-support@now.gg