Atomic Plugins for InApps
Java Objective-C CSS C++ JavaScript Objective-C++ Other
Latest commit 21010fe Aug 5, 2016 Imanol Martin OrderId can be missing if it's a testing transaction

README.md

Atomic Plugins for In-App Purchases

This repo contains In-App purchase APIs designed using the Atomic Plugins paradigm. You can integrate IAPs in your app and take advantage of all the features provided: elegant API, local and server-side receipt validation, secure consumable and non-consumable purchase tracking, local product cache and more. The API is already available in many languagues and we plan to add more in the future:

Currently there are 3 in-app purchase providers implemented but new ones can be easily added:

  • Apple AppStore (iOS/Mac)
  • GooglePlay
  • Amazon AppStore.

You can contribute and help to create more awesome plugins.

About Atomic Plugins

Atomic Plugins provide an elegant and minimalist API and are designed with portability in mind from the beginning. Framework dependencies are avoided by design so the plugins can run on any platform and can be integrated with any app framework or game engine.

Provided APIs

iOS API:

API Reference

See API Documentation

See LDInAppService.h header file for a complete overview of the capabilities of the class.

See InAppTest for a complete project that tests all the features provided in the API.

Introduction

LDInAppService class provides an easy to use and secure in-app purchase API. Built-in support for local and server-side receipt validation, consumable and non-consumable purchase tracking and local product cache. Completed purchases are secured using Apple's keychain services and are remembered even if the user deletes the app.

Setup your project

You can use CocoaPods:

pod 'LDInAppService'

Example

LDInAppService * service = [[LDInAppService alloc] init];

[service addPurchaseObserver: self]; //optional delegate to observe purchases
[service start]; //start processing transactions

[service fetchProducts:@[@"productIds"] completion:^(NSArray *products, NSError *error) {
     //fetch products from remote server
}];

service.products; //local cached products

[service purchase:productId quantity:2 completion:^(NSError *error) {
    //purchase consumable or non consumable products
}];
[service consume:productId quantity:1]; //consume product

[service isPurchased:productId]; //check if a productId is purchased
[service stockOfProduct:productId]; //check available stock of consumable products

[service restorePurchases:^(NSError *error) {
     //restore non-consumable purchases
}];
[service setValidationHandler:^(NSData *validationReceipt, NSString *productId, LDValidationCompletion completion) {
    //custom server validation
    completion(nil); //Call completion with nil error if validation succeeds
}];
[service setLudeiServerValidationHandler]; //validate using Ludei's Cloud server

Android API:

API Reference

See API Documentation

See InAppTest for a complete project that tests all the features provided in the API. In order to test Android In-Apps select the googlePlayRelelease or amazonRelease built variant in Android Studio. You must set your custom productIds in MainActivity.java and set your bundleId and versionCode in the build.gradle

You also have to configure your release signingConfig. Add these properties to your global gradle.properties file

STORE_FILE=/Users/user/.android/company.keystore
STORE_PASSWORD=xxxxx
KEY_ALIAS=xxxxxxx
KEY_PASSWORD=xxxxx

Introduction

InAppService interface provides an easy to use and secure in-app purchase API. Built-in support for local and server-side receipt validation, consumable and non-consumable purchase tracking and local product cache. Single API for multiple IAP providers.

Setup your project

Releases are deployed to Maven Central. You only have to add the desired dependencies in your build.gradle:

dependencies {
    compile 'com.ludei.inapps.googleplay:1.0.0' //Google Play IAP Provider
    compile 'com.ludei.inapps.amazon:1.0.0' //Amazon AppStore IAP Provider
}

Example

//create the service instance using the desired provider
InAppService service =  new GooglePlayInAppService(context);
//service =  new AmazonInAppService(context);

service.fetchProducts(productIds, new InAppService.FetchCallback() {
    public void onComplete(List<InAppProduct> products, InAppService.Error error) {
        //fetch products from store
    }
});

service.getProducts(); // Local cached products

service.purchase(productId, new InAppService.PurchaseCallback() {
    public void onComplete(InAppPurchase purchase, InAppService.Error error) {
        //purchase product
    }
});

service.consume(productId, 1, new InAppService.ConsumeCallback() {
    public void onComplete(int consumed, InAppService.Error error) {
        //consume product
    }
});

service.isPurchased(productId); //check if a product is purchased
service.stockOfProduct(productId); //check available stock of consumable products 

service.restorePurchases(new InAppService.RestoreCallback() {
    public void onComplete(InAppService.Error error) {
        //Restore completed purchases
    }
});

service.setValidationHandler(new InAppService.ValidationHandler() {
    public void onValidate(String receipt, String productId, InAppService.ValidationCompletion completion) {
        //custom server validation
    }
});

service.setLudeiServerValidationHandler(); //Validate using Ludei's Cloud server

Remember to notify onActivityResult and onDestroy events

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data)
{
    boolean handled = service.onActivityResult(requestCode, resultCode, data);
    if (!handled) {
        super.onActivityResult(requestCode, resultCode, data);
    }
}

@Override
public void onDestroy()
{
    service.onDestroy();
    super.onDestroy();
}

JavaScript API:

API Reference

See API Documentation

For a complete project that tests all the features provided in the API run the following command:

gulp create-cordova

A cordova project is created in test/cordova/InAppTest

Introduction

Cocoon.InApp class provides a multiplatform, easy to use and secure in-app purchase API. Built-in support for local and server-side receipt validation, consumable and non-consumable purchase tracking and local product cache. Single JavaScript API for multiple IAP providers.

