Android Integration

Our Android libraries let you easily accept mobile payments inside any Android app. If you need help after reading this, check out our answers to common questions or chat live with other developers in #stripe on freenode.

Stripe has created a Java library for Android, allowing you to easily submit payments from an Android app. With our mobile library, we shoulder the burden of PCI compliance by eliminating the need to send card data directly to your server. Instead, our libraries send the card data directly to our servers, where we can convert them to tokens.

Your app will receive the token back, and can then send the token to an endpoint on your server, where it can be used to process a payment, establish recurring billing, or merely saved for later use.

We support Android back to version 4, and the library has no external dependencies.

Installation

Installing the Stripe Android library differs whether using Android Studio or Eclipse. For Android Studio, you don’t need to clone a repo or download any files, just add the following to your app’s build.gradle file, inside the dependencies section.

compile 'com.stripe:stripe-android:+'

To install the Stripe Android library for Eclipse:

  1. First download the stripe-android libraries.
  2. Be sure you’ve installed the Android SDK with a minimum of API Level 17 and android-support-v4.
  3. Import the stripe folder into Eclipse.
  4. In your project settings, add the stripe project under the “Libraries” section of the “Android” category.

Collecting credit card information

At some point in the flow of your app, you’ll want to obtain payment details from the user. There are a couple ways to do this:

Instructions for each route follows, although you may want to write your app to offer support for both.

Using Android Pay beta

Through Android Pay, you can access payment information stored in your customers’ Google accounts.

Setting up your app

You’ll first need to obtain credentials and a client ID for your app, as explained in the Android Pay API Tutorial. You will also need to set up the latest version of Google Play Services, version 8.4 or higher.

Collecting payment information through Android Pay

To use Android Pay in your app, first enable the Android Pay API by adding the following to the <application> tag of your AndroidManifest.xml:

<application
  ...
  <meta-data
    android:name="com.google.android.gms.wallet.api.enabled"
    android:value="true" />
</application>

Your application will need a SupportWalletFragment in the activity’s layout. The fragment is the placeholder for the Android Pay purchase button. You can create this either programmatically or add it to an activity layout via XML:

<!-- You will need to add the wallet namespace to your enclosing Layout -->
xmlns:wallet="http://schemas.android.com/apk/res-auto"

<fragment
  android:id="@+id/wallet_fragment"
  android:name="com.google.android.gms.wallet.fragment.SupportWalletFragment"
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  wallet:environment="test"
  wallet:fragmentMode="buyButton" />

With the fragment in place, back in the activity, you need to:

  1. Grab a reference to that fragment.
  2. Create a MaskedWalletRequest.
  3. Initialize the fragment.

In the MaskedWalletRequest, you are able to specify the amount to charge and what additional information you’d like to collect (e.g., the shipping address). This is also where you specify you are using Stripe as the processor. Doing so will let the application request a Stripe token directly from the wallet.

Before starting the Android Pay flow, use the isReadyToPay() method to check whether the user has the Android Pay app installed and is ready to pay through it. Also see Google’s documentation for information on their UI and branding requirements.

public class PaymentActivity extends FragmentActivity implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {

  // You will need to use your live API key even while testing
  public static final String PUBLISHABLE_KEY = "pk_live_XXX";

  // Unique identifiers for asynchronous requests:
  private static final int LOAD_MASKED_WALLET_REQUEST_CODE = 1000;
  private static final int LOAD_FULL_WALLET_REQUEST_CODE = 1001;

