razorpay / razorpay-flutter-customui

Razorpay Flutter Plugin for Customui
MIT License
6 stars 18 forks source link

issue java.lang.IllegalStateException: Reply already submitted #39

Open Renatinaveen opened 2 years ago

Renatinaveen commented 2 years ago

Facing this issue and app is crashing because of this

java.lang.IllegalStateException: Reply already submitted
    at io.flutter.embedding.engine.dart.DartMessenger$Reply.reply(DartMessenger.java:431)
    at io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler$1.success(MethodChannel.java:267)
    at com.razorpay.flutter_customui.RazorpayDelegate$1.onPaymentMethodsReceived(RazorpayDelegate.java:114)
    at com.razorpay.BaseRazorpay$6.onResponse(BaseRazorpay.java:1230)
    at com.razorpay.BaseRazorpay$8.run(BaseRazorpay.java:1307)
    at com.razorpay.Q$$U_.onPostExecute(Owl.java:5137)
    at android.os.AsyncTask.finish(AsyncTask.java:771)
    at android.os.AsyncTask.access$900(AsyncTask.java:199)
    at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:788)
    at android.os.Handler.dispatchMessage(Handler.java:106)
    at android.os.Looper.loopOnce(Looper.java:201)
    at android.os.Looper.loop(Looper.java:288)
    at android.app.ActivityThread.main(ActivityThread.java:7842)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)
mishrabhilash commented 2 years ago

@Renatinaveen how were you able to solve this ?

Renatinaveen commented 2 years ago

@mishrabhilash i was calling getapps with upi and get subscription amount methods in the init state.

Now I moved the get subscription method inside getapps with upi call issue didn't appear.

Renatinaveen commented 2 years ago

java.lang.IllegalStateException: at io.flutter.embedding.engine.dart.DartMessenger$Reply.reply (Unknown Source:35) at io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler$1.success (Unknown Source:14) at com.razorpay.flutter_customui.RazorpayDelegate.sendReply (Unknown Source:4) at com.razorpay.flutter_customui.RazorpayDelegate.onPaymentError (Unknown Source:43) at com.razorpay.flutter_customui.RazorpayDelegate.onLocalActivityResult (Unknown Source:50) at com.razorpay.flutter_customui.RazorpayDelegate.onActivityResult (Unknown Source:10)

This is happening in a different scenario. We have around 160+ users who are affected in Production

mishrabhilash commented 2 years ago

A common cause could be .success getting called more than once. Check your plugin code for such scenarios.

Renatinaveen commented 2 years ago

@mishrabhilash I load the UPI apps first and then the payment options like wallet and other users are clicking on the available apps while the payment options are still loading could that be the issue?

I mean calling the Razorpay method again when one call is already happening might be causing this crash?

mrinaljain commented 1 year ago

Razorpay plugins provides the following methods 1) to get all payment methods. getPaymentMethodsRazorPay();

2) To get all supported UPI Apps getAllSupportedUpiApps();

As per our UI, we call both the methods simultaneously. And this is causing crashes

Fatal Exception: java.lang.IllegalStateException: Reply already submitted at io.flutter.embedding.engine.dart.DartMessenger$Reply.reply(DartMessenger.java:4) at io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler$1.success(MethodChannel.java:1) at ki.a$a.a(RazorpayDelegate.java:2) at com.razorpay.s.a(BaseRazorpay.java:2) at com.razorpay.u.a(BaseRazorpay.java:4) at com.razorpay.w0.onPostExecute(Owl.java:3) at android.os.AsyncTask.finish(AsyncTask.java:695) at android.os.AsyncTask.access$600(AsyncTask.java:180) at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:712) at android.os.Handler.dispatchMessage(Handler.java:106) at android.os.Looper.loop(Looper.java:201) at android.app.ActivityThread.main(ActivityThread.java:6810) at java.lang.reflect.Method.invoke(Method.java) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:547) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:873)

vivekshindhe commented 1 year ago

@mrinaljain Unable to reproduce this issue. Can I get a code snippet where you're seeing this happen?

ghost commented 1 year ago

Hi @vivekshindhe We are calling this two method in our Subscription Screen Init State method

void getRazorPaymentMethod() async {
    paymentMethods = await _razorpayService.getPaymentMethodsRazorPay();
    upiApps=await _razorpayService.getAllSupportedUpiApps();
  }

Crash is happening on random on opening Subscription Screen We are using paymentMethods value to display wallets list,netbanking list on Checkout Screen upiApps value to display upi apps UI in Payment CheckOut Screen,

We are calling _razorpay.submit(options) on clicking a particular payment method with respective options object Example

var options = {
                            "card[cvv]": cardInfoModel?.cvv,
                            "card[expiry_month]": cardInfoModel?.expiryMonth,
                            "card[expiry_year]": cardInfoModel?.expiryYear,
                            "card[name]": cardInfoModel?.cardHolderName,
                            "card[number]": cardInfoModel?.cardNumber,
                            "method": [PaymentMethodRazorPay.card.name](http://paymentmethodrazorpay.card.name/),
                            "email":cardInfoModel?.email,
                            "contact":cardInfoModel?.mobileNumber
                          };

We are calling these method as well for getting logo as well on Checkout Page to show UI

return await razorPay.getBankLogoUrl(netBankingModel.bankKey);
return await razorPay.getWalletLogoUrl(walletModel.walletName);
vivekshindhe commented 1 year ago

@imofidul do you have any logs for the crash? Does it happen every run?

ghost commented 1 year ago

Hi @vivekshindhe Log is already share by @mrinaljain .I happens randomly

vivekshindhe commented 1 year ago

@imofidul from what I see, the issue is intermittent and you have a service written that wraps Razorpay's functions. The issue is happening because there's only one methodChannel and there's no complete solution from what I saw in Flutter's issue log. There are multiple solutions that I can take as a developer. i.e, either have a flag that tells me about the status of the pendingResult or have multiple methodChannels for all functions. But, as mentioned above these aren't complete solutions to this problem. Would it be possible to implement the following for you,

_razorpay.getPaymentMethods().then((value) async => {
          paymentMethods = value,
          upiApps = await _razorpay.getAppsWhichSupportUpi()
   });

This way we reduce the chance of pendingResult clashing when using the same methodCall and by point reduce the intermittent crashes. While we at Razorpay will look into different solutions.

ghost commented 1 year ago

@vivekshindhe thanks for the update.We will be waiting for permanent solution for this .we are calling like this

 paymentMethods = await _razorpayService.getPaymentMethodsRazorPay();
    upiApps=await _razorpayService.getAllSupportedUpiApps();

But You are suggesting like this

_razorpay.getPaymentMethods().then((value) async => {
          paymentMethods = value,
          upiApps = await _razorpay.getAppsWhichSupportUpi()
   });

I guess technically both are same .Moreover we are passing paymentMethods ,upiApps as routeArgs to someother screen so using your suggested approach would be more error prone.

vivekshindhe commented 1 year ago

@imofidul the problem here is while the await part waits, it's not letting flutter clear the pendingResult value that is created in the plugin for the first call which gets reused and hence the error Reply already submitted. My suggestion to use it this way was to give flutter enough time to clear the data from the previous call to go forward with the next one. From the code snippet you shared, I can see that it's setting up to different variables. I'm not sure how you are waiting for these values to be set before routing them, but the same logic can be reused here as well.

ghost commented 1 year ago

Sure will try this