5

We are using the Braintree SDK in our application, in conjunction with PayPal, to enable users to make in-app purchases. Unfortunately, we have been unable to create nonce's from PayPal payment information or user-entered credit card information using Braintree.

Below is some context on our specific implementation:

We initialize the Braintree object using our client token in the following way:

Braintree braintree = Braintree.getInstance(context, token);

We also have set the Braintree listener to our Fragment, which implements Braintree.PaymentMethodNonceListener. On activityCreated() we initialize the Braintree object using the above code. onPause() we remove the listener, and onResume() we add the listener.

In the app, we allow users to pay either through PayPal or via credit card.

If the user chooses to use PayPal, we launch an intent to the PayPal activity using a unique request code. Using the following code block, we receive the response from the PayPal activity completion.

@Override
public void onActivityResult(int requestCode, int responseCode, Intent data) {
    if (requestCode == PAYPAL_REQUEST_CODE) {
        if (responseCode == FragmentActivity.RESULT_OK) {
            braintree.finishPayWithPayPal(getActivity(), responseCode, data);
        }
    }
}

In accordance with the Braintree SDK documentation seen here,

Additionally, we provide the user the ability to enter credit card info, which we then use to construct a CardBuilder object, which is passed to the Braintree object through the "tokenize" method as seen in the below snippet:

 CardBuilder cardBuilder = new CardBuilder()
                .cardNumber(cardNumber)
                .expirationDate(expirationDate);
        braintree.tokenize(cardBuilder);

According to the Braintree developer documentation, seen here, after tokenize is called, one should expect the onPaymentMethodNonce callback; at which point, the nonce is received for the user-entered credit card information.


TL/DR:

Based on our implementation described above, we currently have (2) issues we have been unable to resolve:

1) onActivityResult()

Method is never called, despite having entered valid PayPal credentials in the PayPal activity window, and having resumed to our application. After searching the internet, we discovered a potential bug in Android, regarding the parent Activity to a Fragment not calling super.onActivityResult(). onActivityResult is not being called in Fragment onActivityResult() not called when Activity started from Fragment onActivityResult not called in fragment android https://code.google.com/p/android/issues/detail?id=15394 Unfortunately, none of the advice in these posts seemed to allows onActivityResult to ever get called in our Fragment. Which, in return, results in finishPayWithPaypal() never being called on the Braintree object. Which, finally, results in the onPaymentMethodNonce never firing for our nonce listener Fragment.

Update for the onActivityResult() callback issue:

Per Luke's recommendation in the comments section, I have implemented the resolution to the onActivityResult() callback issue:

In the Payment Activity, we override onActivityResult(), which then calls the Fragment's onActivityResult method.

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.payment_fragment);
    if (fragment != null){
        fragment.onActivityResult(requestCode, resultCode, data);
    }
}

The onActivityResult() method now gets called when the PayPal activity finishes. Thanks for your help Luke.

*Note: Be sure that the Fragment in which you are trying to reference is of the same type Fragment returned by the findFragmentById()! If the Fragment is an android.app.Fragment, then use Activity's getFragmentManager().findFragmentById() which returns app Fragment. If the Fragment is an android.support.v4.app.Fragment, then use Activity's getSupportFragmentManager().findFragmentId() which returns the v4 Fragment. Otherwise, a mismatch in Fragment types will result in a null return. While this may seem intuitive, it is very annoying to debug, given the subtle difference in types!

2) onPaymentMethodNonce()

Method is never called. After calling tokenize() or finishWithPayPal(), on the Braintree object, the call seems to get lost in "Braintree world". After setting breakpoints, and stepping through the implementation, we were unable to find any trace that Braintree had either failed or succeeded in tokenizing the card or handling the PayPal activity result.


Environment

Gradle Build Info:

  • compileSdkVersion 19
  • buildToolsVersion 20.0.0
  • minSdkVersion 11
  • targetSdkVersion 19
  • versionCode 5
  • versionName 1.4.1

Test Hardware:

  • Samsung DUOS
  • Model GT-S7582
  • Android Version 4.2.2

Thank you for your help in advance.

Community
  • 1
  • 1
Devin
  • 81
  • 1
  • 3
  • Because the SDK currently only accepts an `Activity` to `Braintree#startPayWithPayPal`, the result will never be returned to your `Fragment` since it was not started using the `Fragment`. You will need to receive the `onActivityResult` in your `Activity` and pass it to your `Fragment`. Are you able to reproduce #2 in a simpler case, for instance using the [Demo app](https://github.com/braintree/braintree_android/tree/master/Demo)? – Luke Oct 22 '14 at 22:55
  • Thank you Luke! I have added code per your recommendation, and the call to the Fragment's onActivityResult is now working. Still having issues with not receiving the Braintree payment nonce callback after calling finishWithPayPal, but at least the Fragment is now getting the PayPal activity result. – Devin Oct 23 '14 at 15:43
  • We are planning to add signatures that accept `Fragment`s in the future to prevent having to forward the result on. Can you create a simple app that reproduces the problem you are having so you can share the code? Have you also tried calling [`Braintree#unlockListeners`](https://github.com/braintree/braintree_android/blob/master/Drop-In/src/main/java/com/braintreepayments/api/dropin/BraintreePaymentActivity.java#L132) to make sure there are no queued responses waiting? – Luke Oct 23 '14 at 17:02
  • You may also want to keep a reference to your listeners as they can get GC'd – Luke Oct 23 '14 at 17:04
  • We have a member variable in the Fragment for storing the Braintree listener. I have used the debugger to step through the code, and the listener is not null onResume(). Also, I put a breakpoint in the actual Braintree callback method, and it never hits it. I will see what I can do on the sample app. Thanks luke. – Devin Oct 24 '14 at 02:05
  • Determined that since onActivityResult() gets called immediately before onResume() (see here http://stackoverflow.com/questions/6468319/onactivityresult-onresume), that the Braintree listener was not being re-added in time for the callback. Still not receiving the payment nonce callback, but finding this issue brings us one step closer. Now calling the add listener method on the Braintree object before we call finishWithPayPal. – Devin Oct 30 '14 at 15:07
  • After stepping through the debugger following the call to finishPayWithPayPal(), I have determined that an exception is being thrown in Braintree, on line 131 of com.braintreepayments.api.internal.PRNGFixes.java. The calling method of that class, apply(), does not catch the exception, which causes the Braintree workflow to fail without any indication of failure. As a result, line 93 of com.braintreepayments.api.internal.HttpRequest.java fails to initialize, which exits the post workflow of the HttpRequest. ---explanation continued in the next comment --- – Devin Oct 30 '14 at 16:48
  • This causes the com.braintreepayments.api.BraintreeApi.java to fail on line 216, where the call to post occurs. Finally, as a result of this failure, the call to notify listeners on lines 447 and 448 of com.braintreepayments.api.Braintree.java, is never made. Which explains why onPaymentMethodNonce is never called in our application. – Devin Oct 30 '14 at 16:48
  • This is the culprit of the exception, if (!LinuxPRNGSecureRandomProvider.class.equals( rng1.getProvider().getClass())) { throw new SecurityException( "new SecureRandom() backed by wrong Provider: " + rng1.getProvider().getClass()); } – Devin Oct 30 '14 at 16:52
  • There is no need to add the listener before calling `finishPayWithPayPal`, if there are no listeners when you call it the response will be queued and flushed to listeners when they are added. PRNGFixes is actually legacy code to patch [some secure random issues in Android](http://android-developers.blogspot.com/2013/08/some-securerandom-thoughts.html) from Braintree's [Client Side Encryption](https://github.com/braintree/braintree_android_encryption) library, it is no longer needed and has already been removed from the library. I'll release version 1.2.6 to maven today to fix this. – Luke Oct 30 '14 at 18:22
  • Thank you Luke. I will retest after pulling down the latest artifacts. – Devin Oct 30 '14 at 18:43
  • Just released 1.2.6, it should be available from maven central in a few hours. – Luke Oct 31 '14 at 00:13
  • after integrating braintree dropin ui pay with creditcard with checkout api amount and nonce am passing and working fine getting success as result.when am work with paypal and calling checkout api with passing amount and showing error with more than one time nonce showing please help me. – Harsha Aug 01 '18 at 06:17

0 Answers0