  private SupportWalletFragment walletFragment;

  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    Wallet.Payments.isReadyToPay(googleApiClient).setResultCallback(
      new ResultCallback<BooleanResult>() {
        @Override
        public void onResult(@NonNull BooleanResult booleanResult) {
          if (booleanResult.getStatus().isSuccess()) {
            if (booleanResult.getValue()) {
              showAndroidPay();
            } else {
              // Hide Android Pay buttons, show a message that Android Pay
              // cannot be used yet, and display a traditional checkout button
            }
          } else {
            // Error making isReadyToPay call
            Log.e(TAG, "isReadyToPay:" + booleanResult.getStatus());
          }
        }
      }
    );
    ...
  }

  public void showAndroidPay() {
    setContentView(R.layout.payment_activity);

    walletFragment =
      (SupportWalletFragment) getSupportFragmentManager().findFragmentById(R.id.wallet_fragment);

    MaskedWalletRequest maskedWalletRequest = MaskedWalletRequest.newBuilder()

      // Request credit card tokenization with Stripe by specifying tokenization parameters:
      .setPaymentMethodTokenizationParameters(PaymentMethodTokenizationParameters.newBuilder()
        .setPaymentMethodTokenizationType(PaymentMethodTokenizationType.PAYMENT_GATEWAY)
        .addParameter("gateway", "stripe")
        .addParameter("stripe:publishableKey", PUBLISHABLE_KEY)
        .addParameter("stripe:version", com.stripe.Stripe.VERSION)
        .build())

      // You want the shipping address:
      .setShippingAddressRequired(true)

      // Price set as a decimal:
      .setEstimatedTotalPrice("20.00")
      .setCurrencyCode("USD")
      .build();

    // Set the parameters:
    WalletFragmentInitParams initParams = WalletFragmentInitParams.newBuilder()
      .setMaskedWalletRequest(maskedWalletRequest)
      .setMaskedWalletRequestCode(LOAD_MASKED_WALLET_REQUEST_CODE)
      .build();

    // Initialize the fragment:
    walletFragment.initialize(initParams);

    ...
  }

  public void onStart() {
    ...
  }

  public void onStop() {
    ...
  }

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

  @Override
  public void onConnectionFailed(ConnectionResult connectionResult) {}

  @Override
  public void onConnected(Bundle bundle) {}

  @Override
  public void onConnectionSuspended(int i) {}
}

Note that the price set within the Android app is written as a decimal. This is for the Android app only. The token received back will be sent to your server, and the charge request will be made of the Stripe API from there. The actual amount to be charged is requested at that point, and is set as an integer.

The last part of the setup process for the app is to connect to the Google Wallet API. You will need this connection in place for when the user presses the Android Pay purchase button just created.

public class PaymentActivity extends FragmentActivity {
  ...

  private GoogleApiClient googleApiClient;

  public void onCreate(Bundle savedInstanceState) {
    ...

    googleApiClient = new GoogleApiClient.Builder(this)
      .addConnectionCallbacks(this)
      .addOnConnectionFailedListener(this)
      .addApi(Wallet.API, new Wallet.WalletOptions.Builder()
        .setEnvironment(WalletConstants.ENVIRONMENT_TEST)
        .setTheme(WalletConstants.THEME_LIGHT)
        .build())
      .build();
  }

  public void onStart() {
    super.onStart();
    googleApiClient.connect();
  }

  public void onStop() {
    super.onStop();
    googleApiClient.disconnect();
  }
}

When your customer confirms their purchase, the application then needs to create a FullWalletRequest. This will allow the application to request access to the customer’s FullWallet, which is where the payment information comes from. To do this, implement onActivityResult.

public class PaymentActivity extends FragmentActivity {
  ...

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

    if (requestCode == LOAD_MASKED_WALLET_REQUEST_CODE) { // Unique, identifying constant
      if (resultCode == Activity.RESULT_OK) {
        MaskedWallet maskedWallet = data.getParcelableExtra(WalletConstants.EXTRA_MASKED_WALLET);
        FullWalletRequest fullWalletRequest = FullWalletRequest.newBuilder()
          .setCart(Cart.newBuilder()
            .setCurrencyCode("USD")
            .setTotalPrice("20.00")
            .addLineItem(LineItem.newBuilder() // Identify item being purchased
              .setCurrencyCode("USD")
              .setQuantity("1")
              .setDescription("Premium Llama Food")
              .setTotalPrice("20.00")
              .setUnitPrice("20.00")
              .build())
            .build())
          .setGoogleTransactionId(maskedWallet.getGoogleTransactionId())
          .build();
        Wallet.Payments.loadFullWallet(googleApiClient, fullWalletRequest, LOAD_FULL_WALLET_REQUEST_CODE);
      }
    } else if (requestCode == LOAD_FULL_WALLET_REQUEST_CODE) { // Unique, identifying constant
      ...
    }
  }
}

You can see from this example that you can add line items to the FullWalletRequest’s cart. The above only has one–Premium Llama Food, but if your customer is purchasing multiple items, you can add multiple line items by calling addLineItem additional times.

Creating tokens from Android Pay

Finally, when the customer allows access to their wallet for payment, the application will be given back a Stripe token. You will want to send this token to your server for use through the API.

