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

NullPointerException upon returning to app #441

Open
Buakenze opened this issue Sep 20, 2023 · 5 comments
Open

NullPointerException upon returning to app #441

Buakenze opened this issue Sep 20, 2023 · 5 comments

Comments

@Buakenze
Copy link

Braintree SDK Version

4.38.2

Environment

Sandbox

Android Version & Device

Samsung Galaxy A34, Android 13

Braintree dependencies

com.braintreepayments.api:drop-in:6.13.0

Describe the bug

Upon returning to app after selecting a paypal payment method I get a NullPointerException:

java.lang.RuntimeException: Unable to start activity ComponentInfo{it.elbuild.ilceppo/com.braintreepayments.api.DropInActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.os.Bundle.setClassLoader(java.lang.ClassLoader)' on a null object reference
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:4169)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:4325)
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:101)
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2574)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loopOnce(Looper.java:226)
        at android.os.Looper.loop(Looper.java:313)
        at android.app.ActivityThread.main(ActivityThread.java:8757)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:571)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1067)
     Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.os.Bundle.setClassLoader(java.lang.ClassLoader)' on a null object reference
        at com.braintreepayments.api.DropInActivity.getDropInRequest(DropInActivity.java:124)
        at com.braintreepayments.api.DropInActivity.onCreate(DropInActivity.java:78)
        at android.app.Activity.performCreate(Activity.java:8591)
        at android.app.Activity.performCreate(Activity.java:8570)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1384)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:4150)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:4325) 
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:101) 
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135) 
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95) 
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2574) 
        at android.os.Handler.dispatchMessage(Handler.java:106) 
        at android.os.Looper.loopOnce(Looper.java:226) 
        at android.os.Looper.loop(Looper.java:313) 
        at android.app.ActivityThread.main(ActivityThread.java:8757) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:571) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1067)

I found other issues with this error namely #403 and #404 but no solution was given. In my case, it happens everytime.

The crash happens both with an emulator and physical device. I can't understand what I'm doing wrong, it should be a very basic implementation. I have a single activity architecture where I needed the DropInClient inside a fragment, and I even tried moving the logic to the activity to no avail. I am only using the DropInClient, not the BraintreeClient.
I also tried overriding onNewIntent as stated here, even though this refers to PayPalClient.

In my activity I have:

private fun initializeDropInClient() {
    if(dropInClient == null) {
        val provider = viewmodel.getClientTokenProvider()
        dropInClient = DropInClient(this, provider)
        dropInClient!!.setListener(this)
    }
}
fun openDropInUI(amount: Double) {
    dropInClient!!.launchDropIn(DropInRequest().apply {
        isCardDisabled = true
        isVenmoDisabled = true
        isGooglePayDisabled = true
        payPalRequest = PayPalCheckoutRequest(formatPrice(amount))
    })
}
override fun onDropInSuccess(dropInResult: DropInResult) {
    val nonce = dropInResult.paymentMethodNonce?.string
    if(nonce != null) {
        (currentFragment() as CarrelloFragment).braintreePayment(nonce)
    }
}

override fun onDropInFailure(error: Exception) {
    if(error !is UserCanceledException) {
        showInfoDialogIfPossible(getString(R.string.errore),
            getString(R.string.error_during_payment) + " " + error.message, getString(android.R.string.ok)) {}
    }
}

I tried fiddling a bit with the intent filters since I read here #419 (comment) that I shouldn't declare it as stated in the documentation (hence the commented part). As for the DropInActivity intent filter, I found it somewhere else in another issue, but can't understand if it's needed or not. I'm still getting the same null pointer either if I declare the intent filter or not.
If I declare the intent filter in my activity, I get two choices to get back to the app (duplicated intent filters it seems): one gets me a UserCanceledException, the other gives me the NullPointerException mentioned above.

<activity
    android:name="it.elbuild.ui.MainActivity"
    android:exported="true"
    android:screenOrientation="portrait"
    android:launchMode="singleInstance"
    android:taskAffinity="">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />

        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>

    <!--
    <intent-filter android:autoVerify="true">
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <data android:scheme="it.elbuild.ilceppo.braintree" />
    </intent-filter>
    -->
</activity>

<activity
    android:name="com.braintreepayments.api.DropInActivity"
    android:exported="true">
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />
        <data android:scheme="it.elbuild.ilceppo.braintree" />

        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
    </intent-filter>
</activity>

I'm also getting the same exception with drop in versions 6.10 and 6.12. I upgraded in hope a later version would solve the issue.

Thank you in advance for your attention.

To reproduce

  1. Open Drop In UI
  2. Select Paypal payment method
  3. login
  4. review order
  5. back to app, crash 100%

Expected behavior

getting a callback to onDropInSuccess or onDropInFailure

Screenshots

No response

@sshropshire
Copy link
Contributor

Hi @Buakenze thanks for using the Braintree SDK for Android. I agree this is strange behavior, but the fact that it's reproducible is promising.

The stack trace references this line in DropInActivity.java. Here, we're looking for an intent extra that contains the original DropInRequest. This gets set by the SDK when your app calls DropInClient.launchDropIn().

The only way I could see this value not being present is if DropInActivity is launched manually without any intent extras. Is it possible for you to set a breakpoint here in DropInActivityResultContract.java to see if the intent is being created correctly?

@Buakenze
Copy link
Author

Hi @sshropshire, thank you for your reply.
I tried and it appears the intent is created correctly, with my DropInRequest inside.
Only weird thing I noticed is that this method is called twice in quick succession after I call launchDropIn. The sessionid inside DropInIntentData is the same, so maybe that's intended behavior.

@sshropshire
Copy link
Contributor

Actually that is a good observation. Is there something in the UI layer that may cause it to launch twice?

@Buakenze
Copy link
Author

I believe there isn't, I confirmed I have only one DropInClient instance and launchDropIn is called only once. What else could cause it to fire twice?

As I stated in the main post I had tried overriding onNewIntent as stated here, but currently that code is commented and I'm getting the same result.

@BunnyBuddy
Copy link

BunnyBuddy commented Sep 23, 2024

I believe there isn't, I confirmed I have only one DropInClient instance and launchDropIn is called only once. What else could cause it to fire twice?

As I stated in the main post I had tried overriding onNewIntent as stated here, but currently that code is commented and I'm getting the same result.

Did you find any workaround or possibly a solution?

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

3 participants