I'm trying to implement In-App purchases using 'com.android.billingclient:billing:2.0.3' library.
the app is released in the Internal test track, and have one managed product, and a single tester (another account of mine), I managed to launch a billing flow and buy the product, but I didn't acknowledge or consume the purchase, in spite of this the responseCode is now always ITEM_ALREADY_OWNED , I thought that if the purchase is not acknowledged within 5 minutes (for testers accounts) it will be refunded. why wasn't it ?
the second question is that I'm trying to consume the product so that i can continue the implementation using my only tester account, here's the onPurchasesUpdated function
override fun onPurchasesUpdated(
billingResult: BillingResult?, purchases: MutableList<Purchase>?) {
val resCode=billingResult!!.responseCode
println(resCode) // prints 7 i.e ITEM_ALREADY_OWNED
println(purchases!!.size) // nullPointerException
}
the purchases list is null, what am I doing wrong ?
please let me know if you want more details, thanks.
i had the same error(i'm using java, so code is a little different)
#Override
public void onPurchasesUpdated(BillingResult billingResult, #Nullable List<Purchase> list) {
in my case list was null, so what i did was just called queryPurchases() to load purchases again
List<Purchase> list2 = billingClient.queryPurchases(BillingClient.SkuType.INAPP).getPurchasesList();
creation of billingClient is in documentation
Related
I have a question about the Google Play Billing Library (version 5) but I guess older versions are fine too.
In Google Play Billing, the purchase flow is launched like below:
BillingResult billingResult = billingClient.launchBillingFlow(getActivity(), billlingFlowParams);
A listener waits for the purchase response, like below:
PurchasesUpdatedListener purchasesUpdatedListener = new PurchasesUpdatedListener() {
#Override
public void onPurchasesUpdated(#NonNull #NotNull BillingResult billingResult, #Nullable #org.jetbrains.annotations.Nullable List<com.android.billingclient.api.Purchase> list) {
if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK && list != null) {
....
....
Additional code here that makes an api request based on the Purchase Object
}
};
The problem is that as soon as we confirm the purchase Google charges for the purchase but I have a backend that also process the purchase, ie confirm the purchase is applicable etc... As a result what can happen is that someone confirms the purchase, Google charges the person but my backend goes, the purchase cannot be done for whatever reason. So technically the purchase shouldn't have gone through but google charges it no matter what since it does that as soon as we confirm a purchase.
I should mention that the API requires data from the Purchase object, which contains the purchaseToken and the subscriptionIdstrong text from the onPurchasesUpdated method.
My question is how are people overcoming this? As long asBillingClient.BillingResponseCode.OK is the response code the purchase goes through regardless of what the backend thinks. I don't believe I have control over the BillingResult.getResponseCode().
How to identify the specific subscription offer from Purchase object in new Google Play Billing v5 library? I can get the product id but there seems to be now way get offer id or token? In that case how do I notify users if they wish to upgrade/downgrade plans?
#Override
public void onPurchasesUpdated(#NonNull BillingResult billingResult,
#Nullable #org.jetbrains.annotations.Nullable List<Purchase> purchases) {
Purchase purchase=purchases.get(0);
//get the exact subscription offer related to this purchase
}
I think when you call launchBillingFlow the purchase dialog will show all the information, from which current plan to which new plan and how will Google charge the fee (ReplaceProrationMode).
But I think the Purchase object should contain the offer or base plan id/tag, imagine the case that I want to disable the base plan that the user is subscribing to prevent the user choose it again (of course purchase dialog will show already subscribed error).
I'm implementing Android in app purchases, with BillingClient api.
I successfully set up billing client, like this:
billingClient = BillingClient.newBuilder(this)
.enablePendingPurchases()
.setListener(this).build()
And I implement the code I want to make the in app purchase, which in my case is a subscription.
My issue is as follows, I need to check (periodicly) if the user still has an active subscription, or if they canceled it. From what I read, I can do a call of the method, queryPurchases(PRODUCT_ID). I am doing this as follows:
override fun onBillingSetupFinished(billingResult: BillingResult?) {
if (billingResult != null) {
if (billingResult.responseCode == BillingClient.BillingResponseCode.OK){
// The BillingClient is ready. You can query purchases here.
Log.d(TAG_PURCHASES_ACTIVITY, "BillingClient ready and connected")
billingClient.queryPurchases(MONTHLY_AGENT_SUBSCRIPTION_PRODUCT_ID)
}
else{
Log.d(TAG_PURCHASES_ACTIVITY, "BillingClient ERROR: ${billingResult.responseCode}")
}
}
}
However, I get this message in the console:
W/BillingClient: getPurchase() failed. Response code: 3
Now after researching, many have said that this is coming from old phones, with older versions of google play services. But I am using new phone (Pixel 3a), which is up to date. This phone also has the google account registered in the google play console for testing.
Why I am getting this message?
Also, is this really the correct way to check if the subscription is still active?
I've tried for ages to find this solution, thanks for any help!
I was making a mistake, passing the product id as a parameter to the query request.
This is what I needed to do:
var list = billingClient.queryPurchases(SkuType.SUBS)
I have updated my application to use v2.1.0 (from an earlier 2.0.1 release) of the android play billing library and I am no longer receiving purchase updates on completion of a pending purchase.
I construct my billing client setting the listener to the current class, that implements PurchasesUpdatedListener:
billingClient = BillingClient.newBuilder( getActivity() )
.setListener( this )
.enablePendingPurchases()
.build();
I then launch a purchase and use the "slow test card approves after a few minutes"
BillingFlowParams.Builder purchaseParamsBuilder = BillingFlowParams.newBuilder()
.setSkuDetails( product );
billingClient.launchBillingFlow( getActivity(), purchaseParamsBuilder.build() );
My listener gets called after this indicating the purchase is pending:
#Override
public void onPurchasesUpdated( BillingResult billingResult, List<Purchase> purchases )
{
int responseCode = billingResult.getResponseCode();
if (responseCode == BillingClient.BillingResponseCode.OK)
{
// I get to here with a Purchase.PurchaseState.PENDING
}
}
However this listener does NOT get called when the purchase completes. I leave the application open and I see the notification from the play store saying the purchase was successful in the notification bar.
If I query the purchases manually after this notification I can get the updated purchase however this doesn't seem like a valid approach for handling the purchase.
Does anyone know what I am doing wrong or has this process changed?
This was an issue in the Play Store app (v17.9.17). The code here is correct and there is no error in the usage of the Play Billing library in the above, i.e. onPurchasesUpdated should be called when the pending transaction completes (either successfully or cancelled).
Google has isolated the issue and it will be fixed in the next update.
Reference for the bug report can be found here:
https://issuetracker.google.com/issues/146480197
I had a functioning Android implementation in-app billing, using the billing client 1.0.2 library and everything worked fine. I have a simple premium upgrade, without subscriptions.
Now I tried to upgrade to 2.0.3, I made all the necessary changes to my code (using official documentation, release notes, and StackOverflow) and it doesn't work. I know I must recognize all purchases within three days. Failure to correctly recognize purchases will result in reimbursement for these purchases. And that's what I did.
The entire purchase workflow looks okay, the behavior is like before the library is updated. But in the end my purchase is always refunded after 5 minutes (using a trial account, so it's 5 minutes instead of 3 days).
this is inside onPurchasesUpdated:
if (purchase.getPurchaseState() == Purchase.PurchaseState.PURCHASED) {
if (!purchase.isAcknowledged()) {
AcknowledgePurchaseParams acknowledgePurchaseParams = AcknowledgePurchaseParams.newBuilder().setPurchaseToken(purchase.getPurchaseToken()).build();
AcknowledgePurchaseResponseListener acknowledgePurchaseResponseListener = new AcknowledgePurchaseResponseListener() {
#Override
public void onAcknowledgePurchaseResponse(BillingResult billingResult) {
Toast.makeText(getContext(), "Purchase acknowledged", Toast.LENGTH_LONG);
}
};
mBillingClient.acknowledgePurchase(acknowledgePurchaseParams, acknowledgePurchaseResponseListener);
}
}
The debugger performs recognition and in onAcknowledgePurchaseResponse, I can see that my billingResult response code is 5 (developer error), the debug message is empty. And I have no idea what's wrong. Please, someone can help me find out what's missing. Many thanks!
After updating the billing client library to 3.0.0 everything works fine!