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

Fatal Exception: java.lang.IllegalStateException: Reply already submitted #339

Closed
offline-first opened this issue Dec 8, 2021 · 35 comments

Comments

@offline-first
Copy link
Contributor

I got the error from Firebase Crashlytics. Are there any insights into this? Is this related to #336 @mgonzalezc ?

Fatal Exception: java.lang.IllegalStateException: Reply already submitted
       at io.flutter.embedding.engine.dart.DartMessenger$Reply.reply(DartMessenger.java:35)
       at io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler$1.success(MethodChannel.java:14)
       at com.dooboolab.flutterinapppurchase.MethodResultWrapper$1.run(MethodResultWrapper.java:8)
       at android.os.Handler.handleCallback(Handler.java:873)
       at android.os.Handler.dispatchMessage(Handler.java:99)
       at android.os.Looper.loop(Looper.java:214)
       at android.app.ActivityThread.main(ActivityThread.java:6990)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1445)

Crash on: Android 9, Galaxy Note9 (real device)

  • flutter_inapp_purchase: ^5.1.2
  • flutter stable channel: 2.5.3
  • Android build-tools 31.0.0
@mgonzalezc
Copy link
Contributor

Hello! yes, it is

I have ended up using version 5.0.4. The crash isn't there for this version

I think the issue is related to the new handlers in MethodResultWrapper.java, added in #328. From what I could investigate, when getPurchaseHistory is called, the channel receives result.success twice. This is not allowed and that's why "Reply already submitted" fires.

My PR #336 helps a bit because it makes the calls under getPurchaseHistory asynchronous but if you call it several times in your code (for example, with a retry strategy when there is no connection) then the exception is fired as well.

@offline-first
Copy link
Contributor Author

Hello @mgonzalezc
Thank you for the clarification. I think your PR fix the issue in my case

@offline-first
Copy link
Contributor Author

Ok the problem still exists. I have downgraded to version 5.0.4

@xalikoutis
Copy link

me too downgraded back to flutter_inapp_purchase: 5.0.3

@0x-cell
Copy link

0x-cell commented Dec 20, 2021

I've updated firebase to the latest version, and same error is occurring on flutter_inapp_purchase: ^5.0.2

  firebase_core: ^1.10.6
  firebase_crashlytics: ^2.4.4
  firebase_messaging: ^11.2.4

It seems that I've found a problem.
The AndroidInappPurchasePlugin.java#onMethodCall invokes several async operations on the billingClient. while persisting the safeResult in scope of the entire AndroidInappPurchasePlugin instance instead of per onMethodCall call. This creates a possibility of having several async tasks call the same instance of safeResult instead of the instance of safeResult bound to the corresponding onMethodCall cycle.

What i did to fix that was to change the

safeResult = new MethodResultWrapper(result, channel);

to

final MethodResultWrapper safeResult = new MethodResultWrapper(result, channel);
safeChannel = safeResult;

in the AndroidInappPurchasePlugin.java#onMethodCall. Note the safeChannel - it is used in private PurchasesUpdatedListener purchasesUpdatedListener = new PurchasesUpdatedListener() { instead of safeResult as it calls the channel anyways.

Back to drinking. Bye.

@jesselpereira
Copy link

Same here.

@hmarat
Copy link

hmarat commented Feb 10, 2022

@jesselpereira I have the same problem :( Did you solve it ??

@jesselpereira
Copy link

@jesselpereira I have the same problem :( Did you solve it ??

Hi dude, I just abandoned that package, migrated to in_app_purchase and solved my problems.

@hmarat
Copy link

hmarat commented Feb 10, 2022

@jesselpereira okay, thank you for answer :) So in that package it will automatically detect call update purchase callback on app open?))

@jesselpereira
Copy link

I believe it is worth trying to do this. In my project I have a callback when a purchase is completed, but I don't check it when I open the app. But this is an option that fits my project, nothing prevents you from implementing the package in your project. I believe this package here has been deprecated, or it's not a recognized flaw.

@jorgevvr
Copy link

Hello, I got the error on v5.0.4, v5.1.0, v5.1.1 and v5.1.2.
Works on v5.0.3
Please check this, and thank you for the great package.

@giladger
Copy link

Hi,
Any updates on this issue?
It suddenly started happening to me after upgrading to flutter 2.10

@reju1021
Copy link

I've updated firebase to the latest version, and same error is occurring on flutter_inapp_purchase: ^5.0.2

  firebase_core: ^1.10.6
  firebase_crashlytics: ^2.4.4
  firebase_messaging: ^11.2.4

It seems that I've found a problem. The AndroidInappPurchasePlugin.java#onMethodCall invokes several async operations on the billingClient. while persisting the safeResult in scope of the entire AndroidInappPurchasePlugin instance instead of per onMethodCall call. This creates a possibility of having several async tasks call the same instance of safeResult instead of the instance of safeResult bound to the corresponding onMethodCall cycle.

What i did to fix that was to change the

safeResult = new MethodResultWrapper(result, channel);

to

final MethodResultWrapper safeResult = new MethodResultWrapper(result, channel);
safeChannel = safeResult;

in the AndroidInappPurchasePlugin.java#onMethodCall. Note the safeChannel - it is used in private PurchasesUpdatedListener purchasesUpdatedListener = new PurchasesUpdatedListener() { instead of safeResult as it calls the channel anyways.

Back to drinking. Bye.

Worked like a charm :)

@giladger
Copy link

@reju1021 @0x-cell can you please share a patch/open a PR?

Thanks!

@valterh4ck3r
Copy link
Contributor

Hello Guys.

Use my library with fix

https://github.com/valterh4ck3r/flutter_inapp_purchase

My fix: #356

Use this dependency on pubspec.yaml

  flutter_inapp_purchase:
    git: https://github.com/valterh4ck3r/flutter_inapp_purchase

@jesselpereira
Copy link

Hello Guys.

Use my library with fix

https://github.com/valterh4ck3r/flutter_inapp_purchase

My fix: #356

Use this dependency on pubspec.yaml

  flutter_inapp_purchase:
    git: https://github.com/valterh4ck3r/flutter_inapp_purchase

Pls pull request your changes. 👏🏻

@valterh4ck3r
Copy link
Contributor

Created Pull Request

#357

@Vakil-Parth
Copy link

Hello Guys.
Use my library with fix
https://github.com/valterh4ck3r/flutter_inapp_purchase
My fix: #356
Use this dependency on pubspec.yaml

  flutter_inapp_purchase:
    git: https://github.com/valterh4ck3r/flutter_inapp_purchase

Pls pull request your changes. 👏🏻

This didn't work for me.

still facing java.lang.IllegalStateException: Reply already submitted

when I call FlutterInappPurchase.instance.getAvailablePurchases() in android

@offline-first
Copy link
Contributor Author

@valterh4ck3r
Unfortunately the error is still present.
Probably you have to make a purchase first and then call getAvailablePurchases()

@valterh4ck3r
Copy link
Contributor

This error happens when flutter calls 2 functions at the same time.

The method call cannot respond at the same time with success or error results, so I've re-implemented the service to not make 2 calls at the same time.

Anyone with the same fix?

@offline-first
Copy link
Contributor Author

@valterh4ck3r

You have it. Please change the part then it will work

Future<List<PurchasedItem>?> getPurchaseHistory() async {
    if (_platform.isAndroid) {
      final inappPurchaseHistory = await _channel.invokeMethod(
        'getPurchaseHistoryByType',
        <String, dynamic>{
          'type': describeEnum(_TypeInApp.inapp),
        },
      );

     final subsPurchaseHistory = await _channel.invokeMethod(
        'getPurchaseHistoryByType',
        <String, dynamic>{
          'type': describeEnum(_TypeInApp.subs),
        },
      );

      return extractPurchased(inappPurchaseHistory)! + extractPurchased(subsPurchaseHistory)!;
    } else if (_platform.isIOS) {
      dynamic result = await _channel.invokeMethod('getAvailableItems');

      return extractPurchased(json.encode(result));
    }
    throw PlatformException(
        code: _platform.operatingSystem, message: "platform not supported");
  }

@valterh4ck3r
Copy link
Contributor

Wait for 1 second, before call method channel again.

Future<List<PurchasedItem>?> getPurchaseHistory() async {
    if (_platform.isAndroid) {
      final inappPurchaseHistory = await _channel.invokeMethod(
        'getPurchaseHistoryByType',
        <String, dynamic>{
          'type': describeEnum(_TypeInApp.inapp),
        },
      );

   await Future.delayed(Duration(seconds: 1) , (){});

     final subsPurchaseHistory = await _channel.invokeMethod(
        'getPurchaseHistoryByType',
        <String, dynamic>{
          'type': describeEnum(_TypeInApp.subs),
        },
      );

      return extractPurchased(inappPurchaseHistory)! + extractPurchased(subsPurchaseHistory)!;
    } else if (_platform.isIOS) {
      dynamic result = await _channel.invokeMethod('getAvailableItems');

      return extractPurchased(json.encode(result));
    }
    throw PlatformException(
        code: _platform.operatingSystem, message: "platform not supported");
  }

@offline-first
Copy link
Contributor Author

The main problem is this line of code

List<dynamic> results = await Future.wait([getInappPurchaseHistory, getSubsPurchaseHistory]);

because the calls are sent in parallel and not in a queue. The timeout of one second is not needed in my test environment. But your fix in Java Source seems to need it too. Can you make a new pull request with my fix which I posted above?

@valterh4ck3r
Copy link
Contributor

Yeah, it's perfect.

I will make new pull request, thank you so much @offline-first

@valterh4ck3r
Copy link
Contributor

Done.

@soarescaique
Copy link

@valterh4ck3r @offline-first Any updates on this? I am still facing the same error on version 5.1.2.

@offline-first
Copy link
Contributor Author

@valterh4ck3r please use my fix for the async issue!

@valterh4ck3r
Copy link
Contributor

@offline-first can you send PR with your fix to repo ?

I can merge into my repo too.

@offline-first
Copy link
Contributor Author

@valterh4ck3r done

@valterh4ck3r
Copy link
Contributor

Thank you so much

@valterh4ck3r
Copy link
Contributor

@offline-first merged.

@soarescaique
Copy link

@valterh4ck3r @offline-first Sorry if I am getting it wrong. But why was the PR #359 closed since it has already been approved to be merged by @hyochan. Thank you guys for the collaboration on the package.

@hyochan
Copy link
Member

hyochan commented May 16, 2022

I think @valterh4ck3r has trouble managing the branch. I'll open up the PR again since it looks like the latest commit was intended.

@hyochan hyochan mentioned this issue May 16, 2022
@hyochan
Copy link
Member

hyochan commented May 16, 2022

Closes due to #360

Released in 5.2.0

@offline-first
Copy link
Contributor Author

Thanks @hyochan, purchase history is now works correctly again on android

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

No branches or pull requests