Paystack SDK for Android. Accept payments on Android

Overview

Maven Central Min API SonarCloud

Paystack Android

This is a library for easy integration of Paystack with your Android application. Use this library in your Android app so we shoulder the burden of PCI compliance by helping you avoid the need to send card data directly to your server. Instead, this library sends credit card data directly to our servers.

Summarized flow

  1. Collect user's card details

  2. Initialize the transaction

    • App prompts your backend to initialize a transaction
    • Your backend returns access_code we return when it calls the Initialize Transaction endpoint
    • App provides the access_code and card details to our SDK's chargeCard function via Charge object
  3. SDK prompts user for PIN, OTP or Bank authentication as required

  4. Once successful, we'll send an event to your webhook URL and call onSuccess callback. You should give value via webhook.

Requirements

  • Android SDKv16 (Android 4.1 "Jelly Bean") - This is the first SDK version that includes TLSv1.2 which is required by our servers. Native app support for user devices older than API 16 will not be available.

Installation

Android Studio (using Gradle)

You do not need to clone this repository or download the files. The latest build is available on Maven Central Add the following lines to your app's build.gradle:

dependencies {
    implementation 'co.paystack.android:paystack:3.1.3'
}

From version 3.0.18, the Pinpad library comes as part of this library and does not need to be explicitly included in your dependencies.

You should also add Java 8 support in your build.gradle:

android { 
    // ... Other configuration code 
    compileOptions {   
        sourceCompatibility JavaVersion.VERSION_1_8 
        targetCompatibility JavaVersion.VERSION_1_8 
    } 

    // For kotlin codebases, include
    kotlinOptions {
         jvmTarget = "1.8" 
    }
}

Eclipse

To use this library with Eclipse, you need to:

  1. Clone the repository.
  2. Import the paystack folder into your Eclipse project
  3. In your project settings, add the paystack project under the Libraries section of the Android category.

Usage

0) Prepare for use

To prepare for use, you must ensure that your app has internet permissions by making sure the uses-permission line below is present in the AndroidManifest.xml.

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

1) Initialize SDK

To use the Paystack Android SDK, you need to first initialize it using the PaystackSdk class.

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

        PaystackSdk.initialize(getApplicationContext());
    }
}

Make sure to call this method in the onCreate method of your Fragment or Activity or Application.

2) Set your Public Key

Before you can charge a card with the PaystackSdk class, you need to set your public key. The library provides two approaches:

a) Add the following lines to the <application></application> tag of your AndroidManifest.xml

<meta-data
    android:name="co.paystack.android.PublicKey"
    android:value="pk_your_public_key"/>

You can obtain your public key from your Paystack dashboard.

b) Set the public key by code

This can be done anytime in your code. Just be sure to initialize before calling chargeCard.

class Bootstrap {
    public static void setPaystackKey(String publicKey) {
        PaystackSdk.setPublicKey(publicKey);
    }
}

3) Collect and validate card details

At this time, we expect you to provide fields on your activity that collect the card details. Our Card class allows you collect and verify these. The library provides validation methods to validate the fields of the card.

card.validNumber

This method helps to perform a check if the card number is valid.

card.validCVC

Method that checks if the card security code is valid.

card.validExpiryDate

Method checks if the expiry date (combination of year and month) is valid.

card.isValid

Method to check if the card is valid. Always do this check, before charging the card.

card.getType

This method returns an estimate of the string representation of the card type.

public class MainActivity extends AppCompatActivity {

  // This sets up the card and check for validity
  // This is a test card from paystack
   String cardNumber = "4084084084084081";
   int expiryMonth = 11; //any month in the future
   int expiryYear = 18; // any year in the future. '2018' would work also! 
   String cvv = "408";  // cvv of the test card
   
   Card card = new Card(cardNumber, expiryMonth, expiryYear, cvv);
    if (card.isValid()) {
       // charge card
    } else {
      //do something
    }
}

4) Charge Card

Charging with the PaystackSdk is quite straightforward.

Parameters for the chargeCard function

  • Activity - The first argument to the PaystackSdk.chargeCard is the calling Activity object. Always give an Activity that will stay open till the end of the transaction. The currently open Activity is just fine.

  • Charge - This object allows you provide information about the transaction to be made. Before calling chargeCard, you should do a charge.setCard(card). The charge can then be used in either of 2 ways

    • Resume an initialized transaction: If employing this flow, you would send all required parameters for the transaction from your backend to the Paystack API via the transaction/initialize call - documented here. The response of the call includes an access_code. This can be used to charge the card by doing charge.setAccessCode({value from backend}). Once an access code is set, the only other parameter relevant to the transaction is the card. Others will be ignored.
    • Initiate a fresh transaction on Paystack: Using the functions: setCurrency, setPlan, setSubaccount, setTransactionCharge, setAmount, setEmail, setReference, setBearer, putMetadata, putCustomField, you can set up a fresh transaction directly from the SDK. Documentation for these parameters are same as for transaction/initialize.
  • Transaction Callback - When an error occurs or transaction concludes successfully, we will call the methods available in the callback you provided.

    • OnSuccess will be called once the charge succeeds.
    • beforeValidate is called every time the SDK needs to request user input. This function currently only allows the app know that the SDK is requesting further user input.
    • OnError is called if an error occurred during processing. Some Exception types that you should watch include
      • ExpiredAccessCodeException: This would be thrown if the access code has already been used to attempt a charge.
      • ChargeException: This would be thrown if the charge failed. It would hold the message from the server.
public class MainActivity extends AppCompatActivity {


  // This is the subroutine you will call after creating the charge
  // adding a card and setting the access_code
   public void performCharge(){
         //create a Charge object
         Charge charge = new Charge(); 
         charge.setCard(card); //sets the card to charge
   
       PaystackSdk.chargeCard(MainActivity.this, charge, new Paystack.TransactionCallback() {
           @Override
           public void onSuccess(Transaction transaction) {
               // This is called only after transaction is deemed successful.
               // Retrieve the transaction, and send its reference to your server
               // for verification.
           }

           @Override
           public void beforeValidate(Transaction transaction) {
               // This is called only before requesting OTP.
               // Save reference so you may send to server. If
               // error occurs with OTP, you should still verify on server.
           }

           @Override
           public void onError(Throwable error, Transaction transaction) {
             //handle error here
           }

       });
   }
}

Note that once chargeCard is called, the SDK may prompt the user to provide their PIN, an OTP or conclude Bank Authentication. These are currently being managed entirely by the SDK. Your app will only be notified via the beforeValidate function of the callback when OTP or Bank Authentication is about to start.

5) Verifying the transaction

Send the reference to your backend and verify by calling our REST API. An authorization will be returned which will let you know if its code is reusable. You can learn more about our Verify Transaction endpoint.

Below is a sample authorization object returned along with the transaction details:

   {
     "status": true,
     "message": "Verification successful",
     "data": {
       "amount": 10000,
       "currency": "NGN",
       "transaction_date": "2017-04-06T21:28:41.000Z",
       "status": "success",
       "reference": "d68rbovh4a",
       "domain": "live",
       "metadata": {
         "custom_fields": [
           {
             "display_name": "Started From",
             "variable_name": "started_from",
             "value": "sample charge card backend"
           },
           {
             "display_name": "Requested by",
             "variable_name": "requested_by",
             "value": "some person"
           },
           {
             "display_name": "Server",
             "variable_name": "server",
             "value": "some.herokuapp.com"
           }
         ]
       },
       "gateway_response": "Approved",
       "message": "Approved",
       "channel": "card",
       "ip_address": "41.31.21.11",
       "log": null,
       "fees": 150,
       "authorization": {
         "authorization_code": "AUTH_blahblah",
         "bin": "412345",
         "last4": "6789",
         "exp_month": "10",
         "exp_year": "2345",
         "channel": "card",
         "card_type": "mastercard debit",
         "bank": "Some Bank",
         "country_code": "NG",
         "brand": "mastercard",
         "reusable": true,
         "signature": "SIG_IJOJidkpd0293undjd"
       },
       "customer": {
         "id": 22421,
         "first_name": "Guava",
         "last_name": "Juice",
         "email": "[email protected]",
         "customer_code": "CUS_6t6che6w8hmt",
         "phone": "",
         "metadata": {},
         "risk_action": "default"
       },
       "plan": null
     }
   }

To reuse the authorization gotten from charging this customer in future, you need to do 2 tests:

  1. In the sample JSON above, you can conclude that the transaction was successful because data.status="success". This means the authorization is active.
  2. Confirm that the authorization is reusable by checking data.authorization.reusable which is true in this case. Once both pass, you can save the authorization code against the customer's email.

6) Charging a card authorization from your server in future

To charge an authorization saved from concluding chargeCard, you need its authorization code and the customer's email. Our Recurring Charge documentation provides more information about charging an authorization.

Testing your implementation

You can (and should) test your implementation of the Paystack Android library in your Android app. You need the details of an actual debit/credit card to do this, so we provide ##test cards## for your use instead of using your own debit/credit cards. Kindly reference our Test Payments documentation for test cards.

To try out the OTP flow, we have provided a test "verve" card:

50606 66666 66666 6666
CVV: 123
PIN: 1234
TOKEN: 123456

Remember to use all test cards only with test keys. Also note that all bank issued cards will be declined in test mode.

Building the example project

  1. Clone the repository.
  2. Import the project either using Android Studio or Eclipse
  3. Deploy a sample backend from PaystackJS-Sample-Backend (PHP) or Sample charge card backend (NodeJS heroku single click deploy)
  4. Copy the endpoints from the deployed backend to your MainActivity.java file. In the case of verify, only copy up to the / before the :
  5. Add your public key to your MainActivity.java file
    • Note that the public key must match the secret key, else none of the transactions will be attempted
  6. Build and run the project on your device or emulator

FAQs

Is authorization_code (https://developers.paystack.co/reference#charging-returning-customers) the same as the access_code)?

No

Where do I get an access_code?

Initialize a transaction : https://developers.paystack.co/reference#initialize-a-transaction

Where do I get an authorization_code?

Verify a successful transaction : https://developers.paystack.co/reference#verify-transaction

If I’m trying to use the Android SDK to charge someone who we’ve previously charged, can I use the authorization_code?

You don't need the SDK to charge an authorization code. It doesn't even know of its existence. Rather, use our charge endpoint: https://developers.paystack.co/reference#charge-authorization

Security

If you discover any security related issues, please email [email protected] instead of using the issue tracker.

Contact

For more enquiries and technical questions regarding the Android PaystackSdk, please post on our issue tracker: https://github.com/PaystackHQ/paystack-android/issues.

Change log

Please see CHANGELOG for more information what has changed recently.

Comments
  • SDK doesn't sync in project

    SDK doesn't sync in project

    I included the library in my build.gradle file and my project has since stopped syncing. This is the error I get

    Error:/xxx/app/build/intermediates/incremental/mergeDebugResources/merged.dir/values/values.xml:473 resource android:attr/foregroundInsidePadding is private
    
    Error:java.util.concurrent.ExecutionException: com.android.builder.internal.aapt.AaptException: AAPT2 link failed:
    
    Error:com.android.builder.internal.aapt.AaptException: AAPT2 link failed:
    
    Error:Execution failed for task ':app:processDebugResources'.
    > Failed to execute aapt
    

    When I remove the compile line, my project syncs up fine again.

    This is how my build looks like:

    compileSdkVersion 25
    buildToolsVersion "25.0.2"
    minSdkVersion 21
    targetSdkVersion 25
    
    bug enhancement 
    opened by verygreenboi 28
  • Compiling errors

    Compiling errors

    I am presently having five error integrating the dependency. Number one is this and what is the solution Error:In ForegroundView, unable to find attribute foreground

    help wanted question 
    opened by contactolaolu44real 26
  • Code snippet to initiate transaction locally on Android

    Code snippet to initiate transaction locally on Android

    Problem/Motivation

    I need a code snippet or sample project to initiate transaction on the SDK. The example on the repo only does the transaction on a backend server.

    Proposed resolution

    Some App may not have a backend server and the may only be one programmer who does not write web languages

    Expected Results:

    1. A second Activity class within the example(sample) project that initiate a transaction on the SDK. That is a class within here: https://github.com/PaystackHQ/paystack-android/tree/master/example/src/main/java/co/paystack/example
    help wanted question 
    opened by calistus 19
  • SDK installing error

    SDK installing error

    Screenshot from 2019-05-08 11-58-15

    Problem/Motivation

    SDK installation error

    Unable to resolve dependency for ':app@debug/compileClasspath': Could not resolve co.paystack.android:paystack:3.0.11. Open File Show Details

    Unable to resolve dependency for ':app@debugAndroidTest/compileClasspath': Could not resolve co.paystack.android:paystack:3.0.11. Open File Show Details

    Unable to resolve dependency for ':app@debugUnitTest/compileClasspath': Could not resolve co.paystack.android:paystack:3.0.11. Open File Show Details

    Unable to resolve dependency for ':app@release/compileClasspath': Could not resolve co.paystack.android:paystack:3.0.11. Open File Show Details

    Unable to resolve dependency for ':app@releaseUnitTest/compileClasspath': Could not resolve co.paystack.android:paystack:3.0.11. Open File Show Details

    good first issue 
    opened by Cob007 18
  • AAPT: error: resource attr/foreground (aka com.package.appname:attr/foreground) not found.

    AAPT: error: resource attr/foreground (aka com.package.appname:attr/foreground) not found.

    Problem

    Unable to compile App after adding Paystack dependecies

    Proposed resolution

    Unable to compile application after adding Paystack dependencies, i have also added the below code to my attrs file under values folder

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <declare-styleable name="ForegroundView">
            <attr name="foreground" format="color" />
            <attr name="foregroundGravity" format="integer" />
            <attr name="foregroundInsidePadding" format="boolean" />
        </declare-styleable>
    </resources>
    

    Repeatable

    Always

    Paystack version

    implementation 'co.paystack.android.design.widget:pinpad:1.0.1'
    implementation 'co.paystack.android:paystack:3.0.12'
    

    App default configuration

    defaultConfig {
            applicationId "com.eemanapp.fuoexaet"
            minSdkVersion 19
            targetSdkVersion 29
            multiDexEnabled true
            versionCode 1
            versionName "1.0"
            vectorDrawables.useSupportLibrary true
            testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
        }
    

    Actual Results:

    /Users/mac/AndroidStudioProjects/AppName/app/build/intermediates/incremental/mergeDebugResources/merged.dir/values/values.xml:4751: AAPT: error: resource attr/foreground (aka com.packageName.appName/foreground) not found.

    opened by sodiqOladeni 15
  • Payment transaction issue

    Payment transaction issue

        String cardNumber = "5060 6666 6666 6666 666";
        int expiryMonth = 10; //any month in the future
        int expiryYear = 22; // any year in the future. '2018' would work also!
        String cvv = "123";  // cvv of the test card
    

    Error! Please try again

    opened by gagan50 14
  • So many requests.

    So many requests.

    I have been testing on this project but I noticed one big problem. The app fails and gives an error 'card can not be null'. then it starts posting wildly on my backed.

    opened by solokingjec 14
  • Is there any way to customize PinActivity and OtpActivity?

    Is there any way to customize PinActivity and OtpActivity?

    it's not an issue, but question.

    Case: when user add new card in our app, PaystackSdk request for pin/OTP (PinActivity/OtpActivity is run). Obvious this inner activities are not in our app style. Is there any way to change it's layouts?

    opened by borichellow 11
  • Payment transaction issue

    Payment transaction issue

    Declined. Please use the test card since you are doing a test transaction. i'm using test card credentials that are mentioned below but it throw error

    5438898014560229 cvv 564 Expiry: 10/20 Pin 3310 otp 12345

    opened by gagan50 9
  •  public static boolean isExpired(int year, int month) always return true on active cards

    public static boolean isExpired(int year, int month) always return true on active cards

    The cause of the problem for now is in the "CardUtils class" of the android SDK and needs to be fixed asap. The method isExpired always returns true for a valid card given valid dates  ,this leads to valid cards always not passing the verification stage.

    How to recreate it is to pass valid date of card to it and it will return true which implies expired.I also attached screenshots. I have lso added my CardUtils class i modified that worked. CardUtils.zip

    alwaysreturntrue cardutilsissues codeexpired screenshot_2017-02-18-10-54-25

    opened by stonekase 9
  • java.lang.ClassNotFoundException: Didn't find class

    java.lang.ClassNotFoundException: Didn't find class "retrofit2.Callback" on path: DexPathList

    Got this error when i have entered valid card details and hit pay, the app closes by itself.

    E/AndroidRuntime: FATAL EXCEPTION: main Process: team.hyperiontech.store, PID: 8380 java.lang.NoClassDefFoundError: Failed resolution of: Lretrofit2/Callback; at co.paystack.android.Paystack.chargeCard(Paystack.java:67) at co.paystack.android.Paystack.chargeCard(Paystack.java:57) at co.paystack.android.PaystackSdk.chargeCard(PaystackSdk.java:151) at team.hyperiontech.store.MainActivity.performCharge(MainActivity.java:103) at team.hyperiontech.store.MainActivity.access$1200(MainActivity.java:20) at team.hyperiontech.store.MainActivity$1.onClick(MainActivity.java:75) at android.view.View.performClick(View.java:5675) at android.view.View$PerformClick.run(View.java:22641) at android.os.Handler.handleCallback(Handler.java:836) at android.os.Handler.dispatchMessage(Handler.java:103) at android.os.Looper.loop(Looper.java:203) at android.app.ActivityThread.main(ActivityThread.java:6289) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1063) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:924) Caused by: java.lang.ClassNotFoundException: Didn't find class "retrofit2.Callback" on path: DexPathList[[zip file "/data/app/team.hyperiontech.store-1/base.apk"],nativeLibraryDirectories=[/data/app/team.hyperiontech.store-1/lib/arm, /system/lib, /vendor/lib, /system/vendor/lib]] at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56) at java.lang.ClassLoader.loadClass(ClassLoader.java:380) at java.lang.ClassLoader.loadClass(ClassLoader.java:312) at co.paystack.android.Paystack.chargeCard(Paystack.java:67)  at co.paystack.android.Paystack.chargeCard(Paystack.java:57)  at co.paystack.android.PaystackSdk.chargeCard(PaystackSdk.java:151)  at team.hyperiontech.store.MainActivity.performCharge(MainActivity.java:103)  at team.hyperiontech.store.MainActivity.access$1200(MainActivity.java:20)  at team.hyperiontech.store.MainActivity$1.onClick(MainActivity.java:75)  at android.view.View.performClick(View.java:5675)  at android.view.View$PerformClick.run(View.java:22641)  at android.os.Handler.handleCallback(Handler.java:836)  at android.os.Handler.dispatchMessage(Handler.java:103)  at android.os.Looper.loop(Looper.java:203)  at android.app.ActivityThread.main(ActivityThread.java:6289)  at java.lang.reflect.Method.invoke(Native Method)  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1063)  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:924)  Process 8380 terminated. MainActivity: `package team.hyperiontech.store;

    import android.support.multidex.MultiDex; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.text.TextUtils; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.Toast;

    import co.paystack.android.Paystack; import co.paystack.android.PaystackSdk; import co.paystack.android.Transaction; import co.paystack.android.model.Card; import co.paystack.android.model.Charge;

    public class MainActivity extends AppCompatActivity { private Card card; private Charge charge;

    private EditText emailField;
    private EditText cardNumberField;
    private EditText expiryMonthField;
    private EditText expiryYearField;
    private EditText cvvField;
    
    private String email, cardNumber, cvv;
    private int expiryMonth, expiryYear;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        MultiDex.install(this);
        //init paystack sdk1
        PaystackSdk.initialize(getApplicationContext());
        //init paystack sdk2
    

    // App sdk = new App(); // sdk.onCreate();

        //init view
        Button payBtn = (Button) findViewById(R.id.pay_button);
    
        emailField = (EditText) findViewById(R.id.edit_email_address);
        cardNumberField = (EditText) findViewById(R.id.edit_card_number);
        expiryMonthField = (EditText) findViewById(R.id.edit_expiry_month);
        expiryYearField = (EditText) findViewById(R.id.edit_expiry_year);
        cvvField = (EditText) findViewById(R.id.edit_cvv);
    
    
        payBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (!validateForm()) {
                    return;
                }
                try {
                    email = emailField.getText().toString().trim();
                    cardNumber = cardNumberField.getText().toString().trim();
                    expiryMonth = Integer.parseInt(expiryMonthField.getText().toString().trim());
                    expiryYear = Integer.parseInt(expiryYearField.getText().toString().trim());
                    cvv = cvvField.getText().toString().trim();
    
                    //String cardNumber = "4084084084084081";
                    //int expiryMonth = 11; //any month in the future
                    //int expiryYear = 18; // any year in the future
                    //String cvv = "408";
                    card = new Card(cardNumber, expiryMonth, expiryYear, cvv);
    
                    if (card.isValid()) {
                        Toast.makeText(MainActivity.this, "Card is Valid", Toast.LENGTH_LONG).show();
                        performCharge();
                    } else {
                        Toast.makeText(MainActivity.this, "Card not Valid", Toast.LENGTH_LONG).show();
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }
    
    
    /*Method to perform the charging of the card
     */
    private void performCharge() {
        //create a Charge object
        charge = new Charge();
    
        //set the card to charge
        charge.setCard(card);
    
        //call this method if you set a plan
        //charge.setPlan("PLN_yourplan");
    
        charge.setEmail(email); //dummy email address
    
        charge.setAmount(100); //test amount
    
        PaystackSdk.chargeCard(MainActivity.this, charge, new Paystack.TransactionCallback() {
            @Override
            public void onSuccess(Transaction transaction) {
                // This is called only after transaction is deemed successful.
                // Retrieve the transaction, and send its reference to your server
                // for verification.
                String paymentReference = transaction.getReference();
                Toast.makeText(MainActivity.this, "Transaction Successful! payment reference: "
                        + paymentReference, Toast.LENGTH_LONG).show();
            }
    
            @Override
            public void beforeValidate(Transaction transaction) {
                // This is called only before requesting OTP.
                // Save reference so you may send to server. If
                // error occurs with OTP, you should still verify on server.
            }
    
            @Override
            public void onError(Throwable error, Transaction transaction) {
                //handle error here
            }
        });
    }
    
    private boolean validateForm() {
        boolean valid = true;
    
        String email = emailField.getText().toString();
        if (TextUtils.isEmpty(email)) {
            emailField.setError("Required.");
            valid = false;
        } else {
            emailField.setError(null);
        }
    
        String cardNumber = cardNumberField.getText().toString();
        if (TextUtils.isEmpty(cardNumber)) {
            cardNumberField.setError("Required.");
            valid = false;
        } else {
            cardNumberField.setError(null);
        }
    
    
        String expiryMonth = expiryMonthField.getText().toString();
        if (TextUtils.isEmpty(expiryMonth)) {
            expiryMonthField.setError("Required.");
            valid = false;
        } else {
            expiryMonthField.setError(null);
        }
    
        String expiryYear = expiryYearField.getText().toString();
        if (TextUtils.isEmpty(expiryYear)) {
            expiryYearField.setError("Required.");
            valid = false;
        } else {
            expiryYearField.setError(null);
        }
    
        String cvv = cvvField.getText().toString();
        if (TextUtils.isEmpty(cvv)) {
            cvvField.setError("Required.");
            valid = false;
        } else {
            cvvField.setError(null);
        }
    
        return valid;
    }
    

    } Manifest: <dist:module dist:instant="true" />

    <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>
        <meta-data
            android:name="co.paystack.android.PublicKey"
            android:value="pk_test_my_valid_test_key_here"/>
    </application>
    

    `

    opened by 700brains 7
  • Crash with a wrong OTP code input

    Crash with a wrong OTP code input

    Problem/Motivation

    Crash when the user put a wrong OTP input code. Stacktrace

    E/AndroidRuntime: FATAL EXCEPTION: main
        java.lang.NullPointerException
            at android.content.res.XmlBlock.nativeGetStyleAttribute(Native Method)
            at android.content.res.XmlBlock.access$1500(XmlBlock.java:41)
            at android.content.res.XmlBlock$Parser.getStyleAttribute(XmlBlock.java:459)
            at android.content.res.Resources$Theme.getExplicitStyle(Resources.java:1937)
            at android.view.View.retrieveExplicitStyle(View.java:7009)
            at android.view.View.<init>(View.java:5893)
            at android.view.ViewGroup.<init>(ViewGroup.java:715)
            at android.widget.LinearLayout.<init>(LinearLayout.java:254)
            at android.widget.LinearLayout.<init>(LinearLayout.java:250)
            at android.widget.LinearLayout.<init>(LinearLayout.java:246)
            at co.paystack.android.design.widget.Indicator.<init>(Indicator.java:59)
            at co.paystack.android.design.widget.PinPadView.createIndicators(PinPadView.java:481)
            at co.paystack.android.design.widget.PinPadView.setPinLength(PinPadView.java:432)
            at co.paystack.android.ui.OtpActivity$1.onPinChanged(OtpActivity.java:40)
            at co.paystack.android.design.widget.PinPadView.updatePin(PinPadView.java:470)
            at co.paystack.android.design.widget.PinPadView.access$200(PinPadView.java:51)
            at co.paystack.android.design.widget.PinPadView$1.onButtonClick(PinPadView.java:533)
            at co.paystack.android.design.widget.PinPadButton.dispatchTouchEvent(PinPadButton.java:234)
            at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3920)
            at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:3594)
    

    Repeatable

    Always

    Steps to repeat:

    1. Go to the payment screen
    2. Use this test card number 507850785078507804 (PIN + Phone + OTP validation)
    3. Fill the expiry and CVV inputs
    4. put the pin code (0000)
    5. put any wrong OTP code

    Expected Results:

    at least an error message

    Actual Results:

    The app crashes

    Recrod

    https://user-images.githubusercontent.com/10960959/203558345-7819c52d-c5ab-421b-9327-35061df5180b.mp4

    bug 
    opened by OHoussein 0
  • co.paystack.android.exceptions.PaystackSdkNotInitializedException: Paystack SDK has not been initialized.The SDK has to be initialized before use

    co.paystack.android.exceptions.PaystackSdkNotInitializedException: Paystack SDK has not been initialized.The SDK has to be initialized before use

    Problem/Motivation

    (Why the issue was filed, steps to reproduce the problem, etc.)

    Proposed resolution

    (Description of the proposed solution, the rationale behind it, and workarounds for people who cannot use the patch.)

    Repeatable

    Always|Sometimes|Specific conditions|Specific times

    (If it is a bug, you are reporting lease specify:)

    Steps to repeat: (Describe how the issue can be repeated by someone who is to work on it)

    1. Step 1
    2. Step 2
    3. ...

    Expected Results:

    (What you expected steps 1, 2 and 3 to give)

    Actual Results:

    (What is gave including any error messages, memory dump etc that can help)

    opened by OniAdekunle 1
  • Bump jmespath from 1.4.0 to 1.6.1

    Bump jmespath from 1.4.0 to 1.6.1

    Bumps jmespath from 1.4.0 to 1.6.1.

    Release notes

    Sourced from jmespath's releases.

    Release v1.6.1 - 2022-03-07

    • Issue - Use JSON.parse instead of JSON.load.

    Release v1.6.0 - 2022-02-14

    • Feature - Add support for string comparissons.

    Release v1.5.0 - 2022-01-10

    • Support implicitly convertible objects/duck-type values responding to to_hash and to_ary.

      [See related GitHub pull request #51](jmespath/jmespath.rb#51).

    Changelog

    Sourced from jmespath's changelog.

    1.6.1 (2022-03-07)

    • Issue - Use JSON.parse instead of JSON.load.

    1.6.0 (2022-02-14)

    • Feature - Add support for string comparisons.

    1.5.0 (2022-01-10)

    • Support implicitly convertible objects/duck-type values responding to to_hash and to_ary.

      [See related GitHub pull request #51](jmespath/jmespath.rb#51).

    Commits

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language

    You can disable automated security fix PRs for this repo from the Security Alerts page.

    dependencies 
    opened by dependabot[bot] 0
  • I would want sample codes for Gh momo integration in java/Android studio

    I would want sample codes for Gh momo integration in java/Android studio

    Problem/Motivation

    (Why the issue was filed, steps to reproduce the problem, etc.)

    Proposed resolution

    (Description of the proposed solution, the rationale behind it, and workarounds for people who cannot use the patch.)

    Repeatable

    Always|Sometimes|Specific conditions|Specific times

    (If it is a bug, you are reporting lease specify:)

    Steps to repeat: (Describe how the issue can be repeated by someone who is to work on it)

    1. Step 1
    2. Step 2
    3. ...

    Expected Results:

    (What you expected steps 1, 2 and 3 to give)

    Actual Results:

    (What is gave including any error messages, memory dump etc that can help)

    opened by DanjummahLuwah 0
  • Setup CodeQL for SAST

    Setup CodeQL for SAST

    Setup CodeQL for SAST

    Commit to add CodeQL workflow for Static App Security Testing.

    Description

    Commit to add CodeQL workflow for Static App Security Scanning.

    Motivation and Context

    This commit allows us to run Github CodeQl as Github Actions and use CodeQL as a Static Application Security Testing tool to identify security vulnerabilities in code before it gets merged to master and deployments made.

    Acceptance Criteria

    Screenshots (if appropriate)

    Types of changes

    • [ ] Bug fix (non-breaking change which fixes an issue)
    • [x] New feature (non-breaking change which adds functionality)
    • [ ] Breaking change (fix or feature that would cause existing functionality to change)

    Checklist

    • [x] My pull request addresses exactly one patch/feature.
    • [x] I have created a branch for this patch/feature.
    • [x] Each individual commit in the pull request is meaningful. (Please rebase, removing useless commits if not)
    • [ ] I have added tests to cover my changes.
    • [ ] All new and existing tests passed.
    • [x] My code follows the code style of this project.
    • [ ] My change requires change(s) to the environment.
    • [ ] My change requires change(s) to the database.
    • [ ] Other information.

    Fixes #0 (Enter the number for the issue this fixes. If you have not yet created an issue, please do so now or delete this line if you are only submitting a patch)

    Changes made by this pull request

    CI skip-changelog 
    opened by eyitemi-paystack 2
Releases(v3.1.3)
Owner
Paystack
Paystack
Paystack
A robust Flutter plugin for making payments via Paystack Payment Gateway. Completely supports Android and iOS

?? Paystack Plugin for Flutter A Flutter plugin for making payments via Paystack Payment Gateway. Fully supports Android and iOS. ?? Installation To u

Wilberforce Uwadiegwu 165 Jan 4, 2023
Item selling mobile app with secure payments with Payhere payment gateway. Auto APK generation with github actions CI/CD.

payhere_demo A new Flutter project. Getting Started This project is a starting point for a Flutter application. A few resources to get you started if

Shihara Dilshan 2 Jan 20, 2022
Hybrid App build on flutter SDK able to run on Android, IOS, web, desktop

Codeforces Visualizer APP Ready to use Flutter Application. Uses codeforces API. Useful for codeforces programmers. ScreenShots Single User Page Compa

vikas yadav 13 Dec 31, 2022
A Flutter plugin that supports Pangle SDK on Android and iOS.

Thanks for non-commercial open source development authorization by JetBrains. 穿山甲 Flutter SDK `pangle_flutter`是一款集成了字节跳动穿山甲 Android 和 iOS SDK的 Flutter

null 121 Dec 2, 2022
Cross platform application for iOS and Android using Google's SDK Flutter.

scout Cross platform application for iOS and Android using Google's SDK Flutter. Launch screen for the application. The menu for selecting cookies. Cu

null 0 Nov 9, 2021
Quickstart guide for the Agora Flutter SDK(Android/iOS)

Agora Flutter Quickstart This tutorial describes how to create an Agora account and build a sample app with Agora using Flutter. Other Languages: 简体中文

Agora.io Community 501 Dec 30, 2022
Task List application developed in Dart language with SDK Flutter for Android, iOS and Web

Task List application developed in Dart language with SDK (Software Development Kit) Flutter for Android, iOS and Web.

João Bruno 2 Jun 2, 2022
A Flutter plugin for the Google Mobile Ads SDK

A Flutter plugin for the Google Mobile Ads SDK

Google Ads 251 Jan 2, 2023
P2P payment solution using Stream's Flutter SDK and Rapyd's Wallet API

Peer-to-peer payment integration to a messaging app using Flutter ?? This project shows how to integrate a peer-to-peer payment solution to your Strea

Souvik Biswas 15 Dec 8, 2022
Official plugin for using Thepeer SDK with flutter https://thepeer.co

Flutter Thepeer This package makes it easy to use the Thepeer in a flutter project. ?? Screen Shots ?? How to Use plugin ThePeer Send Launch ThepeerSe

The Peer 23 Dec 27, 2022
A simple chat app UI using flutter SDK project.

Chatty App A simple chat app UI using flutter SDK project. Screenshot Getting Started This project is a starting point for a Flutter application. A fe

Tengku Belmiro 5 Jul 15, 2022
Flutter SDK for Stripe.

Flutter Stripe The Stripe Flutter SDK allows you to build delightful payment experiences in your native Android and iOS apps using Flutter. We provide

null 633 Jan 7, 2023
Official Flutter SDK for Khalti Payment systems

Khalti Payment Gateway for Flutter Use Khalti Payment Gateway solution in your app or website to simplify payment for your customers. You do not need

Khalti 16 Oct 13, 2022
The official sdk for the user-friendly API of Mega services on the Dart language.

megasdkdart The official sdk for the user-friendly API of Mega services in the Dart language. Example: import 'package:megasdkdart/megasdkdart.dart';

meg4cyberc4t 4 Mar 30, 2022
Official sdk for vchat

V_Chat_SDK Micro service Check Our Full documention VCHAT DOCS Quick Review Android IOS Don't forget to see the example attached to github here V_CHAT

Hatem Ragab 42 Dec 17, 2022
This project is the HERE SDK reference application for Flutter

HERE SDK Reference Application for Flutter The reference application for the HERE SDK for Flutter (Navigate Edition) shows how a complex and release-r

HERE Technologies 32 Dec 15, 2022
A Social App Built Using FLutter SDK.

Hi ?? , I'm Faheem ??‍?? A Social App Built Using FLutter SDK. The main objective of this application is to provide a single platform for the Students

Faheem Ahmad 26 Nov 10, 2022
Flutter Video Conferencing SDK & Sample App

100ms Flutter SDK ?? Here you will find everything you need to build experiences with video using 100ms iOS/Android SDK. Dive into our SDKs, quick sta

100ms 79 Dec 22, 2022
Unofficial Dart SDK for Decentralized Social / DeSo.org

DeSo Dart SDK Unofficial Dart SDK for Decentralized Social / DeSo.org Report Bug · Request Feature Table of Contents About the Project Built With Gett

Deverse 8 Sep 16, 2022