Git Product home page Git Product logo

play-billing-samples's Introduction

Google Play Billing Samples

Sample applications for Google Play Billing. To build each sample, see the README instructions in the project directory.

  • [Last Updated: May 2021] Trivial Drive Java - Purchase items/subscriptions in your Android app (serverless).
  • [Last Updated: May 2021] Trivial Drive Kotlin - Purchase items/subscriptions in your Android app (serverless).
  • [Last Updated: May 2023] Classy Taxi Kotlin App - Purchase subscriptions and one-time products in your Android app and manage them on your server.
  • [Last Updated: March 2022] Classy Taxi Java App - Purchase subscriptions in your Android app and manage subscriptions on your server.
  • [Last Updated: May 2023] Classy Taxi Server - Manage subscriptions and one-time products on your server.

Google Play Billing

For more information about Google Play Billing, see the documentation.

CHANGELOG

  • 2023-05-23
    • Updated Classy Taxi Kotlin sample to Google Play Billing Library v6.
    • Implemented consumable one-time products into the Classy Taxi Kotlin sample.
  • 2022-05-11
    • Updated Classy Taxi Kotlin sample to Google Play Billing Library v5.
  • 2021-05-18
    • Updated all samples for Google Play Billing Library v4.
  • 2021-04-28
    • Publish TrivialDriveJava : Billing Library Java sample for purchases.
    • Rewrite TrivialDriveKotlin : Billing Library Java/Kotlin hybrid sample for purchases, now supports billing ktx/coroutines.
  • 2020-02-28
    • Publish ClassyTaxiJava: Billing Library Java sample - currently only supports subscriptions.
  • 2019-12-30
    • Restructure ClassyTaxi to separate Android, web, and server implementations.
      • The ClassyTaxi Android app now lives here.
      • The ClassyTaxi read-only web app now lives here.
      • The ClassyTaxi server implementation now lives here.
  • 2019-10-10
    • Remove apps that do not support Google Play Billing Library 2.0 or newer. The AIDL and older versions of the Google Play Billing Library are deprecated. The old samples are available on GitHub at the following links:
  • 2019-01-16
    • Publish TrivialDriveKotlin: Kotlin sample
  • 2018-05-03
    • Publish ClassyTaxi: Subscriptions sample
  • 2017-07-12
    • Publish TrivialDrive_v2: Billing Library 1.0 sample
  • 2015-09-18
    • Initial repo port to GitHub
    • TrivialDrive: AIDL sample

play-billing-samples's People

Contributors

3dmg avatar ananthusubramanian avatar andreban avatar calren avatar cartland avatar chiel99 avatar cka-dev avatar codingjeremy avatar cybertron-avneesh avatar dagalpin avatar dependabot[bot] avatar elegyd avatar ggfan avatar gorgon avatar gwpantazes avatar isaidamier avatar keithsmyth avatar khanhlvg avatar kplatfoot avatar krasimiracle avatar mrtcnnccn avatar msfstef avatar olegcherr avatar paulrashidi avatar pfmaggi avatar saryongkang avatar te-tatuonagamatu avatar tjohns avatar trambui09 avatar westarle 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

play-billing-samples's Issues

Memory Leak IabHelper.startSetup()

While using this set of util classes we think we found a memory leak for our use case.


In our use case:
We call mHelper.startSetup(this); from within the onCreate() of our activity. However also within the onCreate() we call setRequestedOrientation(); which may well cause our activity to be quickly destroyed, before the IabHelper.OnIabSetupFinishedListener.onIabSetupFinished(IabResult result) has been called. This means that the IabHelper is holding a reference to our activity in the form of a OnIabSetupFinishedListener past the life time of our activity.

The solution for us was:

  • Add a local field to the IabHelper as follows: OnIabSetupFinishedListener mSetupListener;.

  • Then in the startSetup(OnIabSetupFinishedListener listener) set the reference for this field as follows: mSetupListener = listener;

  • Then still within startSetup(OnIabSetupFinishedListener listener) update the mServiceConn to reference the new field instead of listener directly (there are three places this happens).

  • Then in the dispose() method we did mSetupListener = null;.


I am aware this may not suffice as a broader solution because if startSetup() is called more than once then there could still be a memory leak however in our use case we are confident we dont do that.

Hope this helps someone else.

Getting "IAB helper is not set up" even after the setup returns a success

I recently integrated the in-app-billing code into my app and I have some crashes reported in my Crashalytics system saying Fatal Exception: java.lang.IllegalStateException: IAB helper is not set up. Can't perform operation: queryInventory even after the callback for setting it up returns success. Here is my code for setting the IabHelper:

public void setupPayments() {
        mHelper = new IabHelper(MyApplication.applicationInstance,
                Utils.getAppBilllingLicenseKey());
        mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
            @Override
            public void onIabSetupFinished(IabResult result) {
                // Setting is the payment is setup or not ..
                isPaymentsSetup = result.isSuccess();
                if(mSetupListener != null) {
                    mSetupListener.onSetupFinished(result.isSuccess(), result);
                }
            }
        });
    }

On receiving the callback, I perform the following action:

@Override
    public void onSetupFinished(boolean success, IabResult result) {
        if(success) {
            MyApplication.applicationInstance.getmInAppPurchaseUtils()
                    .triggerCheckAdsFreePurchase();
        } else {
            MyApplication.applicationInstance.setmShowAds(true);
            Timber.d("Setting up of the payments was failed. Directly taking to the app");
            checkInternetAndTakeAction();
        }
    }

The code for triggerCheckAdsFreePurchase is:

public void triggerCheckAdsFreePurchase() {
        try {
            mHelper.queryInventoryAsync(mAdsFreeSubscriptionListener);
        } catch (IabHelper.IabAsyncInProgressException e) {
            if(mInventoryAdsFreeSubscriber != null) {
                mInventoryAdsFreeSubscriber.onQueryInventoryException(e);
            }
        }
    }

So, with this code I am getting the Exception: Fatal Exception: java.lang.IllegalStateException: IAB helper is not set up. Can't perform operation: queryInventory. Do I have any errors in my code? If not, I have come across some posts to handle this. This one gives a solution. Is this the only workaround for now?

getContext() from BillingBase is private

Hi,

I am using your library and helped me to add IAB in my android app. I want to use the context to show a progress dialog when I am sending the purchase token to the server. Here is my code:

`
billingProcessor = new BillingProcessor(this, Constants.GOOGLE_LICENCE_KEY, new BillingProcessor.IBillingHandler() {

@OverRide
public void onProductPurchased(String productId, TransactionDetails details) {
progressDialog = ProgressDialog.show(billingProcessor.getContext(), "Loading...", "Subscription...");
...
}
`

Currently billingProcessor.getContext() is private and I was wandering If It can be public.
Or there is another way to access the context in the implementation of onProductPurchased?

This version of the application is not configured for billing through Google Play

I am developing a demo of in-app billing in which i used two manged product and two subscription. Actually Its working till version code 6 and publish 6 builds that all are working but after version code 6 I updated to in-app billing version 3 its not working. Now I got error This version of the application is not configured for billing through Google Play. Check the help center for more information I can not find any solution. is there any setting changes in google developer account from where i published my application???

Please Help me to solve out..

Thanks ..

Crash with null pointer exception after Billing Service gets disconnected

After successful setup and the establishment of a connection to the Billing Service in

IabHelper.startSetup()

The user tries to make an in-app purchase.

IabHelper.launchPurchaseFlow()

gets called which in turn calls methods on mService. But sometimes

IabHelper.onServiceDisconnected()

has been called in the meantime which sets

IabHelper.mService = null

This causes a null pointer exception.

It seems unpredictable when/why this disconnection happens. But I have some pre-launch reports in my developer console as examples.

Would be resolved by:
#46

Your app is using an incorrect implementation of in-app billing

If you are manually invoking the in-app billing service, make sure you are calling Intent.setPackage(“com.android.vending”) on any intents to "com.android.vending.billing.InAppBillingService.BIND".

That's what an email from Google Play says. Cheers.

Response - 1005 : User Cancelled

Hi @ryanseys

I got IabResults : User Canceled. (Response : - 1005 : User Cancelled) is there any solution for that??
When i click on any of the Image like , Buy Gas, Upgrade My Car , Get Infinite Gas. is it any mistake done by me ?

Thanks.

mServices = null in some situations

do {
logDebug("Calling getPurchases with continuation token: " + continueToken);
Bundle ownedItems = mService.getPurchases(3, mContext.getPackageName(),
itemType, continueToken);

IabHelper.queryPurchases (IabHelper.java:840)
IabHelper.queryInventory (IabHelper.java:611)
IabHelper$2.run (IabHelper.java:669)

Crash on IabHelper.startSetup

I got this crash report recently. No idea why it occurs (reported on the play console) :

java.lang.RuntimeException: Unable to start activity ComponentInfo{com.lb.app_manager/com.lb.app_manager.activities.main_activity.MainActivity}: java.lang.NullPointerException: Attempt to invoke interface method 'boolean java.util.List.isEmpty()' on a null object reference
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2595)
at android.app.ActivityThread.access$800(ActivityThread.java:178)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1470)
at android.os.Handler.dispatchMessage(Handler.java:111)
at android.os.Looper.loop(Looper.java:194)
at android.app.ActivityThread.main(ActivityThread.java:5624)
at java.lang.reflect.Method.invoke(Method.java:0)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:959)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:754)
Caused by: java.lang.NullPointerException:
at com.lb.app_manager.utils.inapp_billing.utils.IabHelper.startSetup(IabHelper.java:272)

According to the code (I changed it a bit) , it crashes on this line:
List intentServices = mContext.getPackageManager().queryIntentServices(serviceIntent, 0);

This means that the queryIntentServices() returned null.
It seems you must check if it's null, according to the docs:
https://developer.android.com/reference/android/content/pm/PackageManager.html#queryIntentServices(android.content.Intent, int)

If there are no matching services, an empty list or null is returned.

Here are device stats, if this helps:
image

Owned subscription returns responseCode 6 not 7

When I have subscription and try to buy same subscription, dialog from Google Play show:

You're already subscribed to...
But the responseCode passed in Intent within onActivityResult method is 6.
When I look to Constants:
BILLING_RESPONSE_RESULT_ERROR = 6; //Fatal error during the API action

But it should return: BILLING_RESPONSE_RESULT_ITEM_ALREADY_OWNED = 7; //Failure to purchase since item is already owned

Using promo code results in 'Item Already Owned'

Issue #7 discusses the problem of promo codes and having no developerPayload.

However, even without validation of developerPayload there is an issue in that if you initiate payment from the app but pay with a promo code the workflow results in an 'item already owned' failure in onIabPurchaseFinished. In fact the 'payment' goes through, but the user (and the app itself) don't know that!

I think this is happening 100% of the time, but it possibly depends on whether or not the app is notified of the purchase before the standard purchase flow completes?

More config change bugs: PurchasesUpdatedListener is stored beyond context lifecycle scope

Inside launchBillingFlow, you guys do this:

ResultReceiver chaseResultReceiver =
        new ResultReceiver(mUiThreadHandler) {
            @Override
            protected void onReceiveResult(int responseCode, Bundle resultData) {
                // Here you guys store the BroadcastManager which in turn stores the PurchasesUpdatedListener
                mBroadcastManager.getListener().onPurchasesUpdated(responseCode, purchases);
            }
        };

Then you guys send that stored PurchasesUpdatedListener to the ProxyBillingActivity to be used as a callback. That doesn't work of course if the client context is changed with a rotation for example. So then what happens is the onPurchasesUpdated method gets called on an old context instance which is a memory leak and can cause crashes in the client app.

My proposed solution would be to use the custom action and BroadcastReceiver setup you guys have going. So basically instead of sending that ResultReceiver to the ProxyBillingActivity, you guys would just send a broadcast:

  @Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == REQUEST_CODE) {
        if (resultCode != RESULT_OK || responseCode != BillingResponse.OK) {
            // ...
            LocalBroadcastManager.getInstance(this).sendBroadcast(...)
        }
    }
}

Mirrored on the Google Issue Tracker: https://issuetracker.google.com/issues/63267470.

IabHelper.java does not call getPurchaseHistory()

Trivial Drive is the defacto standard implementation of IAB referenced by the documentation. However it is incomplete since it does not support detecting previously consumed SKUs. Let's suppose you have a group of related items any of which can be purchased multiple times in the same app on the same device but only one of the SKUs in the group have to be purchased to access a specific feature. To allow the user to purchase multiple times, the app has to consume the purchases as they happen. However, once the app has consumed the purchase, IabHelper.queryInventory() no longer returns the SKU in its list.

To solve this, Purchase should be extended to have a mIsConsumed variable and an 'isConsumed()' method to allow the application to determine if the most recent purchase of an item has already been consumed and IabHelper.queryInventory() extended to support the updated Purchase class (e.g. adding a boolean consumed to the method so the caller can decide whether or not they want already consumed items in the results).

MainActivity is calling queryInventoryAsync in onCreate instead of in onResume

Reading official docs for supporting In-app promotions, I read:

To support promotion codes, your app should call the getPurchases() method whenever the app starts or resumes. This simplest approach is to call getPurchases() in your activity's onResume()

To listen for the PURCHASES_UPDATED intent, dynamically create a BroadcastReceiver object and register it to listen for "com.android.vending.billing.PURCHASES_UPDATED". Register the receiver in your activity's onResume()

In the code in this sample, in MainActivity, you are calling getPurchases (queryInventoryAsync), and registering the receiver in onCreate instead of in onResume. So if a promo code is used in Play Store app while the app is open, when the app resumes it won't be notified (because onCreate is not executed).

So, does this sample need to be modified in order to support in-app promotions? (apart from the issue that makes impossible to verify developer payload)

flagStartAsync / flagEndAsync - why not just AsyncTask & SERIAL_EXECUTOR ?

I'm seeing this a lot
Can't start async operation (refresh inventory) because another async operation (refresh inventory) is in progress

flagStartAsync and flagEndAsync are called from different threads, but synchronized does not guarantee order of execution, and they will definitely break if they get called out of order. If you used AsyncTask instead, you wouldn't have to worry about this, everything would just be queued and execute in the proper order.

Please correct me if I am missing something..

Inadequate instructions in the README

Hello,
your README states to test the code by running the APK signed with PRODUCTION certificate. However, this is not adequate. The developer needs to actually go to their Play Developer Console, add email addresses for Closed Alpha Testing, then navigate to the Opt-In URL in the phone's browser:
optin

Then, they need to download the APK from the browser. ONLY THEN can they test this APK.

According to a Google Play Developer expert support chat I just had:

Closed Alpha testing is a way to limit availability of the Alpha release to a list of specific users/testers. Only these testers will be able to access the app via the Opt-In link.
Open Alpha is a way for anyone with the link to access the app.

You really need to update your README to tell developers to take this crucial step. I spent almost a day figuring this nuance out.

Igor

Promo codes breaks remote server verification

Releasing promo codes for in-app purchases will (forever) prevent an app from using remote server purchase verification!

When a promo code is used for an in-app purchase (the PURCHASES_UPDATED intent) it will completely bypass the purchase flow so the app can't supply an "developerPayload", used for remote verification:
http://developer.android.com/google/play/billing/billing_best_practices.html#payload

Later when the app call getPurchases() to get owner products, the purchase data for promo purchases won't contain a "developerPayload" of course, but neither an "orderId", also used for remote verification using the Google Play Developer API:
https://developers.google.com/android-publisher/api-ref/purchases/products

How is an app supposed to verify in-app purchases made with promo codes?

Allowing users to redeem promo codes through the Google Play Store app, thus bypassing the purchase flow, seems like an major oversight which shouldn't be possible.

When purchasing in several devices with the same account, the refresh inventory does not return the correct result

I'm using 2 devices with the same Google account, let's call them Nexus 1 and Nexus 2.

  1. Open the app on Nexus 1
  2. I buy a product on Nexus 1.
  3. Success
  4. Open the app on Nexus 2 (less than 1 minute after)
  5. Buy product
  6. Failed (popup from In App Billing says the the app is already bought)
  7. Refresh inventory -> returns that item without it being marked as bought

I haven't been able to detect that the failed purchase error has the information that the item is already bought (that way I could circunvent this error).

I believe this is some kind of cache on the Play Store that is only refresh a bit after, since eventually it returns the inventory correctly.

I have some logs to prove it, but I don't think they add much value, still if need I can attach them.

Google play blocked my example =\

I followed readme instruction and after publishing on alpha channel my app was blocked.
From email:

Your app is in violation of the intellectual property and impersonation or deceptive behavior provisions of the Content Policy.

If you have the owner’s permission to use this content, please contact our policy support team and attach verifiable and accepted proof of permission.
...

It is sad =\

What is [DF-RPC-01] error code?

Hi,
I am currently developing "upgrading subscription item" function with "getBuyIntentToReplaceSkus()" method.
I query currently purchased items, and I put items' skus list as oldSkus parameter to

IabHelper.launchPurchaseFlow(Activity act, String sku, String itemType, List oldSkus,
int requestCode, OnIabPurchaseFinishedListener listener, String extraData).

I got the error from the google play service dialog says
"Error retrieving information from server. [DF-RPC-01]".

Also I got those logs.

E/Parcel  (  948): java.lang.ClassNotFoundException: com.google.android.finsky.billing.lightpurchase.PurchaseParams
E/Parcel  (  948): 	at java.lang.Class.classForName(Native Method)
E/Parcel  (  948): 	at java.lang.Class.forName(Class.java:308)
E/Parcel  (  948): 	at java.lang.Class.forName(Class.java:272)
E/Parcel  (  948): 	at android.os.Parcel.readParcelableCreator(Parcel.java:2275)
E/Parcel  (  948): 	at android.os.Parcel.readParcelable(Parcel.java:2239)
E/Parcel  (  948): 	at android.os.Parcel.readValue(Parcel.java:2146)
E/Parcel  (  948): 	at android.os.Parcel.readArrayMapInternal(Parcel.java:2479)
E/Parcel  (  948): 	at android.os.BaseBundle.unparcel(BaseBundle.java:221)
E/Parcel  (  948): 	at android.os.BaseBundle.getString(BaseBundle.java:918)
E/Parcel  (  948): 	at android.content.Intent.getStringExtra(Intent.java:5386)
E/Parcel  (  948): 	at com.android.server.am.ActivityStackSupervisor.startActivityLocked(ActivityStackSupervisor.java:1780)
E/Parcel  (  948): 	at com.android.server.am.ActivityStackSupervisor.startActivityMayWait(ActivityStackSupervisor.java:1333)
E/Parcel  (  948): 	at com.android.server.am.ActivityManagerService.startActivityInPackage(ActivityManagerService.java:5281)
E/Parcel  (  948): 	at com.android.server.am.PendingIntentRecord.sendInner(PendingIntentRecord.java:257)
E/Parcel  (  948): 	at com.android.server.am.ActivityManagerService.startActivityIntentSender(ActivityManagerService.java:5079)
E/Parcel  (  948): 	at android.app.ActivityManagerNative.onTransact(ActivityManagerNative.java:262)
E/Parcel  (  948): 	at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:3172)
E/Parcel  (  948): 	at android.os.Binder.execTransact(Binder.java:446)
E/Parcel  (  948): Caused by: java.lang.ClassNotFoundException: Didn't find class "com.google.android.finsky.billing.lightpurchase.PurchaseParams" on path: DexPathList[[directory "."],nativeLibraryDirectories=[/vendor/lib, /system/lib]]
E/Parcel  (  948): 	at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56)
E/Parcel  (  948): 	at java.lang.ClassLoader.loadClass(ClassLoader.java:511)
E/Parcel  (  948): 	at java.lang.ClassLoader.loadClass(ClassLoader.java:469)
E/Parcel  (  948): 	... 18 more
E/Parcel  (  948): 	Suppressed: java.lang.ClassNotFoundException: com.google.android.finsky.billing.lightpurchase.PurchaseParams
E/Parcel  (  948): 		at java.lang.Class.classForName(Native Method)
E/Parcel  (  948): 		at java.lang.BootClassLoader.findClass(ClassLoader.java:781)
E/Parcel  (  948): 		at java.lang.BootClassLoader.loadClass(ClassLoader.java:841)
E/Parcel  (  948): 		at java.lang.ClassLoader.loadClass(ClassLoader.java:504)
E/Parcel  (  948): 		... 19 more
E/Parcel  (  948): 	Caused by: java.lang.NoClassDefFoundError: Class not found using the boot class loader; no stack available
V/ApplicationPolicy(  948): isApplicationStateBlocked userId 0 pkgname com.android.vending

I double checked the skus that I put in and they were correct.
I tried both test google play account and normal account.
Regular subscription works fine as always.

I tested on Samsung SM-N900L, Android 5.0,
Google Play Service 10.0.84 (238-137749526),
Google Play Store 7.3.07.K-all[0][PR].

If anything is needed, please let me know.

Thank you for reading and check for the issue, in advance.

Unable to Upgrade/Downgrade Google Android in-app subscriptions

My problem is that every time I try to Upgrade/Downgrade a subscription calling the method launchPurchaseFlow setting the list of oldSkus, I always receive the error from Google: [DF-RPC-01].

When instead I try to purchase a brand new subscription from scratch (oldSkus list set null), everything works properly.

Anyone that has the same problem?

Service Intent must be explicit

I'm getting this exception:
java.lang.IllegalArgumentException: Service Intent must be explicit: Intent { act=com.android.vending.billing.InAppBillingService.LOCK (has extras) } at android.app.ContextImpl.validateServiceIntent(ContextImpl.java:1711) at android.app.ContextImpl.bindServiceCommon(ContextImpl.java:1810) at android.app.ContextImpl.bindService(ContextImpl.java:1788) at android.content.ContextWrapper.bindService(ContextWrapper.java:539) at com.android.billingclient.api.BillingClientImpl.startConnection(SourceFile:153)

It happens when a user tries to crack the billing system using tools like Freedom and similar. It can be fixed by simply explicitly declaring the package name when sending the intent.

SecurityException: Requires READ_PHONE_STATE in IabHelper

I began to get some crash reposting with this exception

java.lang.SecurityException: Requires READ_PHONE_STATE: Neither user 10088 nor current process has android.permission.READ_PHONE_STATE.
at android.os.Parcel.readException(Parcel.java:1546)
at android.os.Parcel.readException(Parcel.java:1499)
at com.android.vending.billing.IInAppBillingService$Stub$Proxy.getSkuDetails(IInAppBillingService.java:299)
at IabHelper.querySkuDetails(IabHelper.java:939)

Better error handling for devices with no Play Services

Hello,
currently, your app crashes when trying to buy gas on a device which has no Play Services (i.e. Genymotion emulator). This is not user-friendly. I think there should be a DialogFragment or a Toast message to tell the user that they are missing Play Services and that the action cannot be performed. Instead, the following stacktrace currently occurs:

FATAL EXCEPTION: main
Process: com.eazyigz.example.android.trivialdrivesample, PID: 1703
java.lang.IllegalStateException: Could not execute method for android:onClick
at android.view.View$DeclaredOnClickListener.onClick(View.java:4697)
at android.view.View.performClick(View.java:5609)
at android.view.View$PerformClick.run(View.java:22259)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6077)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755)
Caused by: java.lang.reflect.InvocationTargetException
at java.lang.reflect.Method.invoke(Native Method)
at android.view.View$DeclaredOnClickListener.onClick(View.java:4692)
at android.view.View.performClick(View.java:5609) 
at android.view.View$PerformClick.run(View.java:22259) 
at android.os.Handler.handleCallback(Handler.java:751) 
at android.os.Handler.dispatchMessage(Handler.java:95) 
at android.os.Looper.loop(Looper.java:154) 
at android.app.ActivityThread.main(ActivityThread.java:6077) 
at java.lang.reflect.Method.invoke(Native Method) 
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755) 
Caused by: java.lang.IllegalStateException: IAB helper is not set up. Can't perform operation: launchPurchaseFlow
at com.example.android.trivialdrivesample.a.c.a(Unknown Source)
at com.example.android.trivialdrivesample.a.c.a(Unknown Source)
at com.example.android.trivialdrivesample.a.c.a(Unknown Source)
at com.example.android.trivialdrivesample.MainActivity.onBuyGasButtonClicked(Unknown Source)
at java.lang.reflect.Method.invoke(Native Method) 
at android.view.View$DeclaredOnClickListener.onClick(View.java:4692) 
at android.view.View.performClick(View.java:5609) 
at android.view.View$PerformClick.run(View.java:22259) 
at android.os.Handler.handleCallback(Handler.java:751) 
at android.os.Handler.dispatchMessage(Handler.java:95) 
at android.os.Looper.loop(Looper.java:154) 
at android.app.ActivityThread.main(ActivityThread.java:6077) 
at java.lang.reflect.Method.invoke(Native Method) 
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755) 

Fix Android Studio support for IAB

I realize this probably isn't the right place to make this request but I don't know where this request should be directed to.

Android Studio support for IAB is basically non-existent. Users who want to test real-world IAB apps have to leave Android Studio after generating a Signed APK with the same version as that in Google Play and use the command-line to uninstall, install, and enable debugging mode. Only then can Android Studio attach to the waiting debugger. It's incredibly inefficient.

In addition, a complete application has to be registered in Google Play including a published dummy APK to Alpha or Beta and a merchant account set up before IAB can actually be implemented in the application in Android Studio.

The IAB development cycle is, hands-down, the most broken feature in Android Studio.

Unable to query inventory

Hello,
I am unable to query the inventory with your sample. I get this error on every app launch:

Failed to query inventory. IabResult: Error refreshing.

See screenshot.
Igor
device-2016-09-06-122044

IABHelper `queryInventoryAsync` sets `mDisposed` to false before checking it.

If disposeWhenFinished() has set mDisposeAfterAsync to true, queryInventoryAsync will set mDisposed to false when it calls flagEndAsync. It will then test mDisposed and not post the callback.

This could be fixed by not calling flagEndAsync until after the callback has been called, or caching the value of mDisposed from before the call to flagEndAsync.

Simplify removal of IAB test purchases

I realize this probably isn't the right place to make this request but I don't know where this request should be directed to.

Android Developer mode should allow removal/consumption of IAB test purchases from within Settings -> Manage Apps.

The current requirement to modify the app to add a button to consume test purchases and remembering to remove the button prior to publishing is tedious (at best). Being able to select individual test items from the global Settings app to consume them would make this process much more manageable.

getPurchaseHistory() doesn't work

I have troubles getting getPurchaseHistory() to work. The code is as simple as:

Bundle purchaseHistoryBundle = mService.getPurchaseHistory(7, BuildConfig.APPLICATION_ID, "subs", null, new Bundle());

Response I get is BILLING_RESPONSE_RESULT_ERROR = 6

What s wrong with the code?

ProxyBillingActivity prematurely finishes itself on rotation instead of staying around for result

See https://issuetracker.google.com/issues/63266562

Issue converted to markdown:

Here's the bug:

try {
   startIntentSenderForResult(
           pendingIntent.getIntentSender(), REQUEST_CODE, new Intent(), 0, 0, 0);
} catch (IntentSender.SendIntentException e) {
   BillingHelper.logWarn(TAG, "Got exception while trying to start a purchase flow: " + e);
   mResultReceiver.send(BillingResponse.ERROR, null);
   finish(); // <----------- This occurs because the activity was recreated
}

There are two solutions:

  1. Wrap the code above in saved instance null check so if (savedInstanceState == null) { ... }
  2. Do what I've done to fix the bug in my app and don't recreate the activity on rotation by specifying control over the config changes and not doing anything. That's way more efficient and the right way to do it IMO. You guys would replace you manifest entry with the following:
<activity
   android:name="com.android.billingclient.util.ProxyBillingActivity"
   android:configChanges="keyboard|keyboardHidden|screenLayout|screenSize|orientation"
   android:theme="@android:style/Theme.Translucent.NoTitleBar" />

No longer possible to get subscription SKU details with queryInventoryAsync

As of commit 4ee7eb8, queryInventoryAsync cannot retrieve SKU details for subscription products. The reason is that queryInventory now uses the moreSubsSkusargument when querying for ITEM_TYPE_SUBS. Prior to the change, both calls to querySkuDetails used moreItemSkus. Though the new code is correct, it exposes a separate problem, which is that queryInventoryAsync takes only a single list of SKUs to query. It used to be possible to include in that list SKUs for both in-app and subscription purchases, and everything worked (perhaps the service's getSkuDetails method was filtering them?).

I have a patch ready that fixes the problem by adding a moreSubsSkus parameter to queryInventoryAsync and passing it through to queryInventory. I've also cleaned up the signatures of the queryInventory* methods. There were some overrides that didn't make sense, for example: queryInventoryAsync(querySkuDetails, QueryInventoryFinishedListener. The value of the first argument is effectively ignored, because there's no way to actually pass any SKUs to query.

In-app Billing

I would like to ask Kazakhstan Zhuo mobile phone users to the root of the phone or can be purchased inside the google play it, googel paly will not limit the purchase of the root phone it Thank you

IllegalArgumentException: Service not registered

I get a lot of exceptions with the stack trace below. I guess we need to add a null check for mService in line IabHelper.java:330

Caused by java.lang.IllegalArgumentException: Service not registered: com.goseet.a.a.c@420bbdd0
       at android.app.LoadedApk.forgetServiceDispatcher(LoadedApk.java:954)
       at android.app.ContextImpl.unbindService(ContextImpl.java:1566)
       at android.content.ContextWrapper.unbindService(ContextWrapper.java:484)
       at com.goseet.billing.util.IabHelper.dispose(IabHelper.java:330)
       at com.goseet.billing.util.IabHelper.disposeWhenFinished(IabHelper.java:350)
       at com.goseet.videowallpaper.InAppActivity.onDestroy(InAppActivity.java:39)
       at android.app.Activity.performDestroy(Activity.java:5400)
       at android.app.Instrumentation.callActivityOnDestroy(Instrumentation.java:1112)
       at com.lbe.security.service.core.client.b.x.callActivityOnDestroy(Unknown Source)
       at android.app.ActivityThread.performDestroyActivity(ActivityThread.java:3655)
       at android.app.ActivityThread.handleDestroyActivity(ActivityThread.java:3688)
       at android.app.ActivityThread.access$1200(ActivityThread.java:162)
       at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1407)
       at android.os.Handler.dispatchMessage(Handler.java:99)
       at android.os.Looper.loop(Looper.java:153)
       at android.app.ActivityThread.main(ActivityThread.java:5356)
       at java.lang.reflect.Method.invokeNative(Method.java)
       at java.lang.reflect.Method.invoke(Method.java:511)
       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:853)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:620)
       at dalvik.system.NativeStart.main(NativeStart.java)

IInAppBillingService.getBuyIntent return null Bundle

I get some crash reposting with this exception

java.lang.NullPointerException
        at io.vec.util.b.d.a(IabHelper.java:890)
        at io.vec.util.b.d.a(IabHelper.java:478)
        at io.vec.util.b.d.a(IabHelper.java:406)

in this repo, in this method

public void launchPurchaseFlow(Activity act, String sku, String itemType, List<String> oldSkus,
            int requestCode, OnIabPurchaseFinishedListener listener, String extraData)
        throws IabAsyncInProgressException { }

we called

 buyIntentBundle = mService.getBuyIntent(3, mContext.getPackageName(), sku, itemType,
                        extraData);

and buyIntentBundle is null

can you help me?

and I can't reproduce it.

I dont get to test

I have implemented purchase in my owner app, so i read the documentation of google, but when i was trying test using:
*android.test.purchased
*android.test.canceled
*android.test.item_unavailable
i dont get to test, i was analyzing the code, and i identify that the class Securiy inside the method verifyPurchase, it was blocking for test. I proposed the modification this method to use to test.( I already did)

If I am wrong, can you give feedback?,
i hope have helped
Tks.

Trivial Drive in Google Play

Searching for "Trivial Drive" in Google Play turns up some really shady results. Since this application is tied to in-app purchasing and is intended only as an example not for publishing as-is, those apps should not be allowed to persist in Google Play.

This might be a violation of Section 5.5 of the developer agreement which says, "You agree that you will not submit material to Google Play that is copyrighted ... or have permission from their rightful owner to submit the material." Google should not grant permission to publish its own sample IAB Trivial Drive example as-is within the Google Play ecosystem.

IABHELPER crash when activity is destroyed before helper dismissed

I have found adding these two lines fix the problem. Useful if your app is aggresively killing activities for out of memory reasons.

Thoughts?

int queryPurchases(Inventory inv, String itemType) throws JSONException, RemoteException {
        // Query purchases

        // This is a check to see if activity was destroyed before helper is dismissed
        if(mDisposed) return IABHELPER_UNKNOWN_ERROR;
        if(mContext == null) return IABHELPER_UNKNOWN_ERROR;


        logDebug("Querying owned items, item type: " + itemType);
        ...

Non-renewable subscription and tracking

I want to implement a non-renewable subscription in the app. I have two types of subscriptions in my app and when the other will be selected then the previous one must be cancelled but I am not able to find a solution for this.

IabHelper.dispose() can cause crashes in pending async operations

The IabHelper class has a dispose() method that does various cleanup tasks (unbinds the ServiceConnection, nulls out instance fields, etc). This method is intended to be called from the host activity's onDestroy method. IabHelper also includes *Async methods that can perform billing operations on a background thread. However, this combination produces a race condition that can cause runtime crashes. If dispose() is called while an async operation is in progress, the async operation may crash, e.g. because mDisposed is false (IllegalStateException) or mContext is null (NullPointerException).

I've seen crash reports like from my Android app running in production. I fixed the problem in my app by having dispose() check whether an async operation is in progress, and if so, defer the dispose until after it finishes. I've created a similar patch for the android-play-billing sample project.

IabHelper needs unit tests

IabHelper is complicated enough (and frequently enough borrowed) that it needs unit tests to verify that things work correctly and prevent regressions.

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.