Android Market In-app Billing Library

Overview

Update

In-app Billing v2 API is deprecated and will be shut down in January 2015. This library was developed for v2 a long time ago. If your app is still using this library, please migrate to the v3 API as soon as possible.

The project Android Checkout Library by @serso supports v3 and attemps to provide data compatibility with AndroidBillingLibrary. We haven't verified this so please use it at your own discretion.

Android Billing Library

requestPurchase("com.example.item")

That's how simple it should be to use Android In-app Billing.

And with this library it is.

Android Billing Library implements in-app billing's full specification and offers high-level classes to use it. Transactions are stored in a local obfuscated database which can be easily queried.

Getting Started

  • Get acquainted with the Android In-app Billing documentation.

  • Add Android Billing Library to your project.

  • Open the AndroidManifest.xml of your application and add this permission...

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

...and this service and receiver inside the application element:

<service android:name="net.robotmedia.billing.BillingService" />
<receiver android:name="net.robotmedia.billing.BillingReceiver">
	<intent-filter>
		<action android:name="com.android.vending.billing.IN_APP_NOTIFY" />
		<action android:name="com.android.vending.billing.RESPONSE_CODE" />
		<action android:name="com.android.vending.billing.PURCHASE_STATE_CHANGED" />
	</intent-filter>
</receiver>

That's it!

Usage

Subclassing AbstractBillingActivity

AbstractBillingActivity is an abstract activity that provides default integration with in-app billing (an analogous class for fragments is also provided). It is useful to get acquainted with the library, or for very simple applications that require in-app billing integration in only one activity. For more flexibility use BillingController directly.

When created your AbstractBillingActivity instance will check if in-app billing is supported, followed by a call to onBillingChecked(boolean), which has to be implemented by the subclass.

Additionally, your AbstractBillingActivity subclass will attempt to restore all transactions, only once. This is necessary in case the user has previously installed the app and made purchases. Existing transactions will generate calls to onPurchaseStateChange(String, PurchaseState), which has to be implemented by the subclass.

Starting a purchase is as simple as calling requestPurchase(String). AbstractBillingActivity will start the Google Play intent automatically and onPurchaseStateChange(String, PurchaseState) will be called after the transaction is confirmed.

If you override any of the methods provided by AbstractBillingActivity, make sure to call the superclass implementation.

BillingController

BillingController provides high-level functions to interact with the Billing service and to query an obfuscated local transaction database.

Since most billing functions are asynchronous, BillingController notifies all registered IBillingObserver of the responses.

Additionally, BillingController requires a BillingController.IConfiguration instance from which the public key required to validate signed messages and a salt to obfuscate transactions are obtained. A good place to provide the configuration is in the Application subclass.

Dungeons Redux

Dungeons Redux is a sample app that shows how to use Android Billing Library via BillingController. It is a simplified version of the Dungeons in-app billing example provided by Google.

It should be noted that Dungeons Redux does not intend to be an example of how to use in-app billing in general.

Contact

http://www.twitter.com/robotmedia | http://www.facebook.com/robotmedia | http://www.robotmedia.net

License

