Mobile Development 23 min read

Overview and Detailed Design of the Android Checkout In‑App Billing Library

The Android Checkout library wraps Google Play’s In‑App Billing API, providing a streamlined, lifecycle‑aware interface that handles service binding, request queuing, caching, purchase verification, and pagination, while exposing core classes such as Billing, Request, Checkout, Inventory, and configuration to simplify integration despite added synchronization overhead.

37 Interactive Technology Team
37 Interactive Technology Team
37 Interactive Technology Team
Overview and Detailed Design of the Android Checkout In‑App Billing Library

1. Function Introduction

Checkout is a wrapper library for Android In‑App Billing API (v3+). The In‑App Billing service provided by Google Play allows apps to sell digital content such as downloadable media, virtual items, subscriptions, and premium features directly inside the app.

The main goal of Checkout is to make the integration of in‑app products as simple and direct as possible, so developers can focus on their app logic instead of dealing with the tedious billing API.

GitHub address: https://github.com/serso/android-checkout

1.2 Problems Solved by Checkout

How to cancel all billing requests when an Activity is destroyed?

How to query purchase information in the background?

How to verify a purchase?

How to use continuationToken to load more purchased items (the API returns only 20 items per request)?

How to add a minimal sample code for implementing consumable purchases?

1.3 Checkout Flow

Checkout flow diagram
Checkout flow diagram

2. Overall Design

2.1 Overall Design Diagram

Overall design diagram
Overall design diagram

2.2 Core Class Concepts

Billing: The core class that implements Android's Billing API. It is responsible for:

Establishing and disconnecting the Billing Service connection

Executing billing requests

Caching request results

Creating Checkout objects

Request: Represents a billing request entity. Concrete subclasses include BillingSupportedRequest, GetPurchaseHistoryRequest, GetPurchasesRequest, ChangePurchaseRequest, ConsumePurchaseRequest, GetSkuDetailsRequest, PurchaseRequest, each representing a specific operation.

OnConnectedServiceRunnable: Wrapper for Request implementing RequestRunnable. Its core method is run() which checks cache, service state, and then starts the request.

Checkout: Helper class that maintains a Billing instance. It must be bound to the lifecycle of an Activity/Fragment/Service. Subclasses such as FragmentCheckout, ActivityCheckout, and CustomUiCheckout provide concrete implementations.

PendingRequests: Holds a list of RequestRunnable objects and executes them sequentially.

Requests: Implements BillingRequests interface and forwards calls to the underlying Billing instance.

Configuration: Interface for providing public key, cache, purchase verifier, etc.

Cache: Interface for storing and retrieving request results. Implementations include MapCache, ConcurrentCache, SafeCache.

ServiceConnector: Handles binding and unbinding to the Google Play billing service. Default implementation is DefaultServiceConnector.

Purchase: Represents a purchase record with fields such as sku, orderId, packageName, time, payload, token, state, autoRenewing, data, and signature.

Purchases: Holds a list of Purchase objects and a continuation token for pagination.

PurchaseFlow: Manages the whole purchase lifecycle from request to completion, implementing CancellableRequestListener.

Inventory: Loads product, SKU, and purchase information. Implementations include CheckoutInventory, FallingBackInventory, and RobotmediaInventory.

3. Request Flow Diagram

Request flow diagram
Request flow diagram

4. Detailed Design

4.1 UML Class Relationship Diagram

UML diagram
UML diagram

4.2 Core Class Analysis

4.2.1 Checkout.java

Checkout is a utility class that wraps the Billing flow and delegates to Inventory. It must be created with a non‑abstract subclass such as FragmentCheckout, ActivityCheckout, or CustomUiCheckout. The stop() method should be called in onDestroy() to cancel pending requests and unbind the service.

public static UiCheckout forUi(@Nonnull IntentStarter intentStarter, @Nonnull Object tag, @Nonnull Billing billing);
public static UiCheckout forFragment(@Nonnull Fragment fragment, @Nonnull Billing billing);
public static ActivityCheckout forActivity(@Nonnull Activity activity, @Nonnull Billing billing);
public static Checkout forService(@Nonnull Service service, @Nonnull Billing billing);

4.2.2 Request.java

Abstract class defining the contract for billing requests. Subclasses must implement:

abstract void start(@Nonnull IInAppBillingService service, @Nonnull String packageName) throws RemoteException, RequestException;
abstract String getCacheKey();

4.2.3 OnConnectedServiceRunnable

Implements RequestRunnable and adds cache checking and error handling. Core method:

public boolean run() {
    final Request localRequest = getRequest();
    if (localRequest == null) {
        // request was cancelled
        return true;
    }
    if (checkCache(localRequest)) return true;
    // check service state and execute request
    ...
}

4.2.4 PendingRequests

Maintains a list of RequestRunnable objects and executes them sequentially.

4.2.5 Requests

Implements BillingRequests and forwards calls to the underlying Billing instance.

4.2.6 Configuration

Provides methods such as String getPublicKey();, Cache getCache();, PurchaseVerifier getPurchaseVerifier();, and boolean isAutoConnect();.

4.2.7‑4.2.15 (Various cache, connector, and service classes) – each implements thread‑safe wrappers or service binding logic.

4.2.14 Billing.java

Core class that holds references to configuration, cache, pending requests, request interface, service connection, state machine, and executors. It manages the connection lifecycle with states INITIAL, CONNECTING, CONNECTED, DISCONNECTING, DISCONNECTED, FAILED.

void setState(@Nonnull State newState) {
    synchronized (mLock) {
        if (mState == newState) return;
        // validate state transition
        mState = newState;
        switch (mState) {
            case CONNECTED:
                executePendingRequests();
                break;
            case FAILED:
                mMainThread.execute(() -> mPendingRequests.onConnectionFailed());
                break;
            // other cases omitted for brevity
        }
    }
}

4.2.15‑4.2.18 Inventory and related classes

Inventory loads product and purchase data. loadInventory() creates an Inventory instance (either CheckoutInventory or FallingBackInventory) and starts asynchronous loading.

public Inventory loadInventory(@Nonnull Inventory.Request request, @Nonnull Inventory.Callback callback) {
    final Inventory inventory = makeInventory();
    inventory.load(request, callback);
    return inventory;
}

5. Summary

Advantages

Provides a simple API for integrating Google Play In‑App Billing.

Implements caching to avoid redundant cross‑process calls.

Manages requests through a queue, simplifying request lifecycle handling.

Disadvantages

Heavy use of synchronization may impact performance in highly concurrent scenarios.

Performance impact illustration
Performance impact illustration

Enjoyed the article? Thank you for your support!

QR code for donation
QR code for donation
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaMobile DevelopmentAndroidCheckout LibraryIn-App Billing
37 Interactive Technology Team
Written by

37 Interactive Technology Team

37 Interactive Technology Center

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.