Easy Checkout Library (Android In-App Billing v3 and v5)
Fast and easy checkout library (Android In-App Billing) for Android apps with RxJava support. For RxJava please check here.
Why you should use Easy-Checkout?
This library supports both non-consumable/consumable items and upgrading/downgrading of subscriptions.
NOTE: Upgrade/Downgrade of subscriptions are only available in the api version 5. You can still set the api version 3 for other actions in the library. The api version 5 automatically will be used only in this case.
It also solves common problems that developers face while working with In-App Billing, such as:
- How to query purchase information in the background
- How to load all the purchases using continuationToken
- How to load all item SKU details, since one request is limited by 20 items. See more
Test coverage 100%
Easy-Checkout has 100% test coverage and I will try to keep it at that level for stable releases.
Let's get started
Installation
-  Supports Android 2.3 SDK or higher. 
-  For Eclipse users, download the latest jar version on Bintray and add it as a dependency. 
-  For Gradle users, the library is available in the jcenter and mavenCentral. Add this into your build.gradle file: 
repositories {
    jcenter()
    mavenCentral()
}
dependencies {
    compile 'jp.alessandro.android:easy-checkout:vX.X.X'
} 
where vX.X.X is the your preferred version. For the latest version, please see the project's Releases. You can also see more details on Bintray.
- This library requires com.android.vending.BILLINGpermission. Usually, permissions are merged automatically during the manifest merging step, but you can add it into the AndroidManifest.xml of your application.
<uses-permission android:name="com.android.vending.BILLING" /> 
- If you use Proguard to obfuscate your code, you must add the following line to your Proguard configuration file:
-keep class com.android.vending.billing.** 
Creating a Billing Context
- You need a BillingContext object to execute actions in this library. You can create one as follows:
// Application context
Context context = getApplicationContext();
// Public key generated on the Google Play Console
String base64EncodedPublicKey = "YOUR_PUBLIC_KEY";
BillingContext.Builder builder = new BillingContext.Builder()
    .setContext(getApplicationContext()) // App context
    .setPublicKeyBase64(base64EncodedPublicKey) // Public key generated on the Google Play Console
    .setApiVersion(BillingApi.VERSION_3) // It also supports version 5
    .setLogger(new SystemLogger()) // This is optional
BillingContext context = builder.build(); 
Sample (Sample App coming soon)
- See the sample of how to use it:
public class SampleActivity extends Activity {
    private final PurchaseHandler mPurchaseHandler = new PurchaseHandler() {
      @Override
      public void call(PurchaseResponse response) {
          if (response.isSuccess()) {
              Purchase purchase = response.getPurchase();
              // Do your stuff with the purchased item
          } else {
              // Handle the error
          }
      }
    };
    private BillingProcessor mBillingProcessor;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);
      initBillingProcessor();
    }
    private void initBillingProcessor() {
      // Your public key
      String base64EncodedPublicKey = "YOUR_PUBLIC_KEY";
      BillingContext.Builder builder = new BillingContext.Builder()
        .setContext(getApplicationContext()) // App context
        .setPublicKeyBase64(base64EncodedPublicKey) // Public key generated on the Google Play Console
        .setApiVersion(BillingApi.VERSION_3) // It also supports version 5
        .setLogger(new SystemLogger()) // This is optional
      mBillingProcessor = new BillingProcessor(builder.build(), mPurchaseHandler);
    }
    @Override
    public void onDestroy() {
      super.onDestroy();
      mBillingProcessor.release();
    }
} 
- Don't forget to override Activity's onActivityResult method like this:
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
  if (mBillingProcessor.onActivityResult(requestCode, resultCode, data)) {
      // The response will be sent through PurchaseHandler
      return;
  }
  super.onActivityResult(requestCode, resultCode, data);
} 
Purchase Item
- Call BillingProcessor#startPurchasemethod to purchase a consumable/non-consumable or a subscription item like this:
Activity activity = this;
int requestCode = 10; // YOUR REQUEST CODE
String itemId = "YOUR_ITEM_ID";
PurchaseType purchaseType = PurchaseType.IN_APP; // or PurchaseType.SUBSCRIPTION for subscriptions
String developerPayload = "YOUR_DEVELOPER_PAYLOAD";
mBillingProcessor.startPurchase(activity, requestCode, itemId, purchaseType, developerPayload,
        new StartActivityHandler() {
            @Override
            public void onSuccess() {
                // Billing activity started successfully
                // Do nothing
            }
            @Override
            public void onError(BillingException e) {
                // Handle the error
            }
        }); 
