Library for Android In-App Billing (Version 3+)

Overview

Checkout (Android In-App Billing Library)

Description

Checkout is an implementation of Android In-App Billing API (v3+). Its main goal is to make integration of in-app products as simple and straightforward as possible: developers should not spend much time on implementing boring In-App Billing API but should focus on more important things - their apps. With this in mind, the library was designed to be fast, flexible and secure.

Current version: 1.2.2

Why?

Checkout solves common problems that developers face while working with billing on Android, such as:

  • How to cancel all billing requests when Activity is destroyed?
  • How to query purchase information in the background? See also Querying for Items Available for Purchase
  • How to verify a purchase? See also Security And Design
  • How to load all the purchases using continuationToken or SKU details (one request is limited by 20 items)?
  • How to add billing with a minimum amount of boilerplate code?

Checkout can be used with any dependency injection framework or without it. It has a clear distinction of a functionality available in different contexts: purchase can be done only from Activity while SKU information can be loaded in Service or Application. Moreover, it has a good test coverage and is continuously build on Travis CI: Build Status

Getting started

Setup

  • Gradle/Android Studio in build.gradle:
implementation 'org.solovyev.android:checkout:1.2.2'

Note: if you get the following warning

Conflict with dependency 'com.google.code.findbugs:jsr305'. Resolved versions for app (a.b.c) and test app (x.y.z) differ.

you should change the dependencies of com.android.support.test.espresso:espresso-core to

androidTestImplementation('com.android.support.test.espresso:espresso-core:x.y.z', {
    // use version of jsr305 provided by Checkout
    exclude group: 'com.google.code.findbugs', module: 'jsr305'
})

See Android Studio and Gradle documentation for details.

  • Maven in pom.xml:
<dependency>
    <groupId>org.solovyev.android</groupId>
    <artifactId>checkout</artifactId>
    <version>1.2.2</version>
    <type>aar</type>
</dependency>
  • Download sources from github and either copy them to your project or import them as a project dependency
  • Download artifacts from the repository

Permissions

In-app billing requires com.android.vending.BILLING permission to be set in the app. This permission is automatically added to your app's AndroidManifest.xml by Gradle. You can declare this permission explicitly by adding the following line to the AndroidManifest.xml:

<uses-permission android:name="com.android.vending.BILLING" />

Tutorial

A tutorial for the sample app is available on Medium. Take a look if you prefer step-by-step guides over documentation.

Example

Say there is an app that contains one in-app product with "sku_01" id. Then Application class might look like this:

public class MyApplication extends Application {

    private static MyApplication sInstance;

    private final Billing mBilling = new Billing(this, new Billing.DefaultConfiguration() {
        @Override
        public String getPublicKey() {
            return "Your public key, don't forget about encryption";
        }
    });

    public MyApplication() {
        sInstance = this;
    }

    public static MyApplication get() {
        return sInstance;
    }

    public Billing getBilling() {
        return mBilling;
    }
}

And Activity class like this:

public class MyActivity extends Activity implements View.OnClickListener {

    private class PurchaseListener extends EmptyRequestListener<Purchase> {
        @Override
        public void onSuccess(Purchase purchase) {
           // here you can process the loaded purchase
        }
        
        @Override
        public void onError(int response, Exception e) {
            // handle errors here
        }
    }

    private class InventoryCallback implements Inventory.Callback {
        @Override
        public void onLoaded(Inventory.Products products) {
            // your code here
        }
    }

    private final ActivityCheckout mCheckout = Checkout.forActivity(this, MyApplication.get().getBilling());
    private Inventory mInventory;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mCheckout.start();

        mCheckout.createPurchaseFlow(new PurchaseListener());

        mInventory = mCheckout.makeInventory();
        mInventory.load(Inventory.Request.create()
                .loadAllPurchases()
                .loadSkus(ProductTypes.IN_APP, "sku_01"), new InventoryCallback());
    }

    @Override
    protected void onDestroy() {
        mCheckout.stop();
        super.onDestroy();
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        mCheckout.onActivityResult(requestCode, resultCode, data);
    }

    @Override
    public void onClick(View v) {
        mCheckout.whenReady(new Checkout.EmptyListener() {
            @Override
            public void onReady(BillingRequests requests) {
                requests.purchase(ProductTypes.IN_APP, "sku_01", null, mCheckout.getPurchaseFlow());
            }
        });
    }
}

Advanced usage

Samples

A sample app is available on Google Play (source code). There is also a tutorial for it on Medium.

Building from the sources

Checkout is built by Gradle. The project structure and build procedure are standard for Android libraries. An environmental variable ANDROID_HOME must be set before building and should point to Android SDK installation folder (f.e. /opt/android/sdk). Please refer to Gradle User Guide for more information about the building.

Classes overview

Checkout contains three main classes: Billing, Checkout and Inventory.

