Blog

Back to Blog

How to add in-app purchasing with Android Pay

Posted on 13 Jul 2016 Written by Kai Armer

Android Pay

Android Pay was announced back in 2015 during Google I/O. Touted by some as the future of e-commerce, Android Pay offers a simpler, more secure way of handling payment information. Once a user’s payment information is registered with Android Pay, they can checkout using these details within a few taps. The use of encrypted virtual account numbers and one time transaction tokens ensures security is maintained throughout the transaction.

Supported initially by a small number of banks and retailers, Android Pay did not get off to a great start. However, with a recent release to the UK market and an ever expanding list of supporting devices, Android Pay continues to gain popularity and certainly isn’t going away.

For many, the term mobile payments means using their device as a contactless payment card, usually at a bricks and mortar store. This is only half the story. Android Pay also supports payments for physical goods (i.e. cinema tickets or cuddly toy) from within applications.

Why should I bother?

Research has shown that users often abandon a purchase on a mobile device due to a poor checkout experience. Clumsy credit card forms and Captcha type validation are cumbersome and difficult on smaller displays. Suppliers are now working hard to simplify the checkout process. Apple announced at WWDC 16 that Apple Pay will be supported on web, and PayPal has enabled a similar facility for some users. By simplifying your user checkout flows, users are less likely to abandon the transaction and may even bring increased transactions.

In this blog we are going to build a very simple shopping app to demonstrate how to use Android Pay to process payments. To keep things simple, it will be a very basic app with a single item for purchase. The only payment method will be Android Pay.

Please note: I will not be demonstrating use of a payment processor such as Stripe, Braintree or Fastspring. To keep things simple I will instead demonstrate direct merchant integration.

Getting Started

Before going anyway near code, we need something to test our app on. I tried and failed to get Android Pay installed on a Genymotion emulator due to lack of an NFC chip. So you’ll need a physical device which is equipped with NFC, such as a Nexus 9 tablet.

I was surprised to learn that Android Pay doesn’t support fake cards for development and testing. After speaking to Google, I learnt the only way to enable Android Pay was with my own card! Putting all my faith in Android Pay’s security, I enrolled my card and reached for Android Studio!

I created a new app using Android Studio’s wizard, with a single Activity. I then added an image and some text, to show our item and its price:

pay_demo_no_button

At this point it makes sense to understand the basic components:

WalletFragment

The WalletFragment is a handy tool which takes the heavy lifting out of managing the UI elements of the payment flow. For example it can show a ‘Buy with Android Pay’ button, or a chooser dialog to allow the user to select an alternative shipping address. WalletFragment also helps take care of branding, so you can be sure your UI keeps to Google’s guidelines.

MaskedWallet

The MaskedWallet is a Java object produced by the WalletFragment, which can contain various pieces of information such as the shipping address. It can also contain credit card details which are as the name suggests, masked or to be specific, partially hidden. The MaskedWallet is typically used during the confirmation steps of a payment flow to present details such as shipping information.

FullWallet

The FullWallet, again produced by the WalletFragment, is used toward the end of the payment flow. Again a Java object, it contains the necessary information about the pending transaction which can be sent to a payment processor, such as Stripe, to complete the transaction. It is good to remember that Android Pay itself does not process payments. Instead it stores and transmits payment transaction information in a convenient and secure way.

Enable Android Pay in your app

Android Pay is essentially a Google Cloud service and as such, we need to pre-authorise our app to use it by obtaining a client ID for OAuth 2.0 authorisation. If you have not already done so, register to use Google’s Cloud Platform. Then go to the Google Cloud Platform Dashboard, and choose to create a new project, providing a suitable name. Select the newly created project and hit ‘Use Google API’s’ then ‘Credentials’. Click ‘Create credentials’ then ‘OAuth Client Id’ . At this point you may be prompted to configure the consent screen. If so, simply add a suitable product name and email address then hit ‘Save’.

Select ‘Android’ for the ‘Application Type’. You should see a screen similar to this:

Create_client_id

 

Choose a suitable name and enter the package name which you’ll find in your app’s manifest file. You will also need to provide your app’s SHA1 certificate fingerprint, which you can obtain using the following command from within a terminal prompt:

keytool -exportcert -alias androiddebugkey -keystore path_to_debug_or_production_keystore -list -v

Note: For the purposes of development, usage of the debug certificate is sufficient but this of course would not be suitable for production! The debug keystore password is usually android.

Copy the SHA1 certificate fingerprint from the command prompt and paste it into the ‘Credentials’ screen. Hit ‘Create’.

Now our app is authorised to use the Android Pay service, we need to add the necessary dependencies. Let’s head over to our app module’s build.gradle file to add the following dependencies:

compile 'com.android.support:design:24.0.0'
compile 'com.google.android.gms:play-services-wallet:9.0.2'
compile 'com.google.android.gms:play-services-auth:9.0.2'

Finally, before we can start coding, the need to enable the Android Pay API with an additional tag in the application node of our manifest:

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

Is the user ready?

At last we can start coding! Of course, some users may not be able to use Android Pay. They may have an older device, an older version of Android or simply not have a valid card registered. We only wish to enable the ‘Buy with Android Pay’ button if the user is able to use it, so our first job is to make an initial check. The OnCreate method of our MainActivity seems like a good place to do this work.

To make this check, we are going to use the Google Payments API and as such we must create a GoogleAPIClient object. Let’s do this now:

final GoogleApiClient googleApiClient = new GoogleApiClient.Builder(this)
        .addApi(Wallet.API, new Wallet
                .WalletOptions.Builder()
                .setEnvironment(WALLET_ENVIRONMENT)
                .build())
        .enableAutoManage(this, this)
        .build();

Note the use of the WALLET_ENVIRONMENT constant for the environment parameter. This constant is set to ENVIRONMENT_TEST but you would change for production builds.

The check itself is done by calling the isReadyToPay method on the Google Payments API. When we call this method we must also implement a callback method in which handle its response:

Wallet.Payments.isReadyToPay(googleApiClient).setResultCallback(new ResultCallback() {
    @Override
    public void onResult(@NonNull BooleanResult booleanResult) {

        if (booleanResult.getStatus().isSuccess()) {
            if (booleanResult.getValue()) {
                createAndAddWalletFragment();
            } else {
                View androidPayLayout = findViewById(R.id.layout_android_pay);
                if (androidPayLayout != null) {
                    androidPayLayout.setVisibility(View.GONE);
                }
            }
        } else {
            Log.e(TAG, "isReadyToPay:" + booleanResult.getStatus());
        }
    }
});

As you can see here, we handle the response from isReadyToPay by first checking the status of the result. If the isReadyToPay method call was a success, we can check the result itself. If true, we show the ‘Buy with Android Pay’ button. You will see how we do this shortly.

Remember, in production code you would want to provide the user with an alternative means of payment if they could not use Android Pay. Options could include a traditional payment form, or a contact telephone number for your payments department.

Enable the ‘Buy with Android Pay’ button

If the user taps our soon-to-be-added button, we will need to ask Android Pay for items such as the shipping address and masked payment details. At the same time we must provide information such as what we want to buy and for how much. Enter the MaskedWalletRequest. Let’s create one next.

Get Permission!

To request payment information from Android Pay we need to provide a parameter containing the public part of our encryption key. If using a payment processor, such as Stripe you might work with them to obtain this, along with any other provider-specific values.

For the purposes of this sample app, we can use a simple String held within our resources. To generate this String, we can use OpenSSL. First, open a command prompt at the root of your project and paste the following command:

openssl ecparam -name prime256v1 -genkey -noout -out merchant-key.pem

This creates a small file in the project, which contains the merchant key. We will use this file next to help us create a public and private key pair. Again in your command prompt paste the following command:

openssl ec -in merchant-key.pem -pubout -text -noout

You should see a public and private key listed, which is in hex. We must decode the public key and covert it to base 64. Copy the ‘pub’ hex String and export it to a variable. Let’s call this PUBLICKEY.

Run the following command which should produce a suitable public key String:

echo \$PUBLICKEY | xxd -r -p | base64

You can now add this public key String to your resources to look something similar to the following:

<string name="public_key">BPXFp4094s/kM9yVfpy+DJqEI/uQgJXkL+DCNT5wE28Bc4E/M7ebrbczn6K9ihi+NdfqAwCuJa2Ap13HTh7knv4=</string>

Once we have this public key String, we can add it to a PaymentMethodTokenizationParameters object which we create using the familiar builder pattern:

private PaymentMethodTokenizationParameters getPaymentMethodTokenizationParameters(String publicKey) {
    return PaymentMethodTokenizationParameters.newBuilder()
            .setPaymentMethodTokenizationType(PaymentMethodTokenizationType.NETWORK_TOKEN)
            .addParameter("publicKey",publicKey)
            .build();
}

Prepare the MaskedWalletRequest

We can now build a MaskedWalletRequest, proving transaction details and our PaymentMethodTokenizationParameters:

private MaskedWalletRequest createMaskedWalletRequest(PaymentMethodTokenizationParameters
                                                              parameters) {
    return MaskedWalletRequest.newBuilder()
            .setMerchantName(getString(R.string.store_name))
            .setPhoneNumberRequired(true)
            .setShippingAddressRequired(true)
            .setCurrencyCode(getString(R.string.store_currency))
            .setEstimatedTotalPrice(getString(R.string.total_price))
            .setCart(Cart.newBuilder()
                    .setCurrencyCode(getString(R.string.store_currency))
                    .setTotalPrice(getString(R.string.product_price))
                    .setLineItems(new ShoppingCart(this).getLineItems())
                    .build())
            .setPaymentMethodTokenizationParameters(parameters)
            .build();
}

Remember at this point in the flow we are unsure of a user’s shipping address. So, you can’t be sure of shipping charges, but you should include estimated shipping and tax in the estimatedTotalPrice parameter. You should also ensure the totalPrice field in the cart matches the sum of the line items within it.

Prepare the WalletFragment

The WalletFragment is the object that is going to give us our nice ‘Buy with Android Pay’ button. Before we show it on our UI, we need to do a few things. The first thing we need to do is add it to the layout of our Activity. Let’s add a placeholder, which at run time we will swap for the WalletFragment if we deem it necessary to show the button:

<FrameLayout
    android:id="@+id/placeholder_button_fragment"
    android:layout_width="@dimen/buy_button_width"
    android:layout_height="@dimen/buy_button_height"
    android:layout_gravity="center_horizontal"
    android:layout_marginTop="@dimen/margin_xlarge" />

Next, let’s create a style:

final WalletFragmentStyle walletFragmentStyle = new WalletFragmentStyle()
        .setBuyButtonText(WalletFragmentStyle.BuyButtonText.BUY_WITH)
        .setBuyButtonAppearance(WalletFragmentStyle.BuyButtonAppearance.ANDROID_PAY_DARK)
        .setBuyButtonWidth(WalletFragmentStyle.Dimension.MATCH_PARENT);

The WalletFragmentStyle offers some cool customisation options; for example for a charitable payment use-case you can have the button read ‘Donate with Android Pay’.

Next, we need to apply this style to the WalletFragment. We also need to tell it which environment we wish to use, and a few other details such as our chosen theme. The WalletFragmentOptions object is a good tool for the job:

final WalletFragmentOptions walletFragmentOptions = WalletFragmentOptions.newBuilder()
        .setEnvironment(WALLET_ENVIRONMENT)
        .setFragmentStyle(walletFragmentStyle)
        .setTheme(WalletConstants.THEME_LIGHT)
        .setMode(WalletFragmentMode.BUY_BUTTON)
        .build();

Lets create our WalletFragment and apply these options:

final SupportWalletFragment walletFragment = SupportWalletFragment.newInstance
        (walletFragmentOptions);

At this point we can add our MaskedWalletRequest to the WalletFragment initialisation parameters and initialise it:

final WalletFragmentInitParams.Builder startParamsBuilder = WalletFragmentInitParams
        .newBuilder()
        .setMaskedWalletRequest(maskedWalletRequest)
        .setMaskedWalletRequestCode(REQUEST_CODE_MASKED_WALLET)
        .setAccountName(getString(R.string.user_name));

walletFragment.initialize(startParamsBuilder.build());

Now we have everything we need to show the button, let’s not forget to swap our placeholder fragment for our nice new WalletFragment:

getSupportFragmentManager().beginTransaction().replace(R.id.placeholder_button_fragment,
        walletFragment).commit();

Phew! There was quite a lot to take in there! At this point if we run our app using a device which has a valid card set up for Android Pay, we should see a screen similar to the following:

pay_demo_button

Handle the response

When the user taps the ‘Buy with Android Pay’ button, the MaskedWalletRequest is sent to Android Pay and a MaskedWallet object is returned.  You need to handle this response which you can do by overriding the OnActivityResult method of the Activity which contains the WalletFragment:

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

    int errorCode;
    if (data != null) {
        errorCode = data.getIntExtra(WalletConstants.EXTRA_ERROR_CODE, -1);
    } else {
        Log.d(TAG, "onActivityResult - data was null");
        return;
    }

    switch (requestCode) {
        case REQUEST_CODE_MASKED_WALLET:
            switch (resultCode) {
                case Activity.RESULT_OK:
                    final MaskedWallet maskedWallet =
                             data.getParcelableExtra(WalletConstants
                            .EXTRA_MASKED_WALLET);
                    launchConfirmationPage(maskedWallet);
                    break;
                case Activity.RESULT_CANCELED:
                    break;
                default:
                    handleError(errorCode);
                    break;
            }
            break;
        case WalletConstants.RESULT_ERROR:
            handleError(errorCode);
            break;
        default:
            super.onActivityResult(requestCode, resultCode, data);
            break;
    }
}

As you can see in the code above, we first check the request code. Remember we are targeting a specific request type, which is an arbitrary, non-negative number we previously created and assigned the identifier REQUEST_CODE_MASKED_WALLET. Next, we check the result code, which if ok, allows us to retrieve the MaskedWallet object and pass it to the Activity which will handle our confirmation screen:

private void launchConfirmationPage(MaskedWallet maskedWallet) {
    final Intent intent = new Intent(this, ConfirmationActivity.class);
    intent.putExtra(WalletConstants.EXTRA_MASKED_WALLET, maskedWallet);
    startActivity(intent);
}

Note: If this sample app encounters an error with Android Pay it simply shows a Toast on the screen, listing the error code. In a production application you would probably wish to handle errors a little more gracefully!

Confirm the purchase details

As we mentioned earlier, during the flow the user may choose to change the shipping address or an card; if they have more than one registered with Android Pay. This scenario is catered for by the WalletFragment object, when the user can be presented with a screen looking similar to the following:

pay_demo_chooser

Note: As you can see, when the chooser dialog is shown it reports an ‘Unrecognised app’ error. Google state that whenever you use the ENVIRONMENT_TEST parameter for your GoogleAPIClient, you will receive this error. They state this error won’t be shown in production environments.

Retrieve the MaskedWallet

Before we launched this Activity, we added the MaskedWallet which we created earlier, to our Intent. Let’s retrieve the MaskedWallet as we are going to use it shortly:

maskedWallet = getIntent().getParcelableExtra(WalletConstants.EXTRA_MASKED_WALLET);

Prepare the WalletFragment

As you will see, we are going to use a pattern similar to the one we used when we added our ‘Buy with Android Pay’ button earlier. Again we are going to create and style a WalletFragment object, but this time we will initialise it with our MaskedWallet, rather than the MaskedWalletRequest we used earlier. We will provide a mode of WalletFragmentMode.SELECTION_DETAILS, to inform it that we want the chooser dialog to be shown following the response. Again, we will trigger these events from the onCreate method of our Activity.

First let’s create a style:

final WalletFragmentStyle walletFragmentStyle = new WalletFragmentStyle()
        .setMaskedWalletDetailsTextAppearance(R.style
                .WalletFragmentDetailsTextAppearance)
        .setMaskedWalletDetailsHeaderTextAppearance(R.style
                .WalletFragmentDetailsHeaderTextAppearance)
        .setMaskedWalletDetailsBackgroundColor(ContextCompat.getColor
                (getApplicationContext(), R.color.shinobi_white));

And some options which include a theme:

final WalletFragmentOptions walletFragmentOptions = WalletFragmentOptions.newBuilder()
        .setEnvironment(MainActivity.WALLET_ENVIRONMENT)
        .setFragmentStyle(walletFragmentStyle)
        .setTheme(WalletConstants.THEME_LIGHT)
        .setMode(WalletFragmentMode.SELECTION_DETAILS)
        .build();

Let’s create the WalletFragment and initialise it with some start parameters. Notice the difference from when we did this the first time, namely the request code:

walletFragment = SupportWalletFragment.newInstance(walletFragmentOptions);

final WalletFragmentInitParams.Builder startParamsBuilder =
        WalletFragmentInitParams.newBuilder()
                .setMaskedWallet(maskedWallet)
                .setMaskedWalletRequestCode(REQUEST_CODE_CHANGE_MASKED_WALLET)
                .setAccountName(getString(R.string.user_name));

walletFragment.initialize(startParamsBuilder.build());

Of course we need to show the WalletFragment on our ConfirmationActivity, to allow the user to interact with it. In a similar fashion to our previous Layout, for our ConfirmationActivity’s Layout we include a placeholder which will be swapped for the WalletFragment at runtime:

<FrameLayout
    android:id="@+id/dynamic_wallet_masked_wallet_fragment"
    android:layout_height="wrap_content"
    android:layout_width="match_parent"
    android:layout_gravity="center_horizontal"
    android:layout_marginTop="@dimen/margin_large"
    android:layout_marginBottom="@dimen/margin_large"
    android:layout_marginLeft="@dimen/padding_small"
    android:layout_marginRight="@dimen/padding_small" />

Again, as before with the WalletFragment initialised, adding it to our Layout is simple:

getSupportFragmentManager()
        .beginTransaction()
        .replace(R.id.dynamic_wallet_masked_wallet_fragment, walletFragment)
        .commit();

Handle the response

If you run your app now and hit the ‘Buy with Android Pay’ button, you should see a confirmation screen similar to the screen shot below:

confirm_order_no_button

This sample app is deliberately very simple in that the item details towards the top of the screen are hard coded. In a production application you would of course display a suitable representation of the user’s current shopping cart contents.

This part of the payment flow is very important in it allows your user to change their shipping address or payment method. When the user taps a ‘change’ button they are directed to a chooser screen which will allow them to make these changes. The WalletFragment gives you this for free, to save you having to code it! What you do have to do however is handle the response after the user confirms their changes or exits the chooser prompt.

As before, this work is handled in the OnActivityResult method of the enclosing Activity:

...switch (requestCode) {
            case REQUEST_CODE_CHANGE_MASKED_WALLET:
                switch (resultCode) {
                    case Activity.RESULT_OK:
                        if (data.hasExtra(WalletConstants.EXTRA_MASKED_WALLET)) {
                            maskedWallet = data
                            .getParcelableExtra(WalletConstants.EXTRA_MASKED_WALLET);
                        }
                        break;
                    case Activity.RESULT_CANCELED:
                        break;
                    default:
                        handleError(errorCode);
                        break;
                }
                break;...

As before, the first thing we do is check the requestCode. Again we are looking for a match with the code that we used when we initialised the WalletFragment. In this case it was a value which we assigned the constant identifier REQUEST_CODE_CHANGE_MASKED_WALLET.

Next, we take a look at the resultCode. As long as it is OK, we extract the updated MaskedWallet if one exists, from the data parameter. We then update our own reference to point to this updated MaskedWallet. This step is very important to ensure that when the user finally confirms the payment, any updated details such as shipping address are used.

Confirm the Payment

Once the user is happy with their order, we need to allow them to confirm it. Let’s start by adding a nice confirmation button. This time we will handle this using a standard Android Button, which we will add to our ConfirmationActivity’s Layout file:

<Button
    android:id="@+id/btn_confirm_order"
    android:layout_width="@dimen/buy_button_width"
    android:layout_height="wrap_content"
    android:layout_gravity="center_horizontal"
    android:layout_marginTop="@dimen/padding_large"
    android:text="@string/confirm_order"/>

Prepare the FullWalletRequest

Now we have the button, we need to add code to confirm the transaction when it is clicked. First we need to create a GoogleAPIClient object, which we will use shortly. You should remember we used something similar back at the start when we checked to see if the user was able to use Android Pay. As before, our onCreate method is a suitable place for this work.

googleApiClient = new GoogleApiClient.Builder(this)
        .enableAutoManage(this, this)
        .setAccountName(getString(R.string.user_name))
        .addApi(Wallet.API, new Wallet
                .WalletOptions.Builder()
                .setEnvironment(MainActivity.WALLET_ENVIRONMENT)
                .setTheme(WalletConstants.THEME_LIGHT)
                .build())
        .build();

This code is very similar to that in our MainActivity and of course you may find a better way to share this code and avoid the duplication. An important point to note however is the value which we pass to the setEnvironment builder method. I’ve deliberately used the same constant value here, and you should consider this too. This approach means when you move to a production environment, swapping out this parameter will be easy.

With the GoogleAPIClient set up, we can now write the code which will handle payment confirmation. We can keep this work in its own method which we can then just wire up to the Button.

private void confirmOrder() {
    final FullWalletRequest fullWalletRequest = FullWalletRequest.newBuilder()
            .setGoogleTransactionId(maskedWallet.getGoogleTransactionId())
            .setCart(Cart.newBuilder()
                    .setCurrencyCode(getString(R.string.store_currency))
                    .setTotalPrice(getString(R.string.total_price))
                    .setLineItems(new ShoppingCart(this).getLineItems())
                    .build())
            .build();
    Wallet.Payments.loadFullWallet(googleApiClient, fullWalletRequest,
            REQUEST_CODE_RESOLVE_LOAD_FULL_WALLET);
}

I’m sure you are getting used to Google’s use of the builder pattern by now! This time we create a FullWalletRequest, which again will contain our shopping cart items. It is very important at this stage that the cart details such as the total price are correct. Also notice how we pass the GoogleTransactionId which we retrieve from the MaskedWalletRequest we retrieved earlier.

With the FullWalletRequest ready, we call the loadFullWallet method on the Google Payments API. Again we pass in our GoogleAPIClient but also notice this time we pass in a different request parameter – REQUEST_CODE_RESOLVE_LOAD_FULL_WALLET. This tells Android Pay that we want the FullWallet object returned to us, which will allow us to process the payment either ourselves, or using a payment processor.

Let’s not forget to wire up our Button!

final Button confirmOrder = (Button) findViewById(R.id.btn_confirm_order);
if (confirmOrder != null) {
    confirmOrder.setOnClickListener(this);
}

Handle the Response

The response to our call to loadFullWallet is handled in the onActivityResult method of our Activity. We’ve already implemented this method when we handled the work of the user changing their payment details. We simply need to add code to listen for a different request code. Remember in our confirmOrder method, our request code was the constant identifier REQUEST_CODE_RESOLVE_LOAD_FULL_WALLET.

...case REQUEST_CODE_RESOLVE_LOAD_FULL_WALLET:
    switch (resultCode) {
        case Activity.RESULT_OK:
            if (data.hasExtra(WalletConstants.EXTRA_FULL_WALLET)) {
                final FullWallet fullWallet = data.getParcelableExtra(WalletConstants
                        .EXTRA_FULL_WALLET);
                showPaymentConfirmation(fullWallet);
            } else if (data.hasExtra(WalletConstants
                    .EXTRA_MASKED_WALLET)) {
                maskedWallet = data.getParcelableExtra(WalletConstants
                        .EXTRA_MASKED_WALLET);
                getIntent().putExtra(WalletConstants.EXTRA_MASKED_WALLET, maskedWallet);
                startActivity(getIntent());
            }
            break;
        case Activity.RESULT_CANCELED:
            break;
        default:
            handleError(errorCode);
            break;
    }
    break;...

If the result was OK and our FullWallet is available, we retrieve it from the data parameter and hand it off to another method to be dealt with. Notice the other branch in this code. We may find that the FullWallet is not provided, but instead we receive an updated MaskedWallet object. This may be due to further changes to payment details during the payment flow. In this case, we update our reference to the MaskedWallet and re-launch the Activity.

Extract the PaymentMethodToken

Almost there! The FullWallet object holds the necessary information we need to complete the final steps of processing a payment. You can of course use a payment processor, such as Stripe or you can handle it yourself. This detail is outside the scope of this blog.

In this sample app we are going to show a simple confirmation screen on which will print the PaymentMethodToken we received from Android Pay. The mechanics of this step are fairly arbitrary but you can see below how we retrieve the PaymentMethodToken from our FullWallet object:

final FullWallet fullWallet = getIntent().getParcelableExtra(WalletConstants
        .EXTRA_FULL_WALLET);
final PaymentMethodToken paymentMethodToken = fullWallet.getPaymentMethodToken();
final TextView txtPaymentMethodToken = (TextView) findViewById(R.id
        .txt_payment_method_token);
if (txtPaymentMethodToken != null) {
    txtPaymentMethodToken.setText(paymentMethodToken.getToken());
}

When you run your app and confirm the payment details, you should see something like this:

order_success

Conclusion

In this blog I briefly discussed what Android Pay is, and why you should consider supporting it in your app. The journey exploring Android Pay has been enjoyable, but not without its hiccups. Once I understood how the various components fit together, it was quite straightforward. Of course this app is deliberately simple; there is not much use in a shop that only sells one item! In your own app you would need to consider aspects such as error handling; you might want to direct the user to an alternative payment option if Android Pay was unavailable. Getting to that stage however was, in my opinion, hampered by poor documentation on Google’s part. Details such as Android Pay not accepting fake cards seem insignificant now, but to discover this seemed to take an awful lot of effort. I think, to encourage interest from developers, Google would do well to improve documentation, along with perhaps a little more promotion of Android Pay.

If you would like to try this out for yourself, head over to github and check out the code.

shinobicontrols sadly doesn’t sell cool cuddly toys. We do however, build cool data visualization tools which can really take the pain out of making your data look amazing. Why not check us out by heading over to our product pages.

Back to Blog