As a result you will get a Purchase object.
Consume Purchased Item
- You can consume a purchased item anytime and allow the user to buy the same item again. To do this call BillingProcessor#consumelike this:
String itemId = "YOUR_ITEM_ID";
mBillingProcessor.consumePurchase(itemId, new ConsumeItemHandler() {
    @Override
    public void onSuccess() {
        // Item was consumed successfully
    }
    @Override
    public void onError(BillingException e) {
        // Handle the error
    }
}); 
Upgrade/Downgrade Subscription
- You can upgrade/downgrade an existing subscription by calling BillingProcessor#updateSubscriptionlike this:
This is only available in the api version 5. You can still set the api version 3 for other actions in the library. The api version 5 automatically will be used only in this case.
Activity activity = this;
int requestCode = 10; // YOUR REQUEST CODE
ArrayList<String> itemIdList = new ArrayList<>();
itemIdList.add("CURRENT_ITEM_ID");
String targetItemId = "TARGET_ITEM_ID";
String developerPayload = "YOUR_DEVELOPER_PAYLOAD";
mBillingProcessor.updateSubscription(activity, requestCode, itemIdList, targetItemId, developerPayload,
              new StartActivityHandler() {
                @Override
                public void onSuccess() {
                    // Billing activity started successfully
                    // Do nothing
                }
                @Override
                public void onError(BillingException e) {
                    // Handle the error
                }
              }); 
As a result you will get a Purchase object through of the PurchaseHandler set in the BillingProcessor's constructor.
Inventory of Purchases
- You can get the inventory of your purchases like this:
PurchaseType purchaseType = PurchaseType.IN_APP; // PurchaseType.SUBSCRIPTIONS for subscriptions
mBillingProcessor.getPurchases(purchaseType, new PurchasesHandler() {
    @Override
    public void onSuccess(Purchases purchases) {
        // Do your stuff with the list of purchases
        List<Purchase> purchaseList = purchases.getAll();
    }
    @Override
    public void onError(BillingException e) {
        // Handle the error
    }
}); 
As a result you will get a list of Purchase objects.
List of Item details
- You can get a list of your sku item details such as prices and descriptions
PurchaseType purchaseType = PurchaseType.IN_APP; // PurchaseType.SUBSCRIPTIONS for subscriptions
ArrayList<String> itemIds = new ArrayList<>();
itemIds.add("item_id_2");
itemIds.add("item_id_1");
mBillingProcessor.getItemDetails(purchaseType, itemIds, new ItemDetailListHandler() {
    @Override
    public void onSuccess(ItemDetails itemDetails) {
        // Do your stuff with the list of item details
        List<Item> items = itemDetails.getAll();
    }
    @Override
    public void onError(BillingException e) {
        // Handle the error
    }
}); 
Cancel
- Cancel the all purchase flows. It will clear the pending purchase flows and ignore any event until a new request.
 If you don't need the BillingProcessor instance any more, call directly Release instead.
 Note: By canceling it will not cancel the purchase process since the purchase process is not controlled by the app.
mBillingProcessor.cancel(); 
Release
- Release the handlers. Once you release it, you MUST create a new instance. 
 Note: By releasing it will not cancel the purchase process since the purchase process is not controlled by the app.
mBillingProcessor.release(); 
As a result you will get a list of Item detail objects.
Check In-App Billing service availability
- In some devices, In-App Billing may not be available. Therefore, it is advisable to check whether it is available or not by calling BillingProcessor.isServiceAvailableas follows:
boolean isAvailable = BillingProcessor.isServiceAvailable(getApplicationContext());
if (!isAvailable) {
    // Abort
} 
Purchase Object
- This object contains all the information of a purchase
  public String getOriginalJson();
  public String getOrderId();
  public String getPackageName();
  public String getSku();
  public long getPurchaseTime();
  public int getPurchaseState();
  public String getDeveloperPayload();
  public String getToken();
  public boolean isAutoRenewing();
  public String getSignature(); 
Item Object
- This object contains all the information of an item
  public String getOriginalJson();
  public String getSku();
  public String getType();
  public String getTitle();
  public String getDescription();
  public String getCurrency();
  public String getPrice();
  public long getPriceMicros();
  public String getSubscriptionPeriod();
  public String getFreeTrialPeriod();
  public String getIntroductoryPrice();
  public long getIntroductoryPriceAmountMicros();
  public String getIntroductoryPricePeriod();
  public int getIntroductoryPriceCycles(); 
 JarCasting
 JarCasting