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:
- First download the stripe-android libraries.
- Be sure you’ve installed the Android SDK with a minimum of API Level 17 and android-support-v4.
- Import the
stripefolder into Eclipse. - In your project settings, add the
stripeproject 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:
- Grab a reference to that fragment.
- Create a
MaskedWalletRequest. - 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: