Skip to content

miguelbcr/RxBillingService

Repository files navigation

RxBillingService

RxJava 2 extension for Android In-App Billing version 3 .

Currently is only tested for inapp products, not subs

Features:

  • No configuration: no IInAppBillingService.aidl , no billing permission in Manifest.xml, no activity or fragment lifecycle.
  • Works in activities and fragments.
  • Reactive calls, so you don't need onActivityResult() anymore.
  • You will get the proper object ( Purchase , SkuDetails, Boolean) or RxBillingServiceException if something went wrong.

Setup

Add the JitPack repository in your build.gradle (top level module):

allprojects {
    repositories {
        jcenter()
        maven { url "https://jitpack.io" }
    }
}

And add next dependencies in the build.gradle of the module:

dependencies {
    compile "com.github.miguelbcr:RxBillingService:0.0.3"
    compile 'io.reactivex.rxjava2:rxandroid:2.0.0'
}

Usage

Before attempting to use RxBillingService, you need to call RxBillingService.register() in your Android Application class, supplying as parameter the current instance.

public class SampleApp extends Application {

    @Override public void onCreate() {
        super.onCreate();
        RxBillingService.register(this);
    }
}

Limitations: Your fragments need to extend from android.support.v4.app.Fragment instead of android.app.Fragment.

In order to avoid recreate the activity or fragment by rotating the screen during the transaction, which will result a malfunction, you will have to add this to your activity in the Manifest.xml:

android:configChanges="layoutDirection|orientation|screenLayout|screenSize"

or you could define the screen orientation to your activity in the Manifest.xml by adding, for instance:

android:screenOrientation="portrait"

Methods available

Checking whether the billing service is available

Sginature:

Single<Boolean> isBillingSupported(ProductType productType)

Example:

RxBillingService.getInstance(this, BuildConfig.DEBUG)
        .isBillingSupported(ProductType.IN_APP)
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(supported -> {
          // Do your stuffs
        }, throwable -> {
          if (throwable instanceof RxBillingServiceException) {
            // You can handle the response code defined in RxBillingServiceError
          }
        });

Getting product details

Sginature:

Single<List<SkuDetails>> getSkuDetails(ProductType productType, List<String> productIds)

Example:

RxBillingService.getInstance(this, BuildConfig.DEBUG)
        .getSkuDetails(ProductType.IN_APP, Arrays.asList("my-sku", "my-product_id"))
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(skuDetailsList -> {
          // Do your stuffs
        }, throwable -> {
          if (throwable instanceof RxBillingServiceException) {
            // You can handle the response code defined in RxBillingServiceError
          }
        });

Purchasing a product

Sginature:

Single<Purchase> purchase(ProductType productType, String productId, String developerPayload)

Example:

    final String developerPayload = String.valueOf(System.currentTimeMillis());
    
    RxBillingService.getInstance(this, BuildConfig.DEBUG)
        .purchase(ProductType.IN_APP, "my-sku", developerPayload)
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(purchase -> {
          // Do your stuffs
        }, throwable -> {
          if (throwable instanceof RxBillingServiceException) {
            // You can handle the response code defined in RxBillingServiceError
          }
        });

Consuming a purchase

Sginature:

Single<Boolean> consumePurchase(String purchaseToken)

Example:

    final String token = purchase.token();
    ...
    RxBillingService.getInstance(this, BuildConfig.DEBUG)
        .consumePurchase(token)
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(success -> {
          // Do your stuffs
        }, throwable -> {
          if (throwable instanceof RxBillingServiceException) {
            // You can handle the response code defined in RxBillingServiceError
          }
        });

Purchasing and consuming a product at once

Sginature:

Single<Purchase> purchaseAndConsume(ProductType productType, String productId, String developerPayload)

Example:

    final String developerPayload = String.valueOf(System.currentTimeMillis());
    
    RxBillingService.getInstance(this, BuildConfig.DEBUG)
        .purchaseAndConsume(ProductType.IN_APP, "my-sku", developerPayload)
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(purchase -> {
          // Do your stuffs
        }, throwable -> {
          if (throwable instanceof RxBillingServiceException) {
            // You can handle the response code defined in RxBillingServiceError
          }
        });

Getting your purchases

Sginature:

Single<List<Purchase>> getPurchases(final ProductType productType)

Example:

    RxBillingService.getInstance(this, BuildConfig.DEBUG)
        .getPurchases(ProductType.IN_APP)
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(purchaseList -> {
          // Do your stuffs
        }, throwable -> {
          if (throwable instanceof RxBillingServiceException) {
            // You can handle the response code defined in RxBillingServiceError
          }
        });

Error handling

If an error happens during the transaction you can check the exception thrown in the subscribe().

You can handle Google Play errors by checking if the Throwable instance is a RxBillingServiceException object and getting the code defined in RxBillingServiceError :

    ...
    .subscribe(purchase -> {
      // Do your stuffs
    }, throwable -> {
      if (throwable instanceof RxBillingServiceException) {     
        RxBillingServiceException billingException = (RxBillingServiceException) throwable;
        if (billingException.getCode() == RxBillingServiceError.ITEM_ALREADY_OWNED) {
            // Notify the user
        }
      }
    });

Credits

  • RxActivityResult: A reactive-tiny-badass-vindictive library to break with the OnActivityResult implementation as it breaks the observables chain.

Author

Miguel García

Another author's libraries using RxJava:

  • RxPaparazzo: RxJava extension for Android to take images using camera and gallery.
  • RxGpsService: An Android service to retrieve GPS locations and route stats using RxJava
  • OkAdapters: Wrappers for Android adapters to simply its api at a minimum