Billing is a core class of Checkout's implementation of the billing API. It is responsible for:

Only one instance of Billing should be used in the app in order to avoid multiple connections to the billing service. Though this class might be used directly it's easier to work with Checkout instead.

Checkout is a middle tier of the library. It uses Billing in a certain context, e.g. in Application, Activity or Service, checks whether billing is supported and executes the requests. ActivityCheckout is a subclass capable of purchasing items.

Inventory loads information about products, SKUs and purchases. Its lifecycle is bound to the lifecycle of Checkout in which it was created.

Purchase verification

By default, Checkout uses simple purchase verification algorithm (see DefaultPurchaseVerifier). As explained in Android documentation it's better to verify purchases on a remote server. Checkout allows you to provide your own PurchaseVerifier via Billing.Configuration#getPurchaseVerifier. BasePurchaseVerifier can be used as a base class for purchase verifiers that should be executed on a background thread.

Proguard

Library's proguard rules are automatically added to the app project by Gradle. You can declare them explicitly by copying the contents of proguard-rules.txt to your proguard configuration.

License

Copyright 2016 serso aka se.solovyev

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

Comments
  • Validate Purchases

    Validate Purchases

    Hello,

    Thanks for the library but I don't understand how to validate purchases. I have been looking at https://github.com/serso/android-checkout/issues/12 it is rather confusing. I don't understand when things are written in a cryptic way such as ActivityCheckout#createPurchaseFlow(RequestListener

    It is not obvious to me where to find these methods, how to override, where to override etc.

    I know how to send json to my server and back. Please can you give some actual code to do the validation and where to put the code, which object etc and explain.

    Thanks

    opened by tomrum 49
  • PurchaseListener not called

    PurchaseListener not called

    Hi, I already succeed buy in_app item. But, why PurchaseListener not called? And then, when I calledmCheckout.loadInventory(), product in_app still empty.

    mCheckout.loadInventory(Inventory.Request.create().loadAllPurchases(), products ->{
               final Inventory.Product product = products.get(ProductTypes.IN_APP);
               if (!product.supported) {
                   // billing is not supported, user can't purchase anything. Don't show ads in this
                   // case
                   showNativeAds();
                   Toast.makeText(this, "not supported", Toast.LENGTH_SHORT).show();
                   return;
               }
               if (product.isPurchased(SKU_REMOVE_AD)) {
                   Toast.makeText(this, "Purchased", Toast.LENGTH_SHORT).show();
                   return;
               }
               // ALWAYS GO TO HERE
               Toast.makeText(this, "Not purchased", Toast.LENGTH_SHORT).show();  
               showNativeAds();
    });
    

    When, I try call mCheckout.startPurchaseFlow() again, it has no response.

    help wanted question 
    opened by willyantows 32
  • onLoaded called, list of Products (sometimes) empty

    onLoaded called, list of Products (sometimes) empty

    First of all: thanks for this great library. I encounter the following situation: in some situations the onLoaded is called but the list of products is empty. Note that this does not happen in all situation: I only get an exception report from a small number of users. What could be causing this? I assumed that in case of onLoaded being called, there would always be a complete inventory available? Thanks for any help.

    help wanted 
    opened by peterhav 20
  • validate purches on a back-end

    validate purches on a back-end

    hi, i am watching your project and its very cool and proffesional development. but i lost a code sample where i can check purches in my server. could you please show me a method where i can call asynch query to check user' purches in my side?

    and one more little question. can i get only one purches item by id to show in activity just like premium account or smth else without common goodies query?

    opened by eGorets 19
  • Unable to validate purchase (product.isPurchased(...))

    Unable to validate purchase (product.isPurchased(...))

    Hello,

    I cannot get my app to verify that the purchase is done.

    product.isPurchased(Constants.IN_APP_SKU_VERSION_PRO)

    This line always returns false, tried with my own SKU and "android.test.purchased" as well.

    Its really weird because if I evaluate it as an expression in debug mode it returns true, but running always returns false.

    Tried to clean, rebuild, etc. and same result. Any ideas?

    Thanks in advance.

    opened by andoni90 12
  • Unable to get purchased items (on multiple devices using the same Google account)

    Unable to get purchased items (on multiple devices using the same Google account)

    My case is similar to an already closed issue #15

    On device#A, I purchased an item(XYZ) but was not able to consume due to some conditions unique to our specification. On device#A, I check if item(XYZ) has been purchased, and if it is, I simply consume it. There is nothing abnormal in this scenario as I was able to get the list of purchased items. The issue is when I use device#B (with same Google account). When that same method that checks if item(XYZ) has been purchased would not correctly return the purchased item(s). Subsequently, when user tries to buy item(XYZ), an error indicating the item is already owned pops up.

    I have tried returning null on Billing.Configuration#getCache method or clearing the cache withCache#clear method as proposed but to no avail.

    #issue 15 is already marked closed, yet, there seems to be another person having the same issue as I am dealing with.

    I simply want to be able to check if an Item is already purchased (so I can just consume it) across devices (with same account).

    I would appreciate if you could assist me to a proper solution.

    opened by josephmesteban 11
  • Please help with lollipop

    Please help with lollipop

    Hi. I am using compile 'org.solovyev.android:checkout:0.5.3-async-verify@aar' but today i have got an error and find your fix in main branch (issue #13). Can you build new aar with this fix for me? or I just can fix it and build aar by 'gradle build' command?

    opened by eGorets 11
  • Google getPurchases().

    Google getPurchases().

    We need to get the Purchased items (Live from google play). In inventory purchased items are locally cached ? What i am trying to do is check the purchased items when app starts and unlock features and make item PURCHASED. Problem with inventory is when i install the same app in other device (same google account logged in) it doesn't reflect. Item is again available for purchase which user has bought already in some other device ((same google account). How i can directly call the google's getPurchases() method of billing service ?

    opened by shivarajp 11
  • Better proguard setup

    Better proguard setup

    Bacause of following proguard config

    -assumenosideeffects class org.solovyev.android.checkout.Check {
    	static *;
    }
    

    I get following warnings:

    Note: the configuration specifies that none of the methods of class 'org.solovyev.android.checkout.Check' have any side effects
    Note: the configuration specifies that none of the methods of class 'org.solovyev.android.checkout.Check' have any side effects
    Note: there were 2 '-assumenosideeffects' options that try to match all
    	  methods with wildcards. This will likely cause problems with methods like
    	  'wait()' and 'notify()'. You should specify the methods more precisely.
    	  (http://proguard.sourceforge.net/manual/troubleshooting.html#nosideeffects)
    

    Could you explain which fields/functions we need to keep in order to have checkout work properly?

    opened by MFlisar 9
  • onSuccess() not called

    onSuccess() not called

    Hello Sergey,

    Since the Issue #78 was closed I opened a new one. I am experiencing probably same issue as user "squeeish".

    I am testing my application with a static response where i try to hide a button. When I click on the button, the Payment is successful, but the onSuccess() is not triggered and the button does not hide.

    Clicking a second time gives me the following error and application crashes. java.lang.IllegalArgumentException: Purchase flow associated with requestCode=51966 already exists I am calling the billing from a Fragment. Do you know why this happens ?

    However just to test it, if I add the hide function(unlock()) to the onError() and restart the app, clicking on the Button hides it so the onError() works fine.

    My code:

    private class PurchaseListener extends EmptyRequestListener<Purchase> {
        @Override
        public void onError(int response, @Nonnull Exception e) {
            super.onError(response, e);
    
          unlock();
        }
    
        @Override
        public void onSuccess(@Nonnull Purchase result) {
            Toast.makeText(getActivity(), "SUCCESS", Toast.LENGTH_SHORT).show();
             unlock();
        }
    }
    

    Thank You Marios

    opened by Astralgr 9
  • product.getPurchases() return empty list

    product.getPurchases() return empty list

    I have already made 2 subscriptions but product.getPurchases(); return empty list. What am I doing wrong?

    mCheckout.loadInventory(request, new Inventory.Callback() {
        @Override
        public void onLoaded(@Nonnull Inventory.Products products) {
    	final Inventory.Product product = products.get(SUBSCRIPTION);
            List<Purchase> purchases = product.getPurchases();
        }
    });
    
    question 
    opened by invizorys 9
  • Improve GRADLE build Performance

    Improve GRADLE build Performance

    Parallel builds. This project contains multiple modules. Parallel builds can improve the build speed by executing tasks in parallel. We can enable this feature by setting org.gradle.parallel=true.

    File system watching. Since Gradle 6.5, File system watching was introduced which can help to avoid unnecessary I/O. This feature is the default since 7.0. For an older version, we can enable this feature by setting org.gradle.vfs.watch=true.

    Configuration on demand. Configuration on demand tells Gradle to configure modules that only are relevant to the requested tasks instead of configuring all of them. We can enable this feature by setting org.gradle.configureondemand=true.

    gradle caching. Shared caches can reduce the number of tasks you need to execute by reusing outputs already generated elsewhere. This can significantly decrease build times. We can enable this feature by setting org.gradle.caching=true.

    ===================== If there are any inappropriate modifications in this PR, please give me a reply and I will change them.

    opened by shisheng-1 0
  • onActivityResult() got deprecated

    onActivityResult() got deprecated

    As stated in the android document, onActivityResult is deprecated. The replaced one is stated as following: use registerForActivityResult(ActivityResultContract, ActivityResultCallback) with the appropriate ActivityResultContract and handling the result in the callback.

    Update: I mean in the fragment.

    Do you have any plan to migrate the library?

    opened by quanmltya 1
  • Not Restore purchased app after uninstall and install again

    Not Restore purchased app after uninstall and install again

    Hello, I am getting restoring problem after uninstall and install again, it does not get product ID in purchased SKU list. please help as soon as possible

    opened by priyankJksol 0
Owner
Sergey Solovyev
Sergey Solovyev
SocialAuth repository which contains socialauth android version and samples

SocialAuth Android is an Android version of popular SocialAuth Java library. Now you do not need to integrate multiple SDKs if you want to integrate y

3Pillar Global Open Source 318 Dec 30, 2022
Android Weather Library: android weather lib to develop weather based app fast and easily

WeatherLib Android weather lib is an android weather aggregator. The lib helps you getting weather data from the most importat weather provider. It su

Surviving with android (by Francesco Azzola) 641 Dec 23, 2022
Android library project for providing multiple image selection from the device.

PolyPicker Android library project for selecting/capturing multiple images from the device. Result Caution! Eclipse library project structure has been

JW 407 Dec 27, 2022
Donations library for Android. Supports Google Play Store, Flattr, PayPal, and Bitcoin

Android Donations Lib Android Donations Lib supports donations by Google Play Store, Flattr, PayPal, and Bitcoin. It is used in projects, such as Open

Sufficiently Secure 346 Jan 8, 2023
Android library that provides for multiple image selection.

#MultipleImageSelect An android library that allows selection of multiple images from gallery. It shows an initial album (buckets) chooser and then im

Darshan Dorai 299 Nov 14, 2022
A clustering library for the Google Maps Android API v2

DEPRECATED Don't use this. The Maps v3 SDK handles markers. That with a few other cool utilities make this library obsolete! Clusterkraf A clustering

Ticketmaster Mobile Studio 258 Nov 28, 2022
Donations library for Android. Supports Google Play Store, Flattr, PayPal, and Bitcoin

Android Donations Lib Android Donations Lib supports donations by Google Play Store, Flattr, PayPal, and Bitcoin. It is used in projects, such as Open

Sufficiently Secure 345 Dec 21, 2022
Small library that wraps Google Play Service API in brilliant RxJava Observables reducing boilerplate to minimum.

ReactiveLocation library for Android Small library that wraps Google Play Services API in brilliant RxJava Observables reducing boilerplate to minimum

Michał Charmas 2.1k Dec 4, 2022
Accept PayPal and credit cards in your Android app

Important: PayPal Mobile SDKs are Deprecated. The APIs powering them will remain operational long enough for merchants to migrate, but the SDKs themse

PayPal 802 Dec 22, 2022
This App is sending Face capture data over network, built around the latest Android Arcore SDK.

AndroidArcoreFacesStreaming From any Android phone ArCore compatible, using this app will send over TCP 5680 bytes messages: The first 5616 bytes is a

Maxime Dupart 30 Nov 16, 2022
How to Integrate SAWO SDK to an Android app

How to Integrate SAWO SDK to an Android app Add following line to root build.gradle repositories block maven { url 'https://jitpack.io' } Add this to

Latiful Mousom 0 Nov 20, 2021
A very simple way to implement In App Purchases on Android.

The Google-developed Android In App Purchases library can seem quite confusing and too much code to do something as simple as making in-app purchases

Maickonn Richard 1 Sep 29, 2021
The client app for Android

handl-service-provider-application “Service Booking Platform ” is an advanced pl

null 0 Dec 20, 2021
A sample project of implementing Liveness Detection and Identity OCR on Android app using Kredibel Vision SDK

Vision Sample (Android) A sample project of implementing Liveness Detection and Identity OCR on Android app using Kredibel Vision SDK. You can checkou

null 10 Nov 27, 2022
Android SDK for eyeson video service incl. demo app

eyeson Android SDK Android SDK for eyeson video service incl. demo app Prerequisites A webservice to host and maintain eyeson meetings is required. Th

eyeson 3 Nov 16, 2022
Qiscus provide everything you need to power up your app with chats. And it's now made simple.

Introduction Qiscus Chat SDK (Software Development Kit) is a product provided by Qiscus that enables you to embed an in-app chat/chat feature in your

Qiscus - Multichannel Conversational Platform 197 Dec 27, 2022
Free forever Marketing SDK with a dashboard for in-app SplashScreen banners with built-in analytics

AdaptivePlus Android SDK AdaptivePlus is the control center for marketing campaigns in mobile applications Requirements minSdkVersion 16 Examples prov

Adaptive.Plus 16 Dec 14, 2021
Its measurement app made using kotlin with sceneform sdk by google

ARCORE MEASUREMENT This app is build using sceneform sdk for android using kotlin language It helps you measure the distance between multiple points i

Kashif Mehmood 39 Dec 9, 2022