public class PaymentActivity extends FragmentActivity {
  ...
  //keep track of your current environment,
  //change to WalletConstants.ENVIRONMENT_PRODUCTION when you're ready to go live
  public static final int mEnvironment = WalletConstants.ENVIRONMENT_TEST;

  @Override
  protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode == LOAD_MASKED_WALLET_REQUEST_CODE) {
      ...
    } else if (requestCode == LOAD_FULL_WALLET_REQUEST_CODE) {
      if (resultCode == Activity.RESULT_OK) {
        FullWallet fullWallet = data.getParcelableExtra(WalletConstants.EXTRA_FULL_WALLET);
        String tokenJSON = fullWallet.getPaymentMethodToken().getToken();

        //A token will only be returned in production mode,
        //i.e. WalletConstants.ENVIRONMENT_PRODUCTION
        if (mEnvironment == WalletConstants.ENVIRONMENT_PRODUCTION) {
          com.stripe.model.Token token = com.stripe.model.Token.GSON.fromJson(
            tokenJSON, com.stripe.model.Token.class);

          // TODO: send token to your server
        }
      }
    } else {
      super.onActivityResult(requestCode, resultCode, data);
    }
  }
}

Testing and Deploying with Android Pay

To test your Android Pay flow, use your live Stripe API key, not your test key, in conjunction with the Android Pay test environment, specified by WalletConstants.ENVIRONMENT_TEST. In test mode, fullWallet.getPaymentMethodToken().getToken() will return the String "TEST_GATEWAY_TOKEN" in place of a JSON string representing a token.

If you want to test your application on a physical device, the device will need to support NFC. You will also need to add a supported credit card to your Android Pay account.

When you are ready to go, you can get production access to Android Pay by submitting your APK to Google for review.

Building your own form

If you build your own payment form, you’ll need to collect at least your customers’ card numbers and expiration dates. You should likely also collect the CVC to prevent fraud. You can optionally collect the user’s name and billing address for additional fraud protection.

Once you’ve collected a customer’s information, you will need to exchange the information for a Stripe token.

Creating & validating cards from a custom form

You’ll need to import the Stripe classes before you can use them.

import com.stripe.android.*;

There are two main classes: Card and Stripe. The Card class contains a bunch of useful helpers for validating card input on the client-side, before you even try to create a charge.

Let’s construct a Card instance with your customers’ payment information, perhaps retrieved from a form.

Card card = new Card(
  cardNumber,
  cardExpMonth,
  cardExpYear,
  cardCVC
);

card.validateNumber();
card.validateCVC();

As you can see in the example above, the Card instance contains some helpers to validate that the card number passes the Luhn check, that the expiration date is the future, and that the CVC looks valid. You’ll probably want to validate these three things at once, so we’ve included a validateCard function that does so.

Card card = new Card("4242-4242-4242-4242", 12, 2017, "123");

if (!card.validateCard()) {
  // Show errors
}

Creating tokens from a custom form

The next step is to pass off that sensitive payment information securely to Stripe, where you’ll exchange it for a token. You can create tokens using the Stripe instance method createToken, passing in a Card instance, and completion callbacks. An asynchronous network request will be executed, and the appropriate callback invoked when it completes.

Card card = new Card("4242424242424242", 12, 2017, "123");

Stripe stripe = new Stripe("pk_test_6pRNASCoBOKtIshFeQd4XMUh");
stripe.createToken(
  card,
  new TokenCallback() {
    public void onSuccess(Token token) {
      // Send token to your server
    }
    public void onError(Exception error) {
      // Show localized error message
      Toast.makeText(getContext(),
        error.getLocalizedString(getContext()),
        Toast.LENGTH_LONG
      ).show();
    }
  }
)

We’ve placed your test publishable API key as the first argument to Stripe. You’ll need to swap it out with your live publishable key in production. You can see all your keys in your dashboard.

Using tokens

Using the payment token, however it was obtained, requires an API call from your server using your secret API key. (For security purposes, you should never embed your secret API key in your app.)

Set up an endpoint on your server that can receive an HTTP POST call for the token. In the onActivityResult method (for Android Pay) or the onSuccess callback (when using your own form), you’ll need to POST the supplied token to your server. Make sure any communication with your server is SSL secured to prevent eavesdropping.

Take a look at the full example application to see everything put together.

Next Up

Once you’ve retrieved a token from Stripe on your server, you’re going to want to do something with the payment details you just collected. This is usually one of two things: