Git Product home page Git Product logo

android-inapp-billing-v3's Introduction

Android In-App Billing v3 Library Build Status Maven Central

This is a simple, straight-forward implementation of the Android v4 In-app billing API.

It supports: In-App Product Purchases (both non-consumable and consumable) and Subscriptions.

Maintainers Wanted

This project is looking for maintainers.

For now only pull requests of external contributors are being reviewed, accepted and welcomed. No more bug fixes or new features will be implemented by the Anjlab team.

If you are interesting in giving this project some โค๏ธ, please chime in!

v4 API Upgrade Notice

Originally this was Google's v2 Billing API implementation, for those who interested all source code kept safe here.

If you got your app using this library previously, here is the Migration Guide.

Getting Started

  • You project should build against Android 4.0 SDK at least.

  • Add this Android In-App Billing v3 Library to your project:

    • If you guys are using Eclipse, download latest jar version from the releases section of this repository and add it as a dependency
    • If you guys are using Android Studio and Gradle, add this to you build.gradle file:
repositories {
  mavenCentral()
}
dependencies {
  implementation 'com.anjlab.android.iab.v3:library:2.0.3'
}
  • Create instance of BillingProcessor class and implement callback in your Activity source code. Constructor will take 3 parameters:
    • Context
    • Your License Key from Google Developer console. This will be used to verify purchase signatures. You can pass NULL if you would like to skip this check (You can find your key in Google Play Console -> Your App Name -> Services & APIs)
    • IBillingHandler Interface implementation to handle purchase results and errors (see below)
public class SomeActivity extends Activity implements BillingProcessor.IBillingHandler {
  BillingProcessor bp;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    bp = new BillingProcessor(this, "YOUR LICENSE KEY FROM GOOGLE PLAY CONSOLE HERE", this);
    bp.initialize();
    // or bp = BillingProcessor.newBillingProcessor(this, "YOUR LICENSE KEY FROM GOOGLE PLAY CONSOLE HERE", this);
    // See below on why this is a useful alternative
  }
	
  // IBillingHandler implementation
	
  @Override
  public void onBillingInitialized() {
    /*
    * Called when BillingProcessor was initialized and it's ready to purchase 
    */
  }
	
  @Override
  public void onProductPurchased(String productId, PurchaseInfo purchaseInfo) {
    /*
    * Called when requested PRODUCT ID was successfully purchased
    */
  }
	
  @Override
  public void onBillingError(int errorCode, Throwable error) {
    /*
    * Called when some error occurred. See Constants class for more details
    * 
    * Note - this includes handling the case where the user canceled the buy dialog:
    * errorCode = Constants.BILLING_RESPONSE_RESULT_USER_CANCELED
    */
  }
	
  @Override
  public void onPurchaseHistoryRestored() {
    /*
    * Called when purchase history was restored and the list of all owned PRODUCT ID's 
    * was loaded from Google Play
    */
  }
}
  • Call purchase method for a BillingProcessor instance to initiate purchase or subscribe to initiate a subscription:
bp.purchase(YOUR_ACTIVITY, "YOUR PRODUCT ID FROM GOOGLE PLAY CONSOLE HERE");
bp.subscribe(YOUR_ACTIVITY, "YOUR SUBSCRIPTION ID FROM GOOGLE PLAY CONSOLE HERE");
  • That's it! A super small and fast in-app library ever!

  • And don't forget to release your BillingProcessor instance!

@Override
public void onDestroy() {
  if (bp != null) {
    bp.release();
  }		
  super.onDestroy();
}

Instantiating a BillingProcessor with late initialization

The basic new BillingProcessor(...) actually binds to Play Services inside the constructor. This can, very rarely, lead to a race condition where Play Services are bound and onBillingInitialized() is called before the constructor finishes, and can lead to NPEs. To avoid this, we have the following:

bp = BillingProcessor.newBillingProcessor(this, "YOUR LICENSE KEY FROM GOOGLE PLAY CONSOLE HERE", this); // doesn't bind
bp.initialize(); // binds

Testing In-app Billing

Here is a complete guide. Make sure you read it before you start testing

Check Play Market services availability

Before any usage it's good practice to check in-app billing services availability. In some older devices or chinese ones it may happen that Play Market is unavailable or is deprecated and doesn't support in-app billing.

Simply call static method BillingProcessor.isIabServiceAvailable(context):

boolean isAvailable = BillingProcessor.isIabServiceAvailable(this);
if(!isAvailable) {
  // continue
}

Please notice that calling BillingProcessor.isIabServiceAvailable() (only checks Play Market app installed or not) is not enough because there might be a case when it returns true but still payment won't succeed. Therefore, it's better to call bp.isConnected() after initializing BillingProcessor:

boolean isConnected = billingProcessor.isConnected();
if(isConnected) {
  // launch payment flow
}

or call isSubscriptionUpdateSupported() for checking update subscription use case:

boolean isSubsUpdateSupported = billingProcessor.isSubscriptionUpdateSupported();
if(isSubsUpdateSupported) {
  // launch payment flow
}

Consume Purchased Products

You can always consume made purchase and allow to buy same product multiple times. To do this you need:

bp.consumePurchaseAsync("YOUR PRODUCT ID FROM GOOGLE PLAY CONSOLE HERE", new IPurchasesResponseListener());

Restore Purchases & Subscriptions

bp.loadOwnedPurchasesFromGoogleAsync(new IPurchasesResponseListener());

Getting Listing Details of Your Products

To query listing price and a description of your product / subscription listed in Google Play use these methods:

bp.getPurchaseListingDetailsAsync("YOUR PRODUCT ID FROM GOOGLE PLAY CONSOLE HERE", new ISkuDetailsResponseListener());
bp.getSubscriptionListingDetailsAsync("YOUR SUBSCRIPTION ID FROM GOOGLE PLAY CONSOLE HERE", new ISkuDetailsResponseListener());

As a result you will get a callback call including List<SkuDetails> data with one SkuDetails object with the following info included:

public final String productId;
public final String title;
public final String description;
public final boolean isSubscription;
public final String currency;
public final Double priceValue;
public final String priceText;

To get info for multiple products / subscriptions on one query, just pass a list of product ids:

bp.getPurchaseListingDetailsAsync(arrayListOfProductIds, new ISkuDetailsResponseListener());
bp.getSubscriptionListingDetailsAsync(arrayListOfProductIds, new ISkuDetailsResponseListener());

where arrayListOfProductIds is a ArrayList<String> containing either IDs for products or subscriptions.

Getting Purchase Info Details

PurchaseInfo object is passed to onProductPurchased method of a handler class. However, you can always retrieve it later calling these methods:

bp.getPurchaseInfo("YOUR PRODUCT ID FROM GOOGLE PLAY CONSOLE HERE");
bp.getSubscriptionPurchaseInfo("YOUR SUBSCRIPTION ID FROM GOOGLE PLAY CONSOLE HERE");

As a result you will get a PurchaseInfo object with the following info included:

public final String responseData;
public final String signature;

// PurchaseData contains orderId, productId, purchaseTime, purchaseToken, purchaseState and autoRenewing fields 
public final PurchaseData purchaseData;

Handle Canceled Subscriptions

Call bp.getSubscriptionPurchaseInfo(...) and check the purchaseData.autoRenewing flag. It will be set to False once subscription gets cancelled. Also notice, that you will need to call periodically bp.loadOwnedPurchasesFromGoogleAsync() method in order to update subscription information

Promo Codes Support

You can use promo codes along with this library. Promo codes can be entered in the purchase dialog or in the Google Play app. The URL https://play.google.com/redeem?code=YOUR_PROMO_CODE will launch the Google Play app with the promo code already entered. This could come in handy if you want to give users the option to enter a promo code within your app.

Protection Against Fake "Markets"

There are number of attacks which exploits some vulnerabilities of Google's Play Market. Among them is so-called Freedom attack: Freedom is special Android application, which intercepts application calls to Play Market services and substitutes them with fake ones. So in the end attacked application thinks that it receives valid responses from Play Market.

In order to protect from this kind of attack you should specify your merchantId, which can be found in your Payments Merchant Account. Selecting Settings->Public Profile you will find your unique merchantId

WARNING: keep your merchantId in safe place!

Then using merchantId just call constructor:

public BillingProcessor(Context context, String licenseKey, String merchantId, IBillingHandler handler);

Later one can easily check transaction validity using method:

public boolean isValidPurchaseInfo(PurchaseInfo purchaseInfo);

P.S. This kind of protection works only for transactions dated between 5th December 2012 and 21st July 2015. Before December 2012 orderId wasn't contain merchantId and in the end of July this year Google suddenly changed orderId format.

Proguard

The necessary proguard rules are already added in the library. No further configurations are needed.

The contents in the consumer proguard file contains:

-keep class com.android.vending.billing.**

License

Copyright 2021 AnjLab

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.

Contributing

  1. Fork it
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create New Pull Request

android-inapp-billing-v3's People

Contributors

allanwang avatar andretietz avatar ardovic avatar autonomousapps avatar cutelyaware avatar dfcarvalho avatar dmitrygusev avatar gaborauth avatar ivanovpv avatar jcdom avatar lopper avatar medetzhakupov avatar moni890185 avatar omerfarukyilmaz avatar paulwoitaschek avatar pyro979 avatar razvanws avatar renedecandido avatar rikurb8 avatar rishabhtayal avatar sadafrasheed avatar saqsun avatar sembozdemir avatar serggl avatar serveravt avatar syndarin avatar thomas-vos avatar tonyp avatar ustark avatar yukuku avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

android-inapp-billing-v3's Issues

Subscription is not cached

Hi There,

Thank you for your work on this library. While testing this library, I found an error - cachedSubscriptions cache has no data if the subscription is successful. only purchased product is cached via cachedProducts.put(productId, purchaseToken);

Thanks,
Daniel

bp.isPurchased(product_id) works only on reinstalling the app

First i want to say this library is GREAT, thank you very much for it!

I just have one problem, when the user makes the payment he has to delete the app and install it again in order to get

bp.isPurchased(product_id) == TRUE

is there something i have to delete or modify to get "bp.isPurchased(product_id)" to TRUE without reinstalling the app?

Love it but?

Fantastic library, extremely useful, however how might i go about extending it to consume purchases?

Error code 102

I`m trying to buy android.test.purchased (test product from google). And get error 102.
Here is my code:

@OverRide
public void onBillingInitialized() {

    billingProcessor.consumePurchase("android.test.purchased");
    billingProcessor.purchase(this, "android.test.purchased");
}

@Override
public void onProductPurchased(String productId, TransactionDetails details) {

    Toast.makeText(this, "onProductPurchased", Toast.LENGTH_LONG).show();
}

@Override
public void onBillingError(int errorCode, Throwable error) {
    Toast.makeText(this, "Error code = " + errorCode, Toast.LENGTH_LONG).show();
}

IsPurchased() question in a second (other) Activity is always false

Hi,
I have a issue with the billing library. I have an activity where you can purchase a product. The activity name is "InAppBillingActivity". That's worked very fine. You can purchase a product and if you start this screen again it tells you that you have purchased this product (like described in the example).
But normally you start this screen only one time. Only to buy the product.
Now I want to ask Google in my standard startscreen "MainActivity" if this product is purchased. The result of bp.isPurchased(PRODUCT_ID) iin the MainActivity is always "false". What do I wrong.????
Is it because I have different context's ? How can I solve this problem?

Thanks for your help

Tom

The InAppBillingActivity where you can buy the product:

    bp = new BillingProcessor(this,  LICENSE_KEY, new BillingProcessor.IBillingHandler() {
        @Override
        public void onProductPurchased(String productId) {
            // Schreibe LoginInfos in DB, wer hat wann zuletzt WatchGEOFriends gestartet
            new StoreInAppBillingData(InAppBillingActivity.this, productId, Defaults.PROGRAMMNAME,_sp.getSharedPrefs(InAppBillingActivity.this, Defaults.PROGRAMMNAME, "GCNickName", "")).execute();
            _sp.saveSharedPrefs(InAppBillingActivity.this, Defaults.PROGRAMMNAME, "InAppProduct", Defaults.IN_APP_BILLING_PRODUCT_ID_1.toUpperCase());
            updateTextViews();
        }
        @Override
        public void onBillingError(int errorCode, Throwable error) {
        }
        @Override
        public void onBillingInitialized() {
            readyToPurchase = true;
            updateTextViews();
        }
        @Override
        public void onPurchaseHistoryRestored() {
            for(String sku : bp.listOwnedProducts())
                Log.d(LOG_TAG, "Owned Managed Product: " + sku);

            updateTextViews();
        }
    });

In my MainActivity I have following Code to ask if the product is purchased:

  bp = new BillingProcessor(this,  LICENSE_KEY, new BillingProcessor.IBillingHandler() {
        @Override
        public void onProductPurchased(String productId) {
        }
        @Override
        public void onBillingError(int errorCode, Throwable error) {
        }
        @Override
        public void onBillingInitialized() {
            if(bp.isPurchased(PRODUCT_ID))
            {   
                adView.setVisibility(View.GONE);
            }
            else
            {
             // Look up the AdView as a resource and load a request.
                adRequest = new AdRequest.Builder().build();
                adView.loadAd(adRequest);
            }
        }

Freezes then jumps into the Google Play window.

I'm not sure if this is suppose to be supported but when opening the Google Play window the app originally pauses. Might be an issue with threads.

Do you have an suggestions on using the app with threads if this is the case?

Getting Purchase History

I have my system setup like the example
bp = new BillingProcessor(this,PublicKey,new BillingProcessor.IBillingHandler()
{

        @Override
        public void onBillingError(int arg0, Throwable arg1) {
            // TODO Auto-generated method stub
            showToast("Billing Error");
            dialog();
        }

        @Override
        public void onBillingInitialized() {
            // TODO Auto-generated method stub
            showToast("Billing Intialized");

            if(bp.loadOwnedPurchasesFromGoogle() == true)
            {
                showToast("Items Loaded");

            }

        }

        @Override
        public void onProductPurchased(String arg0) {
            // TODO Auto-generated method stub
            showToast("Product");

        }

        @Override
        public void onPurchaseHistoryRestored() {
            // TODO Auto-generated method stub
            showToast("Restored");
            if(bp.isPurchased("sku_upgrade"))
            {
                FV.setFullVersion(0);
                showToast("Owned");

            }else
            {
                FV.setFullVersion(1);
                showToast("Not Owned");
            }
        }


    });
}

The problem is bp.loadOwnedPurchasesFromGoogle is never calling onPurchaseHistoryRestored()

Strange behavior using isPurchased() in onCreate method

public void onCreate(Bundle savedInstanceState) {
...
bp = new BillingProcessor(this, license_key, null);
...
// If i try to check directly in the onCreate method it doesn't work
// Is like the bp object is not initialized or something
if (bp.isPurchased(product_id)) {. }
...
// However if i try to do it in a button inside
// the onCreate method it works perfectly!
btn = (Button) findViewById(R.id.btn);
btn.setOnClickListener(new OnClickListener() {

    @Override
    public void onClick(View v) {
        // This works!!
        if (bp.isPurchased(product_id)) {  }
    }

});
...

}

I know i should use threads, etc, but this should work, doesn't it? I mean even using it on the onCreate method the main thread should stop on the "bp = new BillingProcessor(this, license_key, null);" until it gets initialized and then continue with the code...

First time not getting any call back after purchsing product. and while purchasing second time its showing ALREADY_OWNED

Hi,
This library is very helpful to me. Thanks ๐Ÿ‘

But i am facing one issue. Purchase dialog is showing with correct products and price and all.
After buying product m nt getting callback in (i m following the same code which u have submitted callback in IBillingHandler at the time of creating instance of the BillingProcessor)
(1)At first time when user is purchasing product
int response = bundle.getInt(Constants.RESPONSE_CODE); in billing processor responce = BILLING_RESPONSE_RESULT_OK & invoking startIntentSenderForResult but m not getting any callback like IBillingHandler#onProductPurchased or IBillingHandler#onBillingError
(2)And Second time if user try to purchase same product its showing ALREADY OWN

So what can be the issue from my side that its not giving callback at first attempt ..
Thanks

Transaction ID after a purchase

Wouldn't it be nice to extend the Method "onProductPurchased(String sku)" to "onProductPurchased(String sku, String transactionID)"?

My case:
You buy ingame credits in my app.
Theory:
So I purchase an item, wait for "onProductPurchased" and tell my server that the user gets 100 credits more. After that I consume that item, to let the user buy that item again.

Usecase:
When the user buys the item, I get "onProductPurchased" and now the connection is lost. In that case I can wait till the connection is there again, check if the user has some unconsumed items, tell my server to add the credits and then consume them.
My server does not know, if the user got those credits already, cause there's no unique identifier. So in theory, he could stop the app (however he'll do that) before consuming (and after he got he credits from my server). Then restart the app get coins for free, because I will check for not consumed items and tell my server to give him more credits.
If the user repeats that, it would be a big cheat.

If I would have the transactionID I would use this as unique identifier and I could ignore these requests and consume the item.

Get my point?

failed to find com.anjlab.android.iab.v3:library:1.0.13

my build.gradle contains the following

repositories {
    mavenCentral()
}

dependencies {
    compile 'com.anjlab.android.iab.v3:library:1.0.13'
    ...

but I'm always getting failed to find com.anjlab.android.iab.v3:library:1.0.13. It also doesn't work with compile 'com.anjlab.android.iab.v3:library:1.0.+@aar'

Query available items

First of all: Awesome library. Saved me a lot of time.

Not sure if that's possible, but I think so.

A Method to query all available items (sku's) in the play-store.

Key

Frontpage README talks about "Merchant Key" and then in the code snippet it's "License Key". Developer console offers per-app License Key's and Google Wallet offers Merchant Key. Which one is it? Maybe you could also add info on where to get it to the README.

onBillingInitialized() never called

After checking if Google Play Services is available and creating an instance of BillingProcessor some users are reporting that the UI never loads.

The only way this could happen is if "onBillingInitialized" is never called. Is this possible?

Thanks

No Activity found to handle Intent { act=android.intent.action.VIEW dat=market://details?id=com.google.android.gms flg=0x80000 pkg=com.android.vending }

android.content.ActivityNotFoundException: No Activity found to handle Intent { act=android.intent.action.VIEW dat=market://details?id=com.google.android.gms flg=0x80000 pkg=com.android.vending }
at android.app.Instrumentation.checkStartActivityResult(Instrumentation.java:1675)
at android.app.Instrumentation.execStartActivity(Instrumentation.java:1467)
at android.app.Activity._logged_startActivityForResult(Activity.java:3467)
at android.app.Activity.startActivityForResult(Activity.java:3460)
at android.app.Activity._logged_startActivityForResult(Activity.java:3420)
at android.app.Activity.startActivityForResult(Activity.java:3414)
at android.support.v4.app.FragmentActivity.startActivityForResult(SourceFile:840)
at android.app.Activity._logged_startActivity(Activity.java:3702)
at android.app.Activity.startActivity(Activity.java:3691)
at android.app.Activity._logged_startActivity(Activity.java:3662)
at android.app.Activity.startActivity(Activity.java:3656)
at com.google.android.gms.dynamic.a$5.onClick(Unknown Source)
at android.view.View.performClick(View.java:4647)
at android.view.ViewRootImpl.performClickHelper(ViewRootImpl.java:910)
at android.view.ViewRootImpl.performClick(ViewRootImpl.java:919)
at android.view.ViewRootImpl$ViewRootHandler.handleMessage(ViewRootImpl.java:3385)
at android.os.Handler.dispatchMessage(Handler.java:122)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5105)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)
at dalvik.system.NativeStart.main(Native Method)

SDK affected
4.2.2
37%
4.4.2
27%
4.1.2
14%
4.1.1
11%
4.4.3
8%
4.0.4
3%
4.3
3%

Add more security

Add an option to verify purchase signature, the same way as Google's IabHelper does.

ArrayIndexOutOfBoundsException: length=2; index=2 at BillingCache:57

sometimes if I don't consume the purchased consumable, the next time I'm doing

bp = new BillingProcessor(this, null, this);

I'm getting the following Exception:

     Caused by: java.lang.ArrayIndexOutOfBoundsException: length=2; index=2
            at com.anjlab.android.iab.v3.BillingCache.load(BillingCache.java:57)
            at com.anjlab.android.iab.v3.BillingCache.<init>(BillingCache.java:41)
            at com.anjlab.android.iab.v3.BillingProcessor.<init>(BillingProcessor.java:93)

Seems like loadOwnedPurchasesFromGoogle doesn't work

Hey, thank you developing that useful library.

I've problem with loadOwnedPurchasesFromGoogle function. Consider that user has paid app with in-app billing and I've save that user has bought app and unlock all the features. On every loading of app i check loadOwnedPurchasesFromGoogle and isPurchased both but if the user cancels his payment loadOwnedPurchasesFromGoogle and isPurchased still returns true? What's the main problem?

in MainActivity

   bp = new BillingProcessor((Activity) context,
            context.getString(R.string.key),
            new IBillingHandler() {

        @Override
        public void onPurchaseHistoryRestored() {
        }

        @Override
        public void onProductPurchased(String productId, TransactionDetails details) {
            android.util.Log.d("onProductPurchased: ", productId);
        }

        @Override
        public void onBillingInitialized() {
            boolean loadOwnedPurchasesFromGoogle = bp.loadOwnedPurchasesFromGoogle();
            if (loadOwnedPurchasesFromGoogle) {
                if (bp.isPurchased(Constants.PRODUCT_ID)) {
                    Toast.makeText(context, "Product is already purchased", Toast.LENGTH_LONG).show();
                    PreferenceHelper.setProVersion(context, true);
                }else  PreferenceHelper.setProVersion(context, false);
            }
        }

        @Override
        public void onBillingError(int errorCode, Throwable error) {
            android.util.Log.d("onBillingError: ", Integer.toString(errorCode));
        }
    });

Purchase data is unavailable

Hello!

Great work, thank you!

I get a little problem with it, when I want to send data of the purchase to my own server. There is no method which return INAPP_PURCHASE_DATA and INAPP_DATA_SIGNATURE content. May be add it as a parameter of onProductPurchased()? Or as a separate methods...

At now I just save it in a onActivityResult() and than use it in a onProductPurchased():

private Intent mData;

@Override
public void onProductPurchased(String productId) {
    if(mData!=null) {
        mData.getStringExtra("INAPP_PURCHASE_DATA");
        mData.getStringExtra("INAPP_DATA_SIGNATURE");
    }
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    mData=data;
    if (!bp.handleActivityResult(requestCode, resultCode, data)) super.onActivityResult(requestCode, resultCode, data);
}

But I think, that is not is a best way.

Activity Result Fragment Index Out Of range

Im using in a Fragment, and i get this error Activity Result Fragment Index Out Of range so in success purchase does not trigger, if the user "click" again it triggers but not after "buying"

Didn't get correct errorcode from Google in onBillingError

Hi,

we didn't get the correct errormessage from Google in the onBillingError method.
We tested it with a not exixting subscription. onBillingError gave us always the BILLING_ERROR_OTHER_ERROR = 110 back.
Shouldn't it be "Requested product is not available for purchase" ( ResponseCode=4) ?

Is it a bug?

Thx

Tom

BillingProcessor NullPointerException

Using inapp-billing version 1.0

    compile 'com.anjlab.android.iab.v3:library:1.0.+@aar'
java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=2061984, result=0, data=null} to activity {com.utopia.musicoff/com.utopia.musicoff.MainActivity}: java.lang.NullPointerException
       at android.app.ActivityThread.deliverResults(ActivityThread.java:3368)
       at android.app.ActivityThread.handleSendResult(ActivityThread.java:3411)
       at android.app.ActivityThread.access$1300(ActivityThread.java:138)
       at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1247)
       at android.os.Handler.dispatchMessage(Handler.java:102)
       at android.os.Looper.loop(Looper.java:136)
       at android.app.ActivityThread.main(ActivityThread.java:5050)
       at java.lang.reflect.Method.invokeNative(Method.java)
       at java.lang.reflect.Method.invoke(Method.java:515)
       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:602)
       at dalvik.system.NativeStart.main(NativeStart.java)
Caused by: java.lang.NullPointerException
       at com.anjlab.android.iab.v3.BillingProcessor.handleActivityResult(BillingProcessor.java:297)
       at com.utopia.musicoff.activities.BaseBillingActivity.onActivityResult(BaseBillingActivity.java:107)
       at android.app.Activity.dispatchActivityResult(Activity.java:5423)
       at android.app.ActivityThread.deliverResults(ActivityThread.java:3364)
       at android.app.ActivityThread.handleSendResult(ActivityThread.java:3411)
       at android.app.ActivityThread.access$1300(ActivityThread.java:138)
       at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1247)
       at android.os.Handler.dispatchMessage(Handler.java:102)
       at android.os.Looper.loop(Looper.java:136)
       at android.app.ActivityThread.main(ActivityThread.java:5050)
       at java.lang.reflect.Method.invokeNative(Method.java)
       at java.lang.reflect.Method.invoke(Method.java:515)
       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:602)
       at dalvik.system.NativeStart.main(NativeStart.java)

iabv3๏น• resultCode = 0, responseCode = 2

I am getting "Authentication is required. You need to sign in to your Google Account."
I have uploaded a Alpha apk to play and added the required items to the developer account.

I have tried this on two different devices, both only with one google account setup.

FYI: Remove InAppBillingService.aidl before using this library

Spent about an hour trying to fix why it wouldn't compile until I found the "Multiple Dex declarations" and after google-Fu, i found the issue was having the aidl file installed. This library already has it.

Was tracking down a bunch of funky errors that didn't make sense...

Thought it might help the next soul with this issue.

Cheers

TransactionDetails should be able to return the raw json object

The TransactionDetails should be able to return the raw json object which you're using in it's constructor.

This is mandatory for validating the purchase from an own server. So if a user buys something, gplay returns smth, this library checks if it is valid or not. If I want to inform our server that, the user purchased something, I need the raw json object, to verify the purchase again. Otherwise, users could recreate the request to our server and get whatever he wanted to have, without the playstore at all.

So if you could add a method to the transaction details, that return the JsonObject, which you're using to parse the details out of it.

NullPointerException

java.lang.NullPointerException
       at com.anjlab.android.iab.v3.BillingBase.getPreferencesBaseKey(BillingBase.java:37)
       at com.anjlab.android.iab.v3.BillingProcessor.isPurchaseHistoryRestored(BillingProcessor.java:352)
       at com.anjlab.android.iab.v3.BillingProcessor.access$100(BillingProcessor.java:38)
       at com.anjlab.android.iab.v3.BillingProcessor$1.onServiceConnected(BillingProcessor.java:78)
       at android.app.LoadedApk$ServiceDispatcher.doConnected(LoadedApk.java:1049)
       at android.app.LoadedApk$ServiceDispatcher$RunConnection.run(LoadedApk.java:1066)
       at android.os.Handler.handleCallback(Handler.java:587)
       at android.os.Handler.dispatchMessage(Handler.java:92)
       at android.os.Looper.loop(Looper.java:132)
       at android.app.ActivityThread.main(ActivityThread.java:4028)
       at java.lang.reflect.Method.invokeNative(Method.java)
       at java.lang.reflect.Method.invoke(Method.java:491)
       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:844)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:602)
       at dalvik.system.NativeStart.main(NativeStart.java)

Test purchases

Any way to test purchases using android.test.purchased with this library? Any mock security verifier? As playstore returns empty RESPONSE_INAPP_SIGNATURE.

Subscription expire date

How can i check if a subscription is expired?
When I call isSubscribed() it always return true, even if user has deleted the subscription.

Null pointer

java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=2061984, result=0, data=null} to activity {com.lovelyhq.android.lovelydocs/com.lovelyhq.android.lovelydocs.controllers.MainActivity}: java.lang.NullPointerException
at android.app.ActivityThread.deliverResults(ActivityThread.java:3351)
at android.app.ActivityThread.handleSendResult(ActivityThread.java:3394)
at android.app.ActivityThread.access$1300(ActivityThread.java:135)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1244)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5001)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:785)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.NullPointerException
at com.anjlab.android.iab.v3.BillingProcessor.boolean handleActivityResult(int,int,android.content.Intent)(:234)
at com.lovelyhq.android.lovelydocs.controllers.MainActivity.void onActivityResult(int,int,android.content.Intent)(:527)
at android.app.Activity.dispatchActivityResult(Activity.java:5423)
at android.app.ActivityThread.deliverResults(ActivityThread.java:3347)
... 11 more

Support extending Application singleton

Hi, nice library & nice work! We use a design pattern where various billing functions are handled from within the Application singleton. Is there any reason you've chosen to initialize within an Activity context?

The workaround is to add a callback from the MainActivity to the Application and then implement BillingProcessor from the Application, but it's a hack. Any recommendations?

    // Initialize android-inapp-billing-v3 from within the Main Activity onCreate() method
    MyApplication myApp = (MyApplication)getApplication();
    myApp.initBillingOnMainActivity(this);

Billing was not init yet

I only change
bp.verifyPurchasesWithLicenseKey("MY_KEY");
I get MY_KEY from SERVICES & APIS => YOUR LICENSE KEY FOR THIS APPLICATION
But i always got alert "Billing was not init yet".

plez help me :(

Library are working perfectly, but is not protected from the application of freedom app

Please explain to me how I can protect the application from hacker

Thank you

Developer payload

How to set developerPayload with your library? It's very important security feature but i can't find the way to use it in README, is it missing from your library?

Licence?

Hello there,

what's the licence? Can you add a licence file to the repo? :)

Cheers.

Nullpointer when creating BillingProcessor

Everything works as it should when I compile and run my apk, but once I generate the signed apk and run that I always get the following error when I initialize the BillingProcessor:

java.lang.NullPointerException
        at re.getPreferencesBaseKey(SourceFile:36)
        at rf.c(SourceFile:41)
        at rf.d(SourceFile:45)
        at rf.<init>(SourceFile:37)
        at com.anjlab.android.iab.v3.BillingProcessor.<init>(SourceFile:88)
        at net.steamcrafted.craftable2.app.act.MainActivity.setupAds(SourceFile:325)
        at net.steamcrafted.craftable2.app.act.MainActivity.onCreate(SourceFile:207)
        at android.app.Activity.performCreate(Activity.java:5241)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1087)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2169)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2265)
        at android.app.ActivityThread.access$800(ActivityThread.java:145)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1206)
        at android.os.Handler.dispatchMessage(Handler.java:102)
        at android.os.Looper.loop(Looper.java:136)
        at android.app.ActivityThread.main(ActivityThread.java:5081)
        at java.lang.reflect.Method.invokeNative(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:515)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:781)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
        at de.robv.android.xposed.XposedBridge.main(XposedBridge.java:132)
        at dalvik.system.NativeStart.main(Native Method)

NullPointerException at BillingProcessor line 84

I just implemented this library and uploaded my app. Crashlytics is now reporting issues:

Device: SM-N910F (Note 4)
Android: 4.4.4
Rooted: No

Device: C6603
Android: 4.4.4
Rooted: No

java.lang.NullPointerException
at com.anjlab.android.iab.v3.BillingProcessor$1.onServiceConnected(SourceFile:84)
at android.app.LoadedApk$ServiceDispatcher.doConnected(LoadedApk.java:1105)
at android.app.LoadedApk$ServiceDispatcher$RunConnection.run(LoadedApk.java:1122)
at android.os.Handler.handleCallback(Handler.java:733)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:146)
at android.app.ActivityThread.main(ActivityThread.java:5748)
at java.lang.reflect.Method.invokeNative(Method.java)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1291)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1107)
at dalvik.system.NativeStart.main(NativeStart.java)

How could this happen even though line 83 checks if (eventHandler != null) ?

Btw. I'm using ProGuard (DexGuard) and I initialize the BIllingProcessor in onCreate of the MainAcitivity like this:

        bp = new BillingProcessor(this, keyString, new BillingProcessor.IBillingHandler() {
            @Override
            public void onProductPurchased(String productId, TransactionDetails details) {
            ...

Missing 'Item already owned dialog'?

I think it may have been a problem with the original IAB v3 code? Are you aware of this?

If an item is already owned the dialog is never shown and on purchase complete is fired every time.

NullPointerException

Bug found in Android 2.3.6, Samsung Galaxy S2 mini GT-S6500D after BillingProcessor initialization. I was unable to reproduce it on other devices.

01-05 14:36:56.859: E/AndroidRuntime(16059): FATAL EXCEPTION: main
01-05 14:36:56.859: E/AndroidRuntime(16059): java.lang.NullPointerException
01-05 14:36:56.859: E/AndroidRuntime(16059): at com.anjlab.android.iab.v3.BillingBase.getPreferencesBaseKey(BillingBase.java:37)
01-05 14:36:56.859: E/AndroidRuntime(16059): at com.anjlab.android.iab.v3.BillingProcessor.isPurchaseHistoryRestored(BillingProcessor.java:352)
01-05 14:36:56.859: E/AndroidRuntime(16059): at com.anjlab.android.iab.v3.BillingProcessor.access$100(BillingProcessor.java:38)
01-05 14:36:56.859: E/AndroidRuntime(16059): at com.anjlab.android.iab.v3.BillingProcessor$1.onServiceConnected(BillingProcessor.java:78)
01-05 14:36:56.859: E/AndroidRuntime(16059): at android.app.LoadedApk$ServiceDispatcher.doConnected(LoadedApk.java:1064)
01-05 14:36:56.859: E/AndroidRuntime(16059): at android.app.LoadedApk$ServiceDispatcher$RunConnection.run(LoadedApk.java:1081)
01-05 14:36:56.859: E/AndroidRuntime(16059): at android.os.Handler.handleCallback(Handler.java:587)
01-05 14:36:56.859: E/AndroidRuntime(16059): at android.os.Handler.dispatchMessage(Handler.java:92)
01-05 14:36:56.859: E/AndroidRuntime(16059): at android.os.Looper.loop(Looper.java:130)
01-05 14:36:56.859: E/AndroidRuntime(16059): at android.app.ActivityThread.main(ActivityThread.java:3768)
01-05 14:36:56.859: E/AndroidRuntime(16059): at java.lang.reflect.Method.invokeNative(Native Method)
01-05 14:36:56.859: E/AndroidRuntime(16059): at java.lang.reflect.Method.invoke(Method.java:507)
01-05 14:36:56.859: E/AndroidRuntime(16059): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:878)
01-05 14:36:56.859: E/AndroidRuntime(16059): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:636)
01-05 14:36:56.859: E/AndroidRuntime(16059): at dalvik.system.NativeStart.main(Native Method)

BTW. Great library, thanks for developing it ;-).

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.