Migrating from v1 to v2

We've made some big changes in the 2nd major version of the Braintree Android SDK which will simplify your integration and make your life easier.

Motivations

In a nutshell, we want to make your integration experience as simple and easy as possible. In our major remodel we sought to reduce complexity and improve ease of use.

Added APIs

BraintreeFragment

The single biggest breaking change is the introduction of a new class, BraintreeFragment, which is designed to replace the Braintree class. BraintreeFragment is a headless Fragment which is added to your activity. By centralizing our architecture around a Fragment object, we can tie into lifecycle events, removing the need to notify us of them manually.

Create an instance of BraintreeFragment by calling BraintreeFragment#newInstance(Activity, authorization). Under the hood, we'll attach the fragment to your activity, and, if your activity implements any Braintree interface, we'll attach those as well. You should keep a reference to a BraintreeFragment in any activity where you expect to use it, and should make the call to BraintreeFragment#newInstance in your activity's onCreate method.

Where previously your integration might have looked like:

Java
Copy
Copied
public class MainActivity extends Activity {

  private Braintree mBraintree;

  @Override
  public void onCreate(Bundle savedInstanceState) {
    Braintree.setup(this, CLIENT_TOKEN_FROM_SERVER, new BraintreeSetupFinishedListener() {
      @Override
      public void onBraintreeSetupFinished(boolean setupSuccessful, Braintree braintree, String errorMessage, Exception exception) {
        if (setupSuccessful) {
          mBraintree = braintree;
        } else {
          // Braintree could not be initialized, check errors and try again
          // This is usually a result of a network connectivity error
        }
      }
    });
  }
}

It will now look like this:

Java
Copy
Copied
public class MainActivity extends Activity {

  private BraintreeFragment mBraintreeFragment;

  @Override
  public void onCreate(Bundle savedInstanceState) {
    try {
      mBraintreeFragment = BraintreeFragment.newInstance(this, AUTHORIZATION_FROM_SERVER);
    } catch (InvalidArgumentException e) {
      // the authorization provided was of an invalid form
    }
  }
}

Moved APIs

Payment Method Creation

In the spirit of keeping things simple, we've moved quite a bit of our logic into dedicated classes, such as Card, PayPal, and AndroidPay. Each of these classes contains one or more static methods which you'll use to authorize various payment instruments.

For example, previously your call to add a PayPal account might have looked something like this:

Java
Copy
Copied
public void onClick(View v) {
  mBraintree.startPayWithPayPal(this, PAYPAL_REQUEST_CODE);
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
  mBraintree.onActivityResult(this, requestCode, resultCode, data);
}

Your integration will now look more like this:

Java
Copy
Copied
PayPal.authorizeAccount(mBraintreeFragment);

Manual Card Tokenization

Additionally, your entry point for tokenizing a card will not be an instance of the Braintree class, but in a static method on the Card class:

Previously in v1:

Java
Copy
Copied
CardBuilder cardBuilder = new CardBuilder()
  .number("4111111111111111")
  .expirationMonth("11")
  .expirationYear("15");

mBraintree.tokenize(cardBuilder);

Now in v2:

Java
Copy
Copied
CardBuilder cardBuilder = new CardBuilder()
  .number("4111111111111111")
  .expirationMonth("11")
  .expirationYear("15");

Card.tokenize(mBraintreeFragment, cardBuilder);

Changed APIs

Previously, the Braintree SDK contained two interfaces which you could implement to be notified of a new Payment method or nonce. Now, there's just one. Instead of implententing PaymentMethodCreatedListener or PaymentMethodNonceListener, you'll just implement PaymentMethodNonceCreatedListener, in which you'll get an instance of PaymentMethodNonce. A PaymentMethodNonce is an abstract class which is inherited by classes such as CardNonce, PayPalAccountNonce, and AndroidPayCardNonce, which themselves contain specific information regarding your payment method of choice. You can get a nonce from any PaymentMethodNonce.

Your new implementation might look something like this:

Java
Copy
Copied
@Override
public void onPaymentMethodNonceCreated(PaymentMethodNonce paymentMethodNonce) {
  String nonce = paymentMethodNonce.getNonce();

  if (paymentMethodNonce instanceof PayPalAccountNonce) {
    PostalAddress shippingAddress = ((PayPalAccountNonce) paymentMethodNonce).getShippingAddress();
    // ...
  } else if (paymentMethodNonce instanceof AndroidPayCardNonce) {
    String lastTwo = ((AndroidPayCardNonce) paymentMethod).getLastTwo();
    // ...
  } else if (paymentMethodNonce instanceof CardNonce) {
    String cardType = ((CardNonce) paymentMethodNonce).getCardType();
  }
}

We've also simplified BraintreeErrorListener, it now contains only one method to implement. You can perform some logic on the Exception passed to you in onError to determine how it should be handled.

For instance:

Java
Copy
Copied
@Override
public void onError(Exception error) {
  if (error instanceof ErrorWithResponse) {
    // there was a validation error the user provided data
  }
}

Other Changes

Apart from the sweeping changes described above, we've also fixed a ton of bugs and made optimizations throughought the code.

world.level++;

At this point you should be able to upgrade your integration to the newest version of the Android SDK. Refer to the rest of the guides for more detail on specific payment integrations in version 2.0.

Still have questions?

If you can’t find an answer, contact our Support team