Skip to main content

I’m not having any luck getting in-app purchases to work in Android (everything is working fine in iOS).  I followed these directions https://www.revenuecat.com/docs/google-play-store as best I could, but there are parts of them that don’t make any sense to me, and now when I try to make a test purchase, I get the error message, “This version of the application is not configured for billing through Google Play. Check the help center for more information.”

For reference, I am developing using React Native and a custom Expo dev client built remotely using the EAS Build service.  I don’t know the first thing about developing using Java/Android Studio or trying to build locally.  I have gotten as far as setting up a test product in Google Play, importing it into RevenueCat, and retrieving info about that product in my app code.  This leads me to believe that the product is set up correctly.  I am also sure that my user account on the physical device is included in the list of testers for Closed Testing, and I have had that user visit the tester sign up link and “accept.”  My trouble occurs when my code tries to call  Purchases.purchaseStoreProduct().

Here are the bits that I don’t understand from the documentation:

https://www.revenuecat.com/docs/google-play-store#upload-a-signed-apk-to-the-closed-track

Generate a signed APK or use Android App Bundle to upload a signed APK to the alpha track you just created. You don’t even need to roll out the release. Just upload the APK.

So, if I upload a newly built version of my Android app to the Closed Testing track, then what?  How do I test that build and make updates to the code?  How do I see console.log output so I can debug what’s going on inside it?

Before you can make a purchase, make sure your release has been approved and available.

Well, I uploaded a new build, but it never got approved.  It still says, “Ready to send for review.”  I am afraid to submit it for review because I don’t want this build to get released to live users.  I’m still trying to test purchases and their is a lot of half-finished code in this build.

Build and run your app on your test device (you don't need to sign it). You should be able to complete all purchases.

So, I’m supposed to install the build on my test device and test purchases using that?  Again, I ask how am I meant to see console output and make code adjustments if I’m using a finished build rather than my Expo dev client?  If the purchase doesn’t work on the finished build, I’ll have no clue why, or what to change.

Can someone make sense of this for me, please?

Thanks!

same… It works yesterday on emulator, but not working this afternoon


Hey @Mike Davis,

Well, I uploaded a new build, but it never got approved.  It still says, “Ready to send for review.”  I am afraid to submit it for review because I don’t want this build to get released to live users.  I’m still trying to test purchases and their is a lot of half-finished code in this build.

I want to address this first - as long as your release is in a closed test track, this would never be released to live users. This is a testing track specifically for pre-release versions of your app, available only to the small group of test users that you specifically invite. You don’t have to worry about this build suddenly be available on the Play Store or anything like that. 

The error that you’re getting (and @yusunglee-57728e, if you’re getting the same one) is the error that we see either if the release is not approved and published, or if you’re attempting to access a closed test track with a user that is not a licensed test user. So that does seem expected in the scenario that you’ve described. You’ll want to upload your latest build to your closed test track, have the release approved, and then I’d recommend utilizing Android Studio over console.log - as an IDE, it plays more nicely with debug logs and ongoing code adjustments as you’re testing. We have a quick guide on how to open a project for the first time in Android Studio here, and I’m also happy to answer any questions you may have in the process.


Thanks for your response, @kaitlin!

Since I am used to developing in an Expo managed workflow for React Native and just sending debug info to the terminal using console.log, I had to do some googling to figure out how to do a local Android build and use Android Studio to see the debug output.  The doc that you linked to offered some clues, but only part of the picture for someone with my level of Android-specific experience.  In any case, I eventually got it working and here’s what I discovered…
When the app first loads, I get these error messages:

Error connecting to billing client to display in-app messages: PurchasesError(code=UnknownError, underlyingErrorMessage=BillingWrapper is not attached to a listener, message='Unknown error.')

😿‼️ Error fetching offerings - PurchasesError(code=ConfigurationError, underlyingErrorMessage=There are no products registered in the RevenueCat dashboard for your offerings. If you don't want to use the offerings system, you can safely ignore this message. To configure offerings and their products, follow the instructions in https://rev.cat/how-to-configure-offerings.

                                                                                                    More information: https://rev.cat/why-are-offerings-empty, message='There is an issue with your configuration. Check the underlying error for more details.')

I am in fact not using offerings for this version of the app, so this last one I guess can be safely ignored.

When the user attempts to make a purchase, I first get some DEBUG output, including this line, which leads me to believe that the product info is being retrieved correctly:

💰 Purchase started - product:  InAppProduct(productId=yd_course_test_course_v1, productDetails=ProductDetails{jsonString='{"productId":"yd_course_test_course_v1","type":"inapp","title":"Test Course 1 (Your Daily™️)","name":"Test Course 1","description":"A sample course being used to test course purchases in the Your Daily app.","localizedIn":""en-US"],"skuDetailsToken":"AEuhXXXXXXXXXXXXXXXXXXXXXXXXXXXXX","oneTimePurchaseOfferDetails":{"priceAmountMicros":990000,"priceCurrencyCode":"USD","formattedPrice":"$0.99"}}', parsedJson={"productId":"yd_course_test_course_v1","type":"inapp","title":"Test Course 1 (Your Daily™️)","name":"Test Course 1","description":"A sample course being used to test course purchases in the Your Daily app.","localizedIn":""en-US"],"skuDetailsToken":"AEuhXXXXXXXXXXXXXXXXXXXXXXXXXXXXX","oneTimePurchaseOfferDetails":{"priceAmountMicros":990000,"priceCurrencyCode":"USD","formattedPrice":"$0.99"}}, productId='yd_course_test_course_v1', productType='inapp', title='Test Course 1 (Your Daily™️)', productDetailsToken='AEuhXXXXXXXXXXXXXXXXXXXXXXXXXXXXX', subscriptionOfferDetails=null}) null

The above line is immediately followed by this error:

Error connecting to billing client to display in-app messages: PurchasesError(code=UnknownError, underlyingErrorMessage=BillingWrapper is not attached to a listener, message='Unknown error.')

At this point, the UI is showing the Android error dialog that’s pictured in the screenshot in my initial post.  Once the user dismisses it, I get these:

🤖‼️ BillingWrapper purchases failed to update: DebugMessage: Please ensure the app is signed correctly.. ErrorCode: DEVELOPER_ERROR.null

🤖‼️ PurchasesError(code=PurchaseInvalidError, underlyingErrorMessage=Error updating purchases. DebugMessage: Please ensure the app is signed correctly.. ErrorCode: DEVELOPER_ERROR., message='One or more of the arguments provided are invalid.')

My code to configure the SDK looks like this (this segment runs when the app first loads):

Purchases.configure({

    apiKey: ‘goog_XXXXXXXXXXXXXXXXXX’

});

And then, once the user is authenticated, this segment runs:

const purchasesLogin = await Purchases.logIn(uid);

The code to make the purchase looks like this:

const purchaseInfo = await Purchases.getProducts(nmy_product_id], 'inapp');

/* (…some code to extract the correct product info object from the array returned in the above statement) */

const purchaseResult = await Purchases.purchaseStoreProduct(purchaseInfo);

Does this give you enough info to diagnose my issue?  If you need more, just let me know.  Now that I know how to get this additional debug output, I’m happy to get you whatever you need.

THANKS!


I should also mention what’s happening with my current build situation: I submitted (and Google approved) a build to Closed Testing in the Google Play Store.  But I don’t know if or how I am supposed to run and debug with that build on my test device.  The debug info that I posted in my previous comment is all from running an ad hoc build on my local machine, not the build that was submitted.

I still don’t understand how submitting the build to Closed Testing is related to running an ad hoc build in my development environment.  Is submitting any old build supposed to somehow magically unlock something?  Something related to the test user maybe?  Does the build in CLosed Testing need to have the same build number as what I’m running in the dev environment?


OK, I got this solved, with some help from @kaitlin.

She pointed me to the very helpful blog article: https://www.revenuecat.com/blog/engineering/the-ultimate-guide-to-android-subscription-testing/

In that article, I discovered the one missing piece of my puzzle - I had not realized that I needed to set up a user in what Google calls “License Testing” (https://support.google.com/googleplay/android-developer/answer/6062777?hl=en). Once I did this, and waited a little while for propagation, I got the expected Google Pay purchase dialog instead of the error message pictured in my initial post.  And then once I clicked to complete the purchase, the return data that I got from calling Purchases.purchaseStoreProduct() was also as expected.

I now see that there are instructions for setting up License Testing in https://www.revenuecat.com/docs/google-play-store.  I’m not sure why I didn’t see them or understand them during my initial setup.  Maybe because Google’s terminology is so cluttered that everything that they name sounds almost the same as something else they’ve named, and I got confused between License Testing and setting up users in Closed Testing.  Anyway, for anyone reading this who encounters a similar error, setting up License Testing is in fact a separate and very important part of the process, it tuns out.


I came across this issue right now and wanted to add another data point for what worked for me.

As @Mike Davis said above, I was missing the “License Testing” step from the docs here.

I already had email lists for the Closed Track testing and on the Settings → License testing screen I had to select a email group and click save on the bottom right for it to take effect. Once I did that, I was able to see the subscription modal in my app.

 

 


@monte, glad you got it working.  Hope my comments helped!


Reply