Copyright 2011 Robot Media SL (http://www.robotmedia.net)

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
  • Service doesn't stop itself

    Service doesn't stop itself

    I'm just looking through the code now, but I can't see where the service stops itself when the work is done (looking for a stopSelf()). After I finish() the app the BillingService continues to run. How are you stopping the service when using this library?

    Many thanks, Richard

    feature 
    opened by richardleggett 15
  • Verifying application with test items

    Verifying application with test items

    I am doing the following:

    private static final String ANDROID_MARKET_ITEM = "android.test.purchased";
    requestPurchase(ANDROID_MARKET_ITEM);
    

    But onPurchaseExecuted is not called. Purchase Dialog is just closed.

    What is wrong here? Also, if after that I check the database:

    BillingDB bDB = new BillingDB(getApplicationContext());
    Cursor purchases = bDB.queryPurchases();
    Log.i(TAG, "Count: " + purchases.getCount());
    

    I see that no records are added to the database.

    support 
    opened by and7ey 14
  • Allow server-side verification of transactions.

    Allow server-side verification of transactions.

    Hi! Thanks a lot for this handy library.

    I modified the source so that the raw signedData and signature strings are stored in the BillingDB. This way I can recover the transactions in my onPurchaseStateChanged callback through BillingController.getTransactions(this) and send to my server all the information needed to process the transaction and perform its verification.

    It's a small modification, but I think most user will look after this feature.

    opened by mrucci 12
  • Save signedData and signature to allow server side validation

    Save signedData and signature to allow server side validation

    This is a follow up to #58. Upgrade compatibility is guaranteed by the onUpgrade facility.

    Important: Before merging this pull request, someone with good knowledge of this library should test if restoring transactions work

    opened by guetux 7
  • onError-method for transaction restore failed / retry in case of remote exception

    onError-method for transaction restore failed / retry in case of remote exception

    Hi there,

    I added another method to be called in case the restoring of the transactions fails. It makes sense to know if it failed to display a message on an activity or a toast to let the user know that it failed (or handle it otherwise).

    Best regards Andy

    opened by AndyScherzinger 7
  • BillingController.isPurchased always returns false

    BillingController.isPurchased always returns false

    I have two activities - MainActivity extends ListActivity and Preferences extends AbstractBillingActivity.

    If BillingController.isPurchased is called at MainActivity, then false is always returned. But if it is called at Preferences, then it returns correct value (true). Why it happens so?

    support 
    opened by and7ey 7
  • How to handle refunds?

    How to handle refunds?

    There is no mention in documentation or tutorial on how to properly handle refunds. It is not clear what the action flow is and it is hard to test as well. Can somebody please add a How to handle refunds to the README file? Thanks.

    support 
    opened by sandscorpio 6
  • Unable to start receiver net.robotmedia.billing.BillingReceiver

    Unable to start receiver net.robotmedia.billing.BillingReceiver

    One of my user got the following error:

    java.lang.RuntimeException: Unable to start receiver net.robotmedia.billing.BillingReceiver: java.lang.ClassCastException: android.preference.Preference
    at android.app.ActivityThread.handleReceiver(ActivityThread.java:1805)
    at android.app.ActivityThread.access$2400(ActivityThread.java:117)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:981)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:130)
    at android.app.ActivityThread.main(ActivityThread.java:3683)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:507)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
    at dalvik.system.NativeStart.main(Native Method)
    Caused by: java.lang.ClassCastException: android.preference.Preference
    at spb.bridges.Preferences.onPurchaseExecuted(Preferences.java:89)
    at net.robotmedia.billing.BillingController.notifyPurchaseStateChange(BillingController.java:242)
    at net.robotmedia.billing.BillingController.onPurchaseStateChanged(BillingController.java:374)
    at net.robotmedia.billing.BillingReceiver.purchaseStateChanged(BillingReceiver.java:57)
    at net.robotmedia.billing.BillingReceiver.onReceive(BillingReceiver.java:44)
    at android.app.ActivityThread.handleReceiver(ActivityThread.java:1794)
    ... 10 more
    

    What can be the reason?

    support 
    opened by and7ey 6
  • "Item unavailable" error

    I'm trying to use this library to implement in app billing to accept donations in my app (my app will sell unmanaged items called "donations"). When I call to requestPurchase(STORE_ITEM_ID); appears the Google Play screen showing my unmanaged item correctly, but after a second a popup is shown and says: "The item you requested is not available for purchase".... This is what I did:

    1 - In my app: I created a new Activity that extends AbstractBillingActivity. I've overriden getObfuscationSalt method, it returns a byte array with 20 random digits. I've overriden getPublicKey method, it returns the public key I get in my developer console. I check if billing is supported using onBillingChecked, and finally when the user press the "donate" button I call requestPurchase if billing is supported.

    2 - In my developer console: I uploaded a new app signed (but is not published, only uploaded). I created a new unmanaged item, and I activated it. Then I added a new gmail test account. Then I used a real android device to test it, I did a hard reset and l used my gmail test account. I installed my app (the same version I uploaded), and.... thats all

    What I'm doing wrong? Can you help me please?

    support 
    opened by sjvc 5
  • Is there any problem to call restoreTransactions on every app load?

    Is there any problem to call restoreTransactions on every app load?

    Hi,

    thank you very much for the library, made the billing development a breeze.

    This post is just a support request. The app I'm developing is VERY likely to be used on more than one device by user (because connect devices together) and through an in-app purchase it enables the full features.

    Currently the app calls BillingController.restoreTransactions(context); only on the first run. But if (when) the user purchase the upgrade on a device 1, he won't see it on device 2 unless he uninstall/re-install the app.

    So I ask, if I simply call it every single time the app loads, will there be any problem with the database that is storing the transaction or will just drop the DB and re-populate and that's it?

    thanks.

    support 
    opened by budius 5
  • Problem with subscription

    Problem with subscription

    i'm using the DungeonsRedux and trying the subscription service. I can buy a subscription through the app but after bought the subscription i return in the app and i can't see the bought subscription, the code: for (Transaction t : transactions) { if (t.purchaseState == PurchaseState.PURCHASED) { ownedItems.add(t.productId); } } ownedItems is empty and the method onPurchaseStateChanged is never called.

    How i can fix this problem?

    Thank you very much.

    support 
    opened by oibaf79 5
  • BadTokenException in BillingReceiver

    BadTokenException in BillingReceiver

    Hi,

    First of all thak you for you nice library. It's really help me.

    From time to time I've get this exeption from my users: java.lang.RuntimeException: Unable to start receiver net.robotmedia.billing.BillingReceiver: android.view.WindowManager$BadTokenException: Unable to add window -- token android.os.BinderProxy@41e718e8 is not valid; is your activity running?

    I'm using AbstractBillingObserver for handling purchase process (not the activity version). As I understand sometimes for some reason Activity that I had put to Observer allready dead at the end of purchase. What is the proper way to handel this situation?

    opened by nickkadrov 0
  • onPurchaseStateChange does not gets called when purchase is successful.

    onPurchaseStateChange does not gets called when purchase is successful.

    I'm using test ids. onPurchaseStateChange() gets called when user cancels the purchase but it's not called when when purchase is successful. I've followed step2 mentioned in the below link but its still not working

    http://stackoverflow.com/questions/12844132/onpurchasestatechange-not-getting-called/12948238#12948238

    opened by ifra19 1
  • DeadObjectException

    DeadObjectException

    I'm getting a DeadObjectException from BillingRequest line 294:

    response = mService.sendBillingRequest(request);

    I'm using the extending AbstractBillingActivity approach. The original request is:

    requestPurchase("android.test.purchased")

    I am using debug mode. Any ideas on how to track down the problem?

    opened by nscherer 1
  • Issue with onPurchaseStateChanged

    Issue with onPurchaseStateChanged

    Hello. I have a issue: I bought the item in my application, and it was success. But in fact my function for purchase is never called. Every time I open my BillingActivity it shows me a window with text, that I have this item, and cannot buy it twice. As I see onPurchaseStateChanged is never called. And BillingController.isPurchased doesn't work in my case. I have read all topics with the same issues, but I don't understand, why it can be. Please, tell me, what I can do to fix this. And thank you for the library.

    UPD: There is "W/BillingService(14265): Remote billing service crashed" In the logcat. Can my issue be because of this?

    W/ActivityManager( 175): Trying to launch com.gravitrip/.BillingActivity I/AndroidInput(14265): Pointer ID lookup failed: 0, 0:-1 1:-1 2:-1 3:-1 4:-1 5:-1 6:-1 7:-1 8:-1 9:-1 I/InputDispatcher( 175): Delivering touch to current input target: action: 1, channel '40a10008 com.gravitrip/com.gravitrip.GravitripActivity (server)' V/b (14265): try to restore transaction V/AudioPolicyManager( 8906): stopOutput() output 1, stream 3, session 1659 E/AudioPolicyManager( 8906): stopOutput stream = 3 , mHardwareOutput = 1, output = 1 V/AudioPolicyManager( 8906): getNewDevice() selected device 0 V/AudioPolicyManager( 8906): setOutputDevice() output 1 device 0 delayMs 0 V/AudioPolicyManager( 8906): setOutputDevice() setting same device 0 or null device for output 1 I/AndroidInput(14265): Pointer ID lookup failed: 0, 0:-1 1:-1 2:-1 3:-1 4:-1 5:-1 6:-1 7:-1 8:-1 9:-1 W/BillingService(14265): Remote billing service crashed W/BillingService(14265): Remote billing service crashed I/WindowManager( 175): CREATE SURFACE Surface(name=com.gravitrip/com.gravitrip.BillingActivity, identity=733, mNativeSurface=0) IN SESSION android.view.SurfaceSession@40af5908: pid=14265 format=-1 flags=0x0 / Window{40888708 com.gravitrip/com.gravitrip.BillingActivity paused=false} E/DataRouter( 129): fd is 17 Content read is USB Switch : PDA_AP E/DataRouter( 129): length is 20
    E/DataRouter( 129): Content of Buf I/GLThread(14265): noticed surfaceView surface lost tid=9 D/PowerManager( 175): release flags=0x0 tag=ActivityManager-Launch I/ActivityManager( 175): Displayed com.gravitrip/.BillingActivity: +224ms

    import android.os.Bundle;
    import android.util.Log;
    import android.widget.Toast;
    import net.robotmedia.billing.BillingController;
    import net.robotmedia.billing.BillingController.BillingStatus;
    import net.robotmedia.billing.BillingRequest.ResponseCode;
    import net.robotmedia.billing.helper.AbstractBillingActivity;
    import net.robotmedia.billing.model.Transaction.PurchaseState;
    
    public class BillingActivity extends AbstractBillingActivity{
        public static final String ANDROID_MARKET_ITEM = "allchapters"; 
        private boolean billingSupported = false;
        static boolean purchased;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            // TODO Auto-generated method stub
            setContentView(com.gravitrip.R.layout.main);
            super.onCreate(savedInstanceState);
            purchased=false;
            if (checkBillingSupported() != BillingStatus.SUPPORTED) {
                Toast.makeText(getApplicationContext(), "Purchase is not supported", Toast.LENGTH_LONG).show();
                Log.v("b", "Purchase is not supported");
            } 
            else 
            {
                purchased = BillingController.isPurchased(getApplicationContext(), ANDROID_MARKET_ITEM);
                if (!purchased) {
                    Log.v("b", "try to restore transaction");
                    restoreTransactions();
                    purchased = BillingController.isPurchased(getApplicationContext(), ANDROID_MARKET_ITEM);
                    if (!purchased) {
                        requestPurchase(ANDROID_MARKET_ITEM);
                    }
                }
    
                if (purchased) 
                {
                    Log.v("b", "purchased #1");
                    UIClass.purchase();
                }
            }
    
    
        }
    
    @Override
    protected void onPause() {
        // TODO Auto-generated method stub
        purchased = BillingController.isPurchased(getApplicationContext(), ANDROID_MARKET_ITEM);
        if (purchased)        
        {
            Log.v("b", "purchased #2");
                    UIClass.purchase();
        }
        super.onPause();
    }
    
        @Override
        protected void onResume() {
            // TODO Auto-generated method stub
            super.onResume();
    
        }
    
        @Override
        public byte[] getObfuscationSalt() {
            // TODO Auto-generated method stub
            return new byte[] {-1, 5, -7, 4, 1, 2, 1, 8, -9, 1, 1, 2, 1, 14, -49, -21, 17, -8, 1, 22};
    
        }
    
        @Override
        public String getPublicKey() {
            // TODO Auto-generated method stub
        return ... //got from developer consol, RSA key.
        }
    
        @Override
        public void onBillingChecked(boolean arg0) {
            // TODO Auto-generated method stub
               billingSupported = arg0;
        }
    
        @Override
        public void onPurchaseStateChanged(String arg0, PurchaseState arg1) {
            // TODO Auto-generated method stub
                Log.v("b", "onPurchaseStateChanged");
    
            if (arg1==PurchaseState.CANCELLED) 
            {
                Toast.makeText(getApplicationContext(), "Transaction has been cancelled", Toast.LENGTH_LONG).show();
                Log.v("b", "PurchaseState.CANCELLED");
            }
            if (arg1==PurchaseState.PURCHASED) 
            {
                UIClass. purchase ();
                Log.v("b", "PurchaseState.PURCHASED");
            }
            if (arg1==PurchaseState.REFUNDED) 
            {
                Log.v("b", "PurchaseState.REFUNDED");
            }
            if (arg1==PurchaseState.EXPIRED) 
            {
                Log.v("b", "PurchaseState.EXPIRED");
            }
            if (arg1==PurchaseState.CANCELLED) 
            {
                Log.v("b", "PurchaseState.CANCELLED");
            }
        }
    
        @Override
        public void onRequestPurchaseResponse(String arg0, ResponseCode arg1) {
            // TODO Auto-generated method stub
    
        }
    
        @Override
        public void onSubscriptionChecked(boolean arg0) {
            // TODO Auto-generated method stub
    
        }
    
    }
    
    opened by i1j1k1 0
  • Validation of transaction doesn't work ?

    Validation of transaction doesn't work ?

    Hi,

    In my billing activity I put :

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.billing);
        BillingController.registerObserver(mBillingObserver);
        BillingController.checkBillingSupported(this);
        BillingController.setSignatureValidator(this);
    }
    
    @Override
    public void onDestroy() {
        super.onDestroy();
        BillingController.setSignatureValidator(null);
        BillingController.unregisterObserver(mBillingObserver);
    }
    

    I don't do anything within my "mBillingObserver"

    I want to purchase an item (added in my google play account) :

    BillingController.requestPurchase(this, purchaseId, false, null);
    

    After my purchased, I can see a toast "Thanks for your purchased for the play store" and I'm called on my method :

    @Override
    public boolean validate(String signedData, String signature) {
        Log.i(TAG, "validate " + signedData);
        // when a purchased need to be checked, just return false if the server side check return false
        // TODO add the server side check here
        return false; // change it by the server side verification
    }
    

    in my logcat I can see "Billing(16214): Validation failed"

    But the purchased wasn't canceled : I received an email from google to thanks me for my purchased.

    Note : I don't call any other method of BillingController anywhere

    Is it an error from me or from the billing library ?

    Thanks

    opened by StanKocken 0
