Open harrym49 opened 9 months ago
Hello @harrym49 ,
As you told me, I think we have the same problem, or at least a similar one. I leave what happens to me here in case it helps.
I have created an in-game purchase, it works correctly, but when the in-game purchase message appears on any consumable item 2 things happen:
If it is the first purchase, it is duplicated If it is the second purchase, the game freezes and stops working.
It is all in the same position as in the example in Gdevelop (https://gdevelop.io/game-example/free/in-app-purchase).
At the beginning of the scene:
Inside Store is ready:
I don't understand if it's a bug, if there's a loop or what's going on, could you please help me with this error? I don't see where the problem could be.
Steps to reproduce
I add all the details of the purchase Compile the game and run it on an iOS device I make a purchase, even the coins are loaded and I see the OK IAP failure
Hello,
I have created a test app with In App Purchase only and I get the same error. The first time the purchase is duplicated and the second time the game freezes.
The project is here: test.zip
I attach the log file
I forgot to give a piece of information that could also be important. In the config file I use the following version of Cordova plugin parchase:
plugin name="cordova-plugin-purchase" spec="13.10.1"
I think I can provide some more information that may be useful, when it performs the "finished" it goes into a loop and you can see in the log in debug Mode that the same message keeps appearing:
00:50.707.574 Default Space Warhog (3570) Space Warhog Default [CdvPurchase.AdapterListener] DEBUG: receiptsUpdated: [{"className":"Receipt","transactions":[{"className":"Transaction","transactionId":"appstore.application","state":"finished","products":[{"id":"com.stilugames.jabaliespacial"}],"platform":"ios-appstore"},{"className":"Transaction","transactionId":"2000000519733187","state":"finished","products":[{"id":"500monedas"}],"platform":"ios-appstore","purchaseDate":"2024-02-08T11:10:55.000Z"}],"platform":"ios-appstore","nativeData":{"appStoreReceipt":"MIIYaAYJKoZIhvcNAQcCoIIYWTCCGFUCAQExDzANBglghkgBZQMEAgEFADCCB54GCSqGSIb3DQEHAaCCB48EggeLMYIHhzAKAgEIAgEBBAIWADAKAgEUAgEBBAIMADALAgEBAgEBBAMCAQAwCwIBAwIBAQQDDAEzMAsCAQsCAQEEAwIBADALAgEPAgEBBAMCAQAwCwIBEAIBAQQDAgEAMAsCARkCAQEEAwIBAzAMAgEKAgEBBAQWAjQrMAwCAQ4CAQEEBAICARowDQIBDQIBAQQFAgMCmaAwDQIBEwIBAQQFDAMxLjAwDgIBCQIBAQQGAgRQMzAyMBgCAQQCAQIEEDPRs4ekq0SkZlUgJ/eLt0kwGwIBAAIBAQQTDBFQcm9kdWN0aW9uU2FuZGJveDAcAgEFAgEBBBQtLi9MhuolXbWhk28w5m96/K6ikDAeAgEMAgEBBBYWFDIwMjQtMDItMDhUMTE6MTA6NTVaMB4CARICAQEEFhYUMjAxMy0wOC0wMV 00:50.805.216 Default Space Warhog (3570) com.apple.WebKit ProcessSuspension 0x1122c00e0 - [PID=3'571, throttler=0x112018880] ProcessThrottler::Activity::invalidate: Ending foreground activity / 'WebPageProxy::runJavaScriptInFrameInScriptWorld' 00:50.826.899 Default Space Warhog (3570) Space Warhog Default [CdvPurchase.AdapterListener] DEBUG: receiptsUpdated: [{"className":"Receipt","transactions":[{"className":"Transaction","transactionId":"appstore.application","state":"finished","products":[{"id":"com.stilugames.jabaliespacial"}],"platform":"ios-appstore"},{"className":"Transaction","transactionId":"2000000519733187","state":"finished","products":[{"id":"500monedas"}],"platform":"ios-appstore","purchaseDate":"2024-02-08T11:10:55.000Z"}],"platform":"ios-appstore","nativeData":{"appStoreReceipt":"MIIYaAYJKoZIhvcNAQcCoIIYWTCCGFUCAQExDzANBglghkgBZQMEAgEFADCCB54GCSqGSIb3DQEHAaCCB48EggeLMYIHhzAKAgEIAgEBBAIWADAKAgEUAgEBBAIMADALAgEBAgEBBAMCAQAwCwIBAwIBAQQDDAEzMAsCAQsCAQEEAwIBADALAgEPAgEBBAMCAQAwCwIBEAIBAQQDAgEAMAsCARkCAQEEAwIBAzAMAgEKAgEBBAQWAjQrMAwCAQ4CAQEEBAICARowDQIBDQIBAQQFAgMCmaAwDQIBEwIBAQQFDAMxLjAwDgIBCQIBAQQGAgRQMzAyMBgCAQQCAQIEEDPRs4ekq0SkZlUgJ/eLt0kwGwIBAAIBAQQTDBFQcm9kdWN0aW9uU2FuZGJveDAcAgEFAgEBBBQtLi9MhuolXbWhk28w5m96/K6ikDAeAgEMAgEBBBYWFDIwMjQtMDItMDhUMTE6MTA6NTVaMB4CARICAQEEFhYUMjAxMy0wOC0wMV 00:50.827.014 Default Space Warhog (3570) com.apple.WebKit ProcessSuspension 0x1122c0200 - [PID=3'571, throttler=0x112018880] ProcessThrottler::Activity::invalidate: Ending foreground activity / 'WebPageProxy::runJavaScriptInFrameInScriptWorld' 00:50.849.892 Default Space Warhog (3570) Space Warhog Default [CdvPurchase.AdapterListener] DEBUG: receiptsUpdated: [{"className":"Receipt","transactions":[{"className":"Transaction","transactionId":"appstore.application","state":"finished","products":[{"id":"com.stilugames.jabaliespacial"}],"platform":"ios-appstore"},{"className":"Transaction","transactionId":"2000000519733187","state":"finished","products":[{"id":"500monedas"}],"platform":"ios-appstore","purchaseDate":"2024-02-08T11:10:55.000Z"}],"platform":"ios-appstore","nativeData":{"appStoreReceipt":"MIIYaAYJKoZIhvcNAQcCoIIYWTCCGFUCAQExDzANBglghkgBZQMEAgEFADCCB54GCSqGSIb3DQEHAaCCB48EggeLMYIHhzAKAgEIAgEBBAIWADAKAgEUAgEBBAIMADALAgEBAgEBBAMCAQAwCwIBAwIBAQQDDAEzMAsCAQsCAQEEAwIBADALAgEPAgEBBAMCAQAwCwIBEAIBAQQDAgEAMAsCARkCAQEEAwIBAzAMAgEKAgEBBAQWAjQrMAwCAQ4CAQEEBAICARowDQIBDQIBAQQFAgMCmaAwDQIBEwIBAQQFDAMxLjAwDgIBCQIBAQQGAgRQMzAyMBgCAQQCAQIEEDPRs4ekq0SkZlUgJ/eLt0kwGwIBAAIBAQQTDBFQcm9kdWN0aW9uU2FuZGJveDAcAgEFAgEBBBQtLi9MhuolXbWhk28w5m96/K6ikDAeAgEMAgEBBBYWFDIwMjQtMDItMDhUMTE6MTA6NTVaMB4CARICAQEEFhYUMjAxMy0wOC0wMV
I add the log: Log-MyApp.zip
Hi! I have seen many people with the same issue, why you upload something to production broken? And if it works, why don't you explain how to use it? The example in the documentation doesn't work.
Maybe they can help @ClementPasteau @AlexandreSi @4ian
Unfortunately I can't say what I would like to say because we live in a censored world, but just as those two guys have problems with the IAP extension, so do I. These noble gentlemen of dubious reputation never answer, why do they ask to report bugs if they don't deign to answer or provide a solution? That's why GDevelop is losing so many users, because the support is shameful. @4ian @ClementPasteau @AlexandreSi @arthuro555
Will you say something this time or can you give a date to solve the problem? If there are no problems with this extension, please explain how the hell it works, because the GDevelop example is useless.
Hello @harrym49 ,
I think I have the solution. At least it seems to work in a test app I created, I still need to test it in my game to make sure it really works.
I'm sharing everything I've done, because I had to remove the IAP extension, it's broken and doesn't work.
While I'm testing that it works, if it's OK with you, you can do your tests with Android, so we can have both versions working. I'll take care of iOS and you take care of Android.
The problem with the IAP extension could be it never marks the item as "purchased" and that's why it generates these loops and strange errors, but I'm not an expert and I can't be sure that's the problem.
Now, let's get down to business: what to do in the code? We have to manually generate the JS code again in the following way:
1- Load products price information according to user's country:
JS Code:
document.addEventListener('deviceready', onDeviceReady, false);
function onDeviceReady() {
const productIds = ["500_monedas", "1000_monedas"];
const buycoinTemp = runtimeScene.getVariables().get("Quini_monedas_price");
const subscriptionTemp = runtimeScene.getVariables().get("Mil_monedas_price");
const priceUpdatedTemp = runtimeScene.getVariables().get("priceUpdated");
inAppPurchases.getAllProductInfo(productIds).then( function (products) {
for (var i=0; i<products.length; i++){
if (products[i]["productId"] == "500_monedas"){
buycoinTemp.setString(products[i].price);
}
if (products[i]["productId"] == "1000_monedas"){
subscriptionTemp.setString(products[i].price);
}
}
priceUpdatedTemp.setBoolean(true);
})
}
2- Check if it is already purchased or not. In case for consumable, as you must consume it before you can buy it again. to consume product set consume status to "true", leave it blank or set "false" for non-consumable products such as "removeads" and "subscription" products.
I saw the timmer on the internet and that's why I added it, I don't know if it is necessary or if we cannot use it.
JS Code:
document.addEventListener("deviceready", onDeviceReady, false);
function onDeviceReady() {
const productIds = ["500_monedas", "1000_monedas"];
const buycoinTemp = runtimeScene.getVariables().get("Quini_paid");
const subscriptionTemp = runtimeScene.getVariables().get("Mil_paid");
inAppPurchases.restorePurchases().then( function(purchases){
for (var i=0; i<purchases.length; i++){
if (purchases[i]["pending"]) return;
if (!purchases[i]["completed"]) {
if (purchases[i]["productId"] == "500_monedas"){
inAppPurchases
.completePurchase(purchases[i]["productId"],true)
.catch(function(err){});
buycoinTemp.setBoolean(true);
}
if (purchases[i]["productId"] == "1000_monedas"){
inAppPurchases
.completePurchase(purchases[i]["productId"])
.catch(function(err){});
subscriptionTemp.setBoolean(true);
}
}
}
})
}
3- Now we buy the products
JS Code:
document.addEventListener('deviceready', onDeviceReady, false);
function onDeviceReady() {
inAppPurchases.purchase("500_monedas").then( function(purchase){
if (purchase["pending"]) return; //not paid for yet
// handle purchase here, or after its been completed:
})
}
4- Consume all the products. This step is optional, I won't add it to my game, but I found it online and thought I'd add it to the test as well.
document.addEventListener('deviceready', onDeviceReady, false);
const productIds = ["500_monedas", "1000_monedas"];
function onDeviceReady() {
for (var i=0; i<3; i++){
inAppPurchases.completePurchase(productIds[i],true);
}
}
If it doesn't work for you, we will check it. I'll try it in my game and if it works I'll let you know. At the moment I've only tested it in a test app I've created.
On the config.xml I have added this plugin:
<plugin name="cordova-plugin-inapppurchases">
</plugin>
Android steps found on Internet:
1- Build manually the project, we will locate the project in folder called “iap” (just for example)
2- Open visual studio code, open “www” folder in iap folder, then make a new file name it “manifest.json”, open your google play console, select your app, Go to the Monetize > Monetization setup, under licensing you’ll found your base64 string, back to visual studio code, in manifest.json type this : { “play_store_key”: " Insert your base 64 string here " } ,don’t forget to save the file
3- open command prompt, move to “iap” folder, then type : cordova plugin add cordova-plugin-inapppurchases after executing it type: cordova platform add android@12
4- building aab file using Android Studio, I won’t explain this step completely, you can read it on Publish your game to Android and iOS manually using Cordova - GDevelop documentation
5- After building the .aab file, upload it on your google play console testing track
Hi @konguele @harrym49
I've pushed a new version of the extension with #1190 (0.0.5) It brings back the action "Mark purchase as delivered" and simplifies a few things. I've also updated the example with a lot more comments to explain how things work and should be used: https://github.com/GDevelopApp/GDevelop-examples/pull/630
I've only managed to test on Android with the 3 different product types (Consumable, Non Consumable, Subscription) and they all work fine (buying multiple consumables, buying a subscription or non consumable & rehydrating its state when the app relaunches)
Could you test out this latest version on your devices (iOS included) and let me know if this fixes the issues you've been having?
I'm impressed you've tried to create your own implementation of the in app purchase @konguele - why not just try modify/fix the extension? (https://github.com/GDevelopApp/GDevelop-extensions/blob/main/extensions/reviewed/InAppPurchase.json) This would be much faster than recreate everything.
As a reminder, this extension was not started by the core team, so we appreciate any contributions and fixes to it to make it better for the community :) PRs are welcome!
Hello @ClementPasteau ,
Sorry for the delay. I decided to try to create a new one because I don't know much about JavaScript and I didn't understand how it works your extensions :( so it was easier to start with a new one.
I've been testing the new version of the extension on iOS and found a problem. Everything works fine except "Watch the event approved" step.
It never gives the condition as "true", I don't know if it is because it is executed once when the screen starts and it is not executed anymore, so it never detects it is true or if it is for some reason in the code, in case iOS uses other variables.
I have tried to move it to different parts, but it didn't work.
If I set the condition manually to true, it makes the purchase perfectly.
So I think the problem is in that step.
Thank you for your help!
Thanks for testing it out 👍
Normally, registering it at the beginning of scene is enough, it creates an event listener that will be triggered when one transaction goes to "approved", and checks if this is the product you're looking at to set that scene var. It works perfectly on Android, so I assume iOS must be behaving differently. Though I'm unsure what's different 🤔
You could try adding some console.log()
in the different actions and conditions of the extension (you can access the extension and toy around with them before exporting your app again) This may give some useful information.
For instance, in the WatchItemEvent
action (which is the one that you think is not triggered) you could add a log when the approved event is detected, and log the transaction to see what's happening.
For ex:
store.when().approved((transaction) => {
console.log(transaction);
transactionCallback(transaction);
})
Let me know if you learn something
If I have a bit of time, I'll set up an app on the app store with products to test everything out
Is there an existing issue for this?
Enter the name of the extension
Mobile In-App Purchase
Describe the bug of the extension
I did exactly like on your example on https://editor.gdevelop.io/?project=https://resources.gdevelop-app.com/examples/in-app-purchase/in-app-purchase.json But I faced the problem. After I made a purchase, log started to spam
consumePurchase() -> Consume already in progress. 17:50:13.494 D callError({code:6777003, msg:"ITEM_ALREADY_CONSUMED")
After a minute or two ANR is occurredSteps to reproduce
Actual result:
17:51:17.943 I consumePurchase() -> Consume already in progress. 17:51:17.943 D callError({code:6777003, msg:"ITEM_ALREADY_CONSUMED")
spams in logs. After that ANR is occurred anr.txtGDevelop platform
Desktop
GDevelop version
5.3.188
Platform info
Additional context
No response