Setup your project

Releases are deployed to Cordova Plugin Registry. You only have to install the desired plugins using Cordova CLI, CocoonJS CLI or Ludei's Cocoon Cloud Server.

cordova plugin add cocoon-plugin-inapps-ios-appstore;
cordova plugin add cocoon-plugin-inapps-android-googleplay;
cordova plugin add cocoon-plugin-inapps-android-amazon;

The following JavaScript file is included automatically:

cocoon_inapps.js

Example

// Basic usage, register callbacks first
var service = Cocoon.InApp;
service.on("purchase", {
    start: function(productId) {
        console.log("purchase started " + productId);
    },
    error: function(productId, error) {
        console.log("purchase failed " + productId + " error: " + JSON.stringify(error));
    },
    complete: function(purchase) {
        console.log("purchase completed " + JSON.stringify(purchase));
    }
});

// Service initialization
service.initialize({
        autofinish: true
    }, function(error){

    }
);

service.fetchProducts(productIds, function(products, error){
    //Fetch products from the server
});   

service.getProducts(); //Local cached products

service.purchase(productId, 1, function(error) { // Optional sugar callback
    //purchase product
});

service.consume(productId, 3, function(error) {
    //consume product
});

service.isPurchased(productId); //check if a product is purchased
service.stockOfProduct(productId); //check available stock of consumable products

service.setValidationHandler(function(receipt, productId, completion){
     ... //Custom server validation code
     completion(true); //call completion function with true param if validation succeeds
});

service.setLudeiServerValidationHandler(); //validate using Ludei's Cloud server

C++ API:

API Reference

See API Documentation

See InAppService.h header file for a complete overview of the capabilities of the class.

See InAppTest for a complete project (cocos2dx game) that integrates the C++ IAP API.

Introduction

InAppService class provides a multiplatform, easy to use and secure in-app purchase API. Built-in support for local and server-side receipt validation, consumable and non-consumable purchase tracking and local product cache. Single C++ API for multiple IAP providers.

Setup your project

You can download prebuilt headers and static libraries from Releases page

These static libraries provide the bindings between C++ and the native platform (iOS, Android, WP, etc). You might need to add some platform dependent libraries to your project (some jar files or gradle dependecies for example). See InAppTest for an already setup C++ multiplatform project.

Special setup required for Android

There isn't a portable and realiable way to get the current Activity and life cycle events on Android and we don't want to depend on specific game engine utility APIs. C++ and Java bridge is implemented using the SafeJNI utility. Atomic Plugins take advantage of this class and use it also as a generic Activity and Life Cycle Event notification provider. See the following code to set up the activity for atomic plugins and to notify Android life cycle events.

@Override
public void onCreate(Bundle savedInstanceState) {
    //set the activity for atomic plugins and load safejni.so
    SafeJNI.INSTANCE.setActivity(this); 
    super.onCreate(savedInstanceState);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    //notify onActivityResult to atomic plugins
    SafeJNI.INSTANCE.onActivityResult(requestCode, resultCode, data);
}

Optionally (but recommended) you can use setJavaToNativeDispatcher to configure the thread in which async callbacks should be dispatched. By default callbacks are dispatched in the UI Thread. For example the following dispatcher is used in the Cocos2dx game engine test project.

@Override
public Cocos2dxGLSurfaceView onCreateView() {
    final Cocos2dxGLSurfaceView surfaceView = super.onCreateView();
    SafeJNI.INSTANCE.setJavaToNativeDispatcher(new SafeJNI.JavaToNativeDispatcher() {
        @Override
        public void dispatch(Runnable runnable) {
            surfaceView.queueEvent(runnable);
        }
    });
    return surfaceView;
}
Signing a build for release

Set your bundleId and versionCode in the build.gradle

You also have to configure your release signingConfig. Add these properties to your global gradle.properties file

STORE_FILE=/Users/user/.android/company.keystore
STORE_PASSWORD=xxxxx
KEY_ALIAS=xxxxxxx
KEY_PASSWORD=xxxxx

Example

//Easy to use static method to instantiate a new service
//You can pass a specific InAppProvider if you have many providers linked in your app and you want to choose one of them at runtime
InAppService * service = InAppService::create();

service->addPurchaseObserver(observer); //optional purchase observer;
service->start(); //start processing transactions

service->fetchProducts(productIds, [=](const std::vector<InAppProduct> & products, const InAppService::Error & error){
    if (error.empty()) {
        //show error
        return;
    }
    // fetch products from remote server
});

service->purchase(productId, [=](const InAppPurchase & purchase, const InAppService::Error & error){
    //purchase product
});

service->consume(productId, 1, [=](int32_t consumed, const InAppService::Error & error){
    //consume product
});

service->isPurchased(productId); //check if a productId is purchased
service->stockOfProduct(productId); //check available stock of consumable products

service->restorePurchases([=](const InAppService::Error & error){
    //restore purchases
});

service->setValidationHandler([=](const string & receipt, const string & productId, const ValidationCompletion & completion){
    //custom server validation code
    completion(InAppService::Error()); //call completion with empty error if validation succeeds
});

service->setLudeiServerValidationHandler(); //validate using Ludei's Cloud server

//delete the service when you are done. You can wrap it into a Smart Pointer if you want.
delete service; 

License

Mozilla Public License, version 2.0

Copyright (c) 2015 Ludei

See MPL 2.0 License