Owner
Robot Media
Robot Media
Android Utilities Library build in kotlin Provide user 100 of pre defined method to create advanced native android app.

Android Utilities Library build in kotlin Provide user 100 of pre defined method to create advanced native android app.

Shahid Iqbal 4 Nov 29, 2022
Android library for viewing, editing and sharing in app databases.

DbInspector DbInspector provides a simple way to view the contents of the in-app database for debugging purposes. There is no need to pull the databas

Infinum 924 Jan 4, 2023
Small Android library to help you incorporate MVP, Passive View and Presentation Model patterns in your app

DroidMVP About DroidMVP is a small Android library to help you incorporate the MVP pattern along with Passive View and Presentation Model (yes, those

Andrzej Chmielewski 225 Nov 29, 2022
POC Simulate Backend Biometric Authentication with AIDL (client app/server app)

poc-simulate-bio-auth-aidl POC Simulate Backend Biometric Authentication with AIDL (client app/server app) #How to use Install server app and run Inst

gundamD 0 Dec 30, 2021
A robust native library loader for Android.

ReLinker A robust native library loader for Android. More information can be found in our blog post Min SDK: 9 JavaDoc Overview The Android PackageMan

Keepsafe 2.9k Dec 27, 2022
Joda-Time library with Android specialization

joda-time-android This library is a version of Joda-Time built with Android in mind. Why Joda-Time? Android has built-in date and time handling - why

Daniel Lew 2.6k Dec 9, 2022
UPnP/DLNA library for Java and Android

Cling EOL: This project is no longer actively maintained, code may be outdated. If you are interested in maintaining and developing this project, comm

4th Line 1.6k Jan 4, 2023
:iphone: [Android Library] Get device information in a super easy way.

EasyDeviceInfo Android library to get device information in a super easy way. The library is built for simplicity and approachability. It not only eli

Nishant Srivastava 1.7k Dec 22, 2022
An Android library allowing images to exhibit a parallax effect that reacts to the device's tilt

Motion An Android library allowing images to exhibit a parallax effect. By replacing static pictures and backgrounds with a fluid images that reacts t

Nathan VanBenschoten 781 Nov 11, 2022
Android library to easily serialize and cache your objects to disk using key/value pairs.

Deprecated This project is no longer maintained. No new issues or pull requests will be accepted. You can still use the source or fork the project to

Anup Cowkur 667 Dec 22, 2022
Form Validator Library for Android

Android-Validator Form Validator Library for Android [](https://flattr.com/submit/auto?user_id=throrin19&url=https://github.com/throrin19/Android-Vali

Benjamin Besse 449 Dec 17, 2022
Very easy to use wrapper library for Android SharePreferences

Treasure English document Treasure是一个Android平台上基于SharePreferences的偏好存储库,只需要定义接口,无需编写实现,默认支持Serializable和Parcelable。运行时0反射,不仅使用方便而且性能和原生写法几乎无差别。 使用方法 1

星一 507 Nov 12, 2022
Error handling library for Android and Java

ErrorHandler Error handling library for Android and Java Encapsulate error handling logic into objects that adhere to configurable defaults. Then pass

null 237 Dec 29, 2022
A simple Android utils library to write any type of data into cache files and read them later.

CacheUtilsLibrary This is a simple Android utils library to write any type of data into cache files and then read them later, using Gson to serialize

Wesley Lin 134 Nov 25, 2022
Android library that regroup bunch of dateTime utilities

DateTimeUtils This library is a package of functions that let you manipulate objects and or java date string. it combine the most common functions use

Thunder413 98 Nov 16, 2022
Slinger - deep linking library for Android

Slinger - deep linking library for Android Slinger is a small Android library for handling custom Uri which uses regular expression to catch and route

Allegro Tech 27 Dec 8, 2022
A simple and easy to use stopwatch and timer library for android

TimeIt Now with Timer support! A simple and easy to use stopwatch and timer library for android Introduction A stopwatch can be a very important widge

Yashovardhan Dhanania 35 Dec 10, 2022
Trail is a simple logging system for Java and Android. Create logs using the same API and the library will detect automatically in which platform the code is running.

Trail Trail is a simple logging system for Java and Android. Create logs using the same API and the library will detect automatically in which platfor

Mauricio Togneri 13 Aug 29, 2022
UI form validation library for Android

Android Saripaar v2 சரிபார் - sari-paar (Tamil for "to check", "verify" or "validate") Android Saripaar is a simple, feature-rich and powerful rule-ba

Ragunath Jawahar 3.2k Dec 29, 2022