Integrating Paystack Payment Gateway in Android Applications

Hello there, my name is Peterstev Uremgba, but my friends simply call me Peters or Light or Peters Light however they like. well, this is my first time trying out this Blogging thingy so you all can already forgive my future errors and be kind to me :XD. Now to the business at hand.

I am yet to come across any sound/complete Paystack integration tutorial online asides the official GitHub readMe page and Segun Famisa’s blog post, albeit an abridged post, so I’m here to throw my hat into the ring.

What is Paystack?

According to their official page, they are simply a fintech company that helps businesses in Africa get paid by anyone, anywhere in the world, well there you go, but I don’t think you’ll be searching for a way to integrate Paystack into an Android app if you didn’t know what Paystack does.

I’ll make a series of assumptions here.

  1. You are an Android Programmer.
  2. You program using Android Studio.
  3. You know how to add libraries to your project using Gradle.
    Now that we have that out of the way lets roll.

Firstly follow this link to create a Paystack account if you don’t have one or login, when done, complete your profile, head over to settings, click on the API KEYS & WEBHOOK tab to reveal your Test API Key (Note: leave your account in test mode, so you can easily test all the features of Paystack without incurring any charges.)

Next, we have to head over to the official Paystack github page and grab the Paystack android library link, copy the implementation link and paste in your app.gradle file’s dependency block and SYNC GRADLE

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'co.paystack.android:paystack:3.0.12'
}

This version (3.0.12) of the library may be outdated by the time you’re reading this, so make sure to grab the latest version from the official GitHub page.
NOTE: you have to be targeting Android 4.1 “Jelly Bean” and above to be able to use this Library

Next, add the internet permission to your Manifest file (Ignore the other code for now, just focus on the highlighted code block).

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.your.packagename">

    <uses-permission android:name="android.permission.INTERNET" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

Next, create a class that extends Application and initialize the Paystack SDK there

public class App extends Application{
    @Override
    public void onCreate() {
        super.onCreate();

        PaystackSdk.initialize(getApplicationContext());
    }
}

Now add this new class to the as a name attribute in the application tag of your manifest file

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.your.packagename">

    <uses-permission android:name="android.permission.INTERNET" />

    <application
        android:name=".App"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

Now add the following meta tag to the application tag of your manifest file

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.your.packagename">

    <uses-permission android:name="android.permission.INTERNET" />

    <application
        android:name=".App"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">

        <meta-data
          android:name="co.paystack.android.PublicKey"
          android:value="your test public key"/>

        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

The test (As in test environment) public key can be gotten from the API KEYS & WEBHOOK tab in the settings page of your Paystack account

Now here comes the fun part :XD

By now you should head over to your main layout file and create a layout to collect data like Card Number, CVV, Expiry date
These are the compulsory details before you can charge the card, other details include Name, Email, Phone Number etc see the documentation for more details to collect.
Therefore create a simple layout with 2 EditText for Card Number and CVV then 2 Spinners for Expiry Month and year.

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <android.support.v7.widget.AppCompatEditText
        android:id="@+id/et_main_card"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="10dp"
        android:layout_marginTop="30dp"
        android:layout_marginEnd="10dp"
        android:hint="Card Number"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <android.support.v7.widget.AppCompatEditText
        android:id="@+id/et_main_cvv"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="10dp"
        android:hint="Card CVV"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/et_main_card" />

    <android.support.v7.widget.LinearLayoutCompat
        android:id="@+id/sp_container"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="10dp"
        android:animateLayoutChanges="true"
        android:orientation="horizontal"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/et_main_cvv">

        <android.support.v7.widget.AppCompatSpinner
            android:id="@+id/sp_main_month"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:entries="@array/months"
            android:spinnerMode="dropdown" />

        <android.support.v7.widget.AppCompatSpinner
            android:id="@+id/sp_main_year"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:spinnerMode="dropdown" />

    </android.support.v7.widget.LinearLayoutCompat>

    <android.support.v7.widget.AppCompatButton
        android:id="@+id/bt_main_proceed"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="10dp"
        android:text="Process Payment"
        android:textColor="#ffffff"
        app:backgroundTint="@color/colorPrimary"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/sp_container" />

</android.support.constraint.ConstraintLayout>

android:entries=”@array/months” should pop an error in your screen, copy the string array of months and add to your strings.xml file.
You’ll also notice that no entry was defined for the year spinner, that is because we want it to be dynamic and change on its own every year. So we’ll set it in our Java code.

<resources>
    <string name="app_name">Peterstev Blog</string>

    <string-array name="months">
        <item>Month</item>
        <item>01</item>
        <item>02</item>
        <item>03</item>
        <item>04</item>
        <item>05</item>
        <item>06</item>
        <item>07</item>
        <item>08</item>
        <item>09</item>
        <item>10</item>
        <item>11</item>
        <item>12</item>
    </string-array>
</resources>

Now to our Java Code

First, we have to get references to our XML elements (I expect you to reference them yourself) and name them etCard, etCvv, spMonth, spYear, also get a reference to the button and call it btProceed.

Make them global variables outside onCreate() so we can access them later.

Next, we create a new method that’ll enable us get the year dynamically at all times.

    private String[] getYears() {
        String[] years = new String[10];
        Integer year = Calendar.getInstance().get(Calendar.YEAR);
        years[0] = "Year";
        for (int x = 1; x < years.length; x++) {
            String currentYear = String.valueOf(year++);
            years[x] = currentYear;
        }
        return years;
    }

Now we set the year spinner adapter to show these new values we are getting from the getYears() method.

ArrayAdapter<String> adapter = new ArrayAdapter<>(context, android.R.layout.simple_list_item_1, getYears());
//here we set the adapter to the year spinner
spYear.setAdapter(adapter);

Next, we create a chargeCard() method that takes care of collecting card details and passing it over to Paystack through the Paystack Card class.

    private void chargeCard(int amountInKobo) {
        String cardCvv = etCvv.getText().toString().trim();
        String cardNumber = etCard.getText().toString().trim();
        String month, year;

        if (spMonth.getSelectedItemPosition() > 0 &amp;&amp; spYear.getSelectedItemPosition() > 0) {
            month = spMonth.getSelectedItem().toString();
            year = spYear.getSelectedItem().toString();

            if (cardName.isEmpty()) {
                snackBar("Please enter the name on the card");
            } else {
                if (!cardNumber.isEmpty() &amp;&amp; !cardCvv.isEmpty()) {
                    
                    //here we pass the details to the card object
                    Card card = new Card(cardNumber, Integer.valueOf(month), Integer.valueOf(year), cardCvv, cardName);

                    //check if the card is valid before attempting to charge the card
                    if (card.isValid()) {
                        //we disable the button so the user doesn't tap multiple times and create a duplicate transaction
                        btProceed.setEnabled(false);

                        //every transaction requires you to send along a unique reference
                        String customRef = generateReference();

                        //setup a charge object to set values like amount, reference etc
                        Charge charge = new Charge();
                        //the amount(in KOBO eg 1000 kobo = 10 Naira) the customer is to pay for the product or service
                        // basically add 2 extra zeros at the end of your amount to convert from kobo to naira.
                        charge.setAmount(amountInKobo);
                        charge.setReference(customRef);
                        charge.setCurrency("NGN");
                        charge.setCard(card);

                        //Charge the card
                        PaystackSdk.chargeCard(this, charge, new Paystack.TransactionCallback() {
                            @Override
                            public void onSuccess(Transaction transaction) {
                                 btProceed.setEnabled(true);
                                 snackBar("onSuccess");
                            }

                            @Override
                            public void beforeValidate(Transaction transaction) {
                                snackBar("beforeValidate");
                            }

                            @Override
                            public void onError(Throwable error, Transaction transaction) {
                                btProceed.setEnabled(true);
                                
                                    snackBar(error.getMessage());
                            
                            }
                        });
                    } else {
                        snackBar("Invalid Card");
                    }
                }
            }
        } else {
            snackBar("Select Card Expiry Date");
        }
    }
btProceed.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                  chargeCard(100000);                
            }
});

NOTE: Paystack handles the network calls for you under the hood using Retrofit, this is what most posts fail to tell you and so you may spend time wondering how to pass the data on your own. So if its solely charging of user cards your app handles, then there is no need for a lib like Retrofit or Volley etc.

After the request hits Paystack servers you’ll be prompted to enter your card pin and then your OTP then the transaction is validated and processed

Use TEST CARDS to test in the Test Environment, you can find more test cards here or simply use…

Card Number: 5060 6666 6666 6666 666 (Verve)
Expiry Date: any date in the future
CVV: 123
PIN: 1234
OTP: 123456

You can check your dashboard to confirm receipt of the funds or if you hit onError() method, you can log the messages to analyse the cause of the error.

some utility method used like snackBar(“…”), generateReference() are setup below.

private void snackBar(String message) {
        Snackbar.make(etCvv, message, Snackbar.LENGTH_LONG).show();
}
private String generateReference() { 
        String keys = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
                                    + "0123456789"
                                    + "abcdefghijklmnopqrstuvxyz"; 
  
        StringBuilder sb = new StringBuilder(10); 
  
        for (int i = 0; i < 10; i++) { 
            int index = (int)(keys.length() * Math.random()); 
            sb.append(keys.charAt(index)); 
        } 
  
        return sb.toString(); 
    } 

So here you go with integrating Paystack into an android Application.
Do like and share this post on Twitter, Facebook and LinkedIn or other social media platforms if you found it helpful.

if you have any issues don’t fail to reach out to me in the comments box and i’ll do well to promptly reply you.

Thanks.

10119total visits,8visits today

Share

You may also like...

13 Responses

  1. Franklin Uzoukwu says:

    Good one bro

  2. Chizoba says:

    Nice post

  3. Jasmyne says:

    Thanks for the tutorial! Looking forward to more.

  4. Asendo says:

    Nice i think you should make that amount to be passed in as parameters in the charge card method so it would be like :

    chargeCard(1000);

    Nice tutorial

  5. Christian says:

    Hi, Thanks for this great tutorial, i have followed all your guide bu I Always get error please try again while running the code

  6. Hector says:

    Nice post. Excellent explanation

  7. Odera says:

    I think this is the most precise and easy to follow paystack tutorial out there. Thanks.

Leave a Reply

Your email address will not be published. Required fields are marked *