Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Google Play Billing Library v5 #36

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open

Google Play Billing Library v5 #36

wants to merge 1 commit into from

Conversation

timoschwarzer
Copy link
Collaborator

This PR contains breaking changes

@timoschwarzer
Copy link
Collaborator Author

Disclaimer: I'm not able to test this. I created a prerelease on GitHub (https://github.com/godotengine/godot-google-play-billing/releases/tag/2.0.0-rc.1) which you can download and use as usual. The API is a bit different compared to v1 of the plugin. If you use it, please report back if everything works or you find issues. 🙌

@bouncymarble
Copy link

Hi, I'm trying to adapt the old plugin code with the new logic. First I had an error when connecting the signals:

payment.connect("sku_details_query_completed", self, "_on_sku_details_query_completed")
payment.connect("sku_details_query_error", self, "_on_sku_details_query_error")

But it was fixed by replacing the names:

payment.connect("product_details_query_completed", self, "_on_sku_details_query_completed")
payment.connect("product_details_query_error", self, "_on_sku_details_query_error")

Now I have this error: Invalid get index 'status' (on base: 'Nil')., when checking query status:

var query = payment.queryPurchases("inapp")
if query.status == OK:

query is also null with "subs", am I doing something wrong or is it an issue with this release?

I'd appreciate if anyone else testing the new plugin let me know how to make it work, as there's no currently updated docs to follow. According to google we have until november to migrate to billing library v4 or newer, but they seem to be delaying an update of mine, not sure if it's because I'm still using v3.

@NianoTT
Copy link

NianoTT commented Sep 4, 2022

@bouncymarble

queryPurchases is async now, you need to do connect "query_purchases_response" and then call it like that:
payment.queryPurchases("inapp")

the function you connected to query_purchases_response will be emitted when it's done.


I got the plugin working for in app purchases, now need to test everything thouroghly, will report later.

@bouncymarble
Copy link

@NanitesNanites Thanks for your help, after some refactoring I managed to query product details and make purchases (consumables and non consumables). So I connected query_purchases_response as you said and I'm handling the purchase states in the function _on_query_purchases_response, although not sure if I'm checking the correct state, since the purchases dictionary returns purchase_state, but it also returns a dictionary called original_json which contains purchaseState. Anyways, I'm using the first one as it seems to match the states in this docs: https://developer.android.com/reference/com/android/billingclient/api/Purchase.PurchaseState#constants_1

The purchases dictionary also returns products, which seems to contain the product id, but I'm using productId from original_json which I think makes more sense:

product_id = parse_json(purchase.original_json).productId

Btw, I noticed that the plugin often disconnects for some reason, after starting the purchase of any product, I think it's when the signal purchases_updated is emitted, but then the purchase continues after the plugin tries to reconnect. Is that normal? can you check if the same happens to you?

Anyways, consumePurchase and acknowledgePurchase work as expected. I also did several tests with all the test cards, and everything is working :)

@NianoTT
Copy link

NianoTT commented Sep 5, 2022

@bouncymarble

original_json is just the actual return from Google while the rest of the dictionary is constructed from it by the Billing Plugin, at least thats how I understand it from looking at the code. Don't think it matters which one to use?

I never could observe any disconnects.

@timoschwarzer I did test startConnection(), isReady(), querySkuDetails(), acknowledgePurchase(), purchase() for In App Purchases (non consumables only, also no Substriptions as I don't have any of that).

I did not run into any issues, after changing the signal names, making queryPurchases async and adjusting to the new dictionaries everything worked as before.

I hope others can check the things bouncymarble and me did not try like Subscriptions, and thank you for quickly making the upgrade to v5! Greatly appreciated :)

for (ProductDetails.SubscriptionOfferDetails subscriptionOfferDetails : subscriptionOfferDetailsList) {
Dictionary subscriptionOfferDetailsDictionary = new Dictionary();
subscriptionOfferDetailsDictionary.put("offer_token", subscriptionOfferDetails.getOfferToken());
subscriptionOfferDetailsDictionary.put("offer_tags", subscriptionOfferDetails.getOfferTags());
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
subscriptionOfferDetailsDictionary.put("offer_tags", subscriptionOfferDetails.getOfferTags());
Object[] array = subscriptionOfferDetails.getOfferTags().toArray();
subscriptionOfferDetailsDictionary.put("offer_tags", array);

ArrayList won't work in a Dictionary (it will come to Godot as null). It needs to be converted to array.

pricingPhasesDictionaryList.add(pricingPhasesDictionary);
}

subscriptionOfferDetailsDictionary.put("pricing_phases", pricingPhasesDictionaryList);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
subscriptionOfferDetailsDictionary.put("pricing_phases", pricingPhasesDictionaryList);
array = pricingPhasesDictionaryList.toArray();
subscriptionOfferDetailsDictionary.put("pricing_phases", array);

Same.

subscriptionOfferDetailsDictionaryList.add(subscriptionOfferDetailsDictionary);
}

dictionary.put("subscription_offer_details", subscriptionOfferDetailsDictionaryList);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
dictionary.put("subscription_offer_details", subscriptionOfferDetailsDictionaryList);
Object[] array = subscriptionOfferDetailsDictionaryList.toArray();
dictionary.put("subscription_offer_details", array);

Same™

@KoBeWi
Copy link

KoBeWi commented Jan 15, 2023

There is a bug in current 2.0.0rc1 where the returned offer details are null. I fixed it on my side, but I didn't technically clone the repo, so I couldn't figure out how to make a proper patch. You can use my review suggestions.

signals.add(new SignalInfo("sku_details_query_completed", Object[].class));
signals.add(new SignalInfo("sku_details_query_error", Integer.class, String.class, String[].class));
signals.add(new SignalInfo("product_details_query_completed", Object[].class));
signals.add(new SignalInfo("product_details_query_error", Integer.class, String.class, String[].class));
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The last argument here is String[], but below, it's called with List<ProductDetails>.

}
emitSignal("sku_details_query_completed", (Object)GooglePlayBillingUtils.convertSkuDetailsListToDictionaryObjectArray(skuDetailsList));
emitSignal("product_details_query_completed", (Object)GooglePlayBillingUtils.convertProductDetailsListToDictionaryObjectArray(list));
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand why this is being cast to Object -- isn't it already an Object? (It's actually Object[], but that is, itself, an object).

@finepointcgi finepointcgi mentioned this pull request May 19, 2023
@finepointcgi
Copy link
Contributor

finepointcgi commented May 19, 2023

I have tested the code with 6.0 and removed the legacy onPriceChangeConfirmationResult code. Do we want to merge this and do a pr for 6.0 or how do we want to work on this?
Edit: I have also tested both purchase and subscription and it does work.

@LettucePie
Copy link

Hello. New to this whole open contribution space. I have the plugin running off this branch, with changes by KoBeWi and novalis implemented.

I have most functions working so far that I have tested...

  • Sku Query (Request and Signals)
  • Purchases/Receipts (Request and Signals)
  • Purchase Requests (Request and Signals)
  • Purchase Acknowledgements (Request and Signals)
  • Start Connection (Request and Signals)
  • End Connection (Request)

I have only encountered one major issue so far and it was with the endConnection request and disconnected signal. I suddenly received a rogue disconnect signal after switching the accounts on my test device and re-exporting. It processed the connection, query, and receipts as expected, then after a short while it just disconnected itself.

Now after adding connection checks with reconnect logics to my buttons, I added a testing button to call endConnection. It calls it and internally disconnects, but fails to call the disconnect signal. For now I'm just calling my disconnect receiver function after calling out the endConnection as a temporary solution.

Maybe a faulty configuration on my end? Either way thought I should share.

Thank all of you either way for your work and contributions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants