razorpay / react-native-razorpay

React Native wrapper for Razorpay's mobile SDKs
https://www.npmjs.com/package/react-native-razorpay
MIT License
122 stars 107 forks source link

v2.2.8 breaking checkouts due to unpinned Gradle dependency #370

Closed vidurb closed 2 years ago

vidurb commented 2 years ago

Description

v2.2.8 unpinned the com.razorpay.checkout Java dependency for patch versions. This has caused checkout in our apps to break for apps built after the 5th of October, i.e. for version 1.6.13 and above of com.razorpay.checkout.

Razorpay Package Version :

2.2.8

Xcode Version (iOS) :

N/A

Razorpay-pod version (iOS) :

N/A

Java and Gradle Version (android) :

openjdk version "1.8.0_292"
OpenJDK Runtime Environment (build 1.8.0_292-8u292-b10-0ubuntu1~20.04-b10)
OpenJDK 64-Bit Server VM (build 25.292-b10, mixed mode)

Gradle 6.9.1

What you did:

Trigger a Razorpay checkout from our ecommerce app.

What happened:

Upon successful completion of the payment and redirection back to our app activity, there is an unhandled crash.

RuntimeException
Unable to destroy activity {xxx.xxx.xxx/com.razorpay.CheckoutActivity}: java.lang.IllegalArgumentException: Receiver not registered: com.razorpay.AutoReadOtpHelper@7cf4fe

Steps To Reproduce

Provide a detailed list of steps that reproduce the issue.

  1. Build an Android app using v2.2.8 of react-native-razorpay after the 5th of October (when version1.6.13 of com.razorpay.checkout was released).
  2. Trigger a Razorpay checkout and complete it.

Suggested solution:

I don't have the necessary visibility into Razorpay to tell whether your internal practices are suited to allowing a dependency to be unpinned. Hypothetically, if the dependency in question is following semver practices 100%, then a patch release should not generally break anything. In practice, things may be different. My suggestion would be to pin dependencies to exact versions, but as I say, I don't have the knowledge to say whether that is expedient or right.

Code example, screenshot, or link to a repository:

See the following timestamps of activity:

      {
        "timestamp": 1634204516.073,
        "type": "navigation",
        "category": "ui.lifecycle",
        "level": "info",
        "data": { "screen": "MainActivity", "state": "resumed" }
      },
      {
        "timestamp": 1634204516.525,
        "type": "navigation",
        "category": "ui.lifecycle",
        "level": "info",
        "data": { "screen": "CheckoutActivity", "state": "stopped" }
      },
      {
        "timestamp": 1634204516.527,
        "type": "navigation",
        "category": "ui.lifecycle",
        "level": "info",
        "data": { "screen": "CheckoutActivity", "state": "destroyed" }
      }

and the accompanying stack trace:

"exception": {
    "values": [
      {
        "type": "IllegalArgumentException",
        "value": "Receiver not registered: com.razorpay.AutoReadOtpHelper@7cf4fe",
        "module": "java.lang",
        "stacktrace": {
          "frames": [
            {
              "function": "main",
              "module": "com.android.internal.os.ZygoteInit",
              "filename": "ZygoteInit.java",
              "abs_path": "ZygoteInit.java",
              "lineno": 1130,
              "in_app": false
            },
            {
              "function": "run",
              "module": "com.android.internal.os.RuntimeInit$MethodAndArgsCaller",
              "filename": "RuntimeInit.java",
              "abs_path": "RuntimeInit.java",
              "lineno": 602,
              "in_app": false
            },
            {
              "function": "invoke",
              "module": "java.lang.reflect.Method",
              "filename": "Method.java",
              "abs_path": "Method.java",
              "in_app": false
            },
            {
              "function": "main",
              "module": "android.app.ActivityThread",
              "filename": "ActivityThread.java",
              "abs_path": "ActivityThread.java",
              "lineno": 8595,
              "in_app": false
            },
            {
              "function": "loop",
              "module": "android.os.Looper",
              "filename": "Looper.java",
              "abs_path": "Looper.java",
              "lineno": 246,
              "in_app": false
            },
            {
              "function": "dispatchMessage",
              "module": "android.os.Handler",
              "filename": "Handler.java",
              "abs_path": "Handler.java",
              "lineno": 106,
              "in_app": false
            },
            {
              "function": "handleMessage",
              "module": "android.app.ActivityThread$H",
              "filename": "ActivityThread.java",
              "abs_path": "ActivityThread.java",
              "lineno": 2317,
              "in_app": false
            },
            {
              "function": "execute",
              "module": "android.app.servertransaction.TransactionExecutor",
              "filename": "TransactionExecutor.java",
              "abs_path": "TransactionExecutor.java",
              "lineno": 97,
              "in_app": false
            },
            {
              "function": "executeLifecycleState",
              "module": "android.app.servertransaction.TransactionExecutor",
              "filename": "TransactionExecutor.java",
              "abs_path": "TransactionExecutor.java",
              "lineno": 176,
              "in_app": false
            },
            {
              "function": "execute",
              "module": "android.app.servertransaction.DestroyActivityItem",
              "filename": "DestroyActivityItem.java",
              "abs_path": "DestroyActivityItem.java",
              "lineno": 44,
              "in_app": false
            },
            {
              "function": "handleDestroyActivity",
              "module": "android.app.ActivityThread",
              "filename": "ActivityThread.java",
              "abs_path": "ActivityThread.java",
              "lineno": 5682,
              "in_app": false
            },
            {
              "function": "performDestroyActivity",
              "module": "android.app.ActivityThread",
              "filename": "ActivityThread.java",
              "abs_path": "ActivityThread.java",
              "lineno": 5622,
              "in_app": false
            },
            {
              "function": "callActivityOnDestroy",
              "module": "android.app.Instrumentation",
              "filename": "Instrumentation.java",
              "abs_path": "Instrumentation.java",
              "lineno": 1344,
              "in_app": false
            },
            {
              "function": "performDestroy",
              "module": "android.app.Activity",
              "filename": "Activity.java",
              "abs_path": "Activity.java",
              "lineno": 8468,
              "in_app": false
            },
            {
              "function": "onDestroy",
              "module": "com.razorpay.a_$P$",
              "filename": "BaseCheckoutActivity.java",
              "abs_path": "BaseCheckoutActivity.java",
              "lineno": 4,
              "in_app": false
            },
            {
              "function": "cleanUpOnDestroy",
              "module": "com.razorpay.CheckoutPresenterImpl",
              "filename": "CheckoutPresenterImpl.java",
              "abs_path": "CheckoutPresenterImpl.java",
              "lineno": 3,
              "in_app": false
            },
            {
              "function": "unregisterReceiver",
              "module": "android.content.ContextWrapper",
              "filename": "ContextWrapper.java",
              "abs_path": "ContextWrapper.java",
              "lineno": 733,
              "in_app": false
            },
            {
              "function": "unregisterReceiver",
              "module": "android.app.ContextImpl",
              "filename": "ContextImpl.java",
              "abs_path": "ContextImpl.java",
              "lineno": 1712,
              "in_app": false
            },
            {
              "function": "forgetReceiverDispatcher",
              "module": "android.app.LoadedApk",
              "filename": "LoadedApk.java",
              "abs_path": "LoadedApk.java",
              "lineno": 1523,
              "in_app": false
            }
          ]
        },
        "thread_id": 2
      },
      {
        "type": "RuntimeException",
        "value": "Unable to destroy activity {xxx.xxx.xxx/com.razorpay.CheckoutActivity}: java.lang.IllegalArgumentException: Receiver not registered: com.razorpay.AutoReadOtpHelper@7cf4fe",
        "module": "java.lang",
        "stacktrace": {
          "frames": [
            {
              "function": "main",
              "module": "com.android.internal.os.ZygoteInit",
              "filename": "ZygoteInit.java",
              "abs_path": "ZygoteInit.java",
              "lineno": 1130,
              "in_app": false
            },
            {
              "function": "run",
              "module": "com.android.internal.os.RuntimeInit$MethodAndArgsCaller",
              "filename": "RuntimeInit.java",
              "abs_path": "RuntimeInit.java",
              "lineno": 602,
              "in_app": false
            },
            {
              "function": "invoke",
              "module": "java.lang.reflect.Method",
              "filename": "Method.java",
              "abs_path": "Method.java",
              "in_app": false
            },
            {
              "function": "main",
              "module": "android.app.ActivityThread",
              "filename": "ActivityThread.java",
              "abs_path": "ActivityThread.java",
              "lineno": 8595,
              "in_app": false
            },
            {
              "function": "loop",
              "module": "android.os.Looper",
              "filename": "Looper.java",
              "abs_path": "Looper.java",
              "lineno": 246,
              "in_app": false
            },
            {
              "function": "dispatchMessage",
              "module": "android.os.Handler",
              "filename": "Handler.java",
              "abs_path": "Handler.java",
              "lineno": 106,
              "in_app": false
            },
            {
              "function": "handleMessage",
              "module": "android.app.ActivityThread$H",
              "filename": "ActivityThread.java",
              "abs_path": "ActivityThread.java",
              "lineno": 2317,
              "in_app": false
            },
            {
              "function": "execute",
              "module": "android.app.servertransaction.TransactionExecutor",
              "filename": "TransactionExecutor.java",
              "abs_path": "TransactionExecutor.java",
              "lineno": 97,
              "in_app": false
            },
            {
              "function": "executeLifecycleState",
              "module": "android.app.servertransaction.TransactionExecutor",
              "filename": "TransactionExecutor.java",
              "abs_path": "TransactionExecutor.java",
              "lineno": 176,
              "in_app": false
            },
            {
              "function": "execute",
              "module": "android.app.servertransaction.DestroyActivityItem",
              "filename": "DestroyActivityItem.java",
              "abs_path": "DestroyActivityItem.java",
              "lineno": 44,
              "in_app": false
            },
            {
              "function": "handleDestroyActivity",
              "module": "android.app.ActivityThread",
              "filename": "ActivityThread.java",
              "abs_path": "ActivityThread.java",
              "lineno": 5682,
              "in_app": false
            },
            {
              "function": "performDestroyActivity",
              "module": "android.app.ActivityThread",
              "filename": "ActivityThread.java",
              "abs_path": "ActivityThread.java",
              "lineno": 5637,
              "in_app": false
            }
          ]
        },
        "thread_id": 2,
        "mechanism": { "type": "UncaughtExceptionHandler", "handled": false }
      }
    ]
  }

We found the cause of this issue after debugging why our core app (built on the 3rd of October) was working fine but some of our other apps built since broke on Razorpay checkout, despite the fact that we did not update the package version between those two builds. Eventually after testing with the previous version (2.2.7) we started scrutinizing the code in this repository and determined that the pinned version for com.razorpay.checkout is set to 1.6.+ in 2.2.8, which resulted in three builds over the course of 10 days all receiving different versions of that dependency despite the direct NPM dependency not changing.

We pin our dependencies to exact versions to prevent this particular issue. Now that this has come to light, we will probably be pinning all Gradle dependencies in our Gradle build configuration.

We were in a position to notice this problem and be able to debug it since we were specifically able to isolate the issue as occurring for the same package version but with build times differing by a few days. Many other users of this library may not build and release their app as often, in which case they may come across the problem randomly at some point and be unable to debug it, since from their perspective, nothing has changed.

Also, we noticed that although 2.2.8 is published to NPM, a corresponding tag does not exist in this repository. This may be confusing for users.

Ananthakr commented 2 years ago

any updates on this?

vivekshindhe commented 2 years ago

@vidurb @Ananthakr We noticed the issue. This was primarily done to handle the reach of newer versions in different platforms. The error has been resolved and it should work fine now. Thank you for the suggestions. Will consider them before taking next steps.