DEV Community

Cover image for Flutter Paystack All Options Implementation
George Ikwegbu Chinedu
George Ikwegbu Chinedu

Posted on • Updated on

Flutter Paystack All Options Implementation

Table of Content

🕹 Introduction

As at the time of writing this article, paystack integration for android and mobile SDK, only supports card payments and bank (with just Zenith as the option).

In this article, you will learn how to include other payment options in your flutter application.

PS: I'm assuming you are familiar with flutter and 
paystack with all the necessary keys and how to get them 
from your paystack dashboard.
Enter fullscreen mode Exit fullscreen mode

Before we continue, please take a quick look at this article from Paystack, that's where I got ideas from 😋. If you want, you could use that article, or continue reading.

📡 Required Paystack Details and Endpoints

You will need your paystack secret_key (use the test key for testing and live key for prod) as your Bearer token in your Authorization header while making a POST request to the paystack initialize api.

Check the below images for better understanding.

Setting your authorization header with secret_key

Postman Authorization Header Bearer token

POST body details

POST body details

email: This is the payers email.

amount: This is the amount to be paid, please multiply by 
        100, to remove the kobo value

reference: This should be randomly generated as it should 
           be a unique value for each payment.

callback_url: This is the most important part. If you 
              already have a callback url, setup from your 
              paystack dashboard, you don't need this 
              parameter. If you still go ahead to include 
              it, it'll override that of the dashboard. 
              This callback_url is what we will be 
              listening for from our webview.

cancel_action: This will be used to listen for when the 
               user wants to cancel payment, we then pop 
               the webview screen.
Enter fullscreen mode Exit fullscreen mode

Response from paystack API

Paystack Response

authorization_url: This is the most important data we will 
                   be needing for our webview, so hold on 
                   to it 😎.
Enter fullscreen mode Exit fullscreen mode

🖲 Installing WebView Package

To install this package, please visit this link, read through the setup and install it.

🛢 Making API calls in Flutter

This approach depends on which architecture you're using to build your application, at the end, it's all the same response you will receive. In this article, i'll be keeping it really simple 🥹.

var headers = {
  'Authorization': 'Bearer sk_test_039***************',
  'Content-Type': 'application/json',
};
var request = http.Request('POST', Uri.parse('https://api.paystack.co/transaction/initialize'));
request.body = json.encode({
  "email": "g.ikwegbu@gmail.com",
  "amount": "10000",
  "reference": "randomDetails",
  "callback_url": "https://github.com/gikwegbu",
  "metadata": {"cancel_action": "https://www.google.com/"}
});
request.headers.addAll(headers);

http.StreamedResponse response = await request.send();

if (response.statusCode == 200) {
  print(await response.stream.bytesToString());
}
else {
  print(response.reasonPhrase);
}

Enter fullscreen mode Exit fullscreen mode


PS: I personally love using the flutter dio package

Retrieve the authorization_url from the response and store 
it in a global variable.
Enter fullscreen mode Exit fullscreen mode

📲 Displaying Paystack pop-up in webView

Ok, let's be on the same page here 🙃. We are building an application that allows users make payment for an item via paystack.

🏳️ The Data Flow:

when the user clicks on the PAY button, the paystack pops-up, user selects whichever option that's suitable, and proceed. Once the payment is successful, we will be redirected to a callback_url. Once this happens, we will have to be listening for that callback_url, which when detected, allows us to close the webview widget, and then continue with sending our reference code to our server to complete checking out of the PAID item.

🏳️ Implementation:

To make the process seamless, i'd be using a popup dialog, set it to fullscreen to overlay our current page, add the webview widget.

Below is a code snippet that will help you understand more:


// This is called when the PAY button is clicked.
_showPaystack() async {
    var _ref = 'ChargedFromMyApp_${DateTime.now().millisecondsSinceEpoch}';
    Map data = {
      // Removing the kobo by multiplying with 100
      "amount": double.parse('${_amount * 100}').toInt(),
      "email": _user.email,
      "reference": _ref,
      "callback_url": "https://github.com/gikwegbu",
      "metadata": {"cancel_action": "https://www.google.com/"}
    };
    // This awaits the [authorization_url](#authUrl). NB: I'm using the MVVM architecture in my live code, but it's still the same process of retrieving the authURL.
    var authUrl = await _profileCtrl.paystackWebViewChargeCard(data);

    // only pull-up the dialog box when we get the authURL
    if (authUrl != null) {
      return showGeneralDialog(
          context: context,
          barrierDismissible: true,
          barrierLabel:
              MaterialLocalizations.of(context).modalBarrierDismissLabel,
          barrierColor: Colors.black45,
          transitionDuration: const Duration(milliseconds: 200),
          pageBuilder: (BuildContext buildContext, Animation animation,
              Animation secondaryAnimation) {
            return Center(
                child: Container(
              width: MediaQuery.of(context).size.width - 10,
              // height: MediaQuery.of(context).size.height - 80,
              height: MediaQuery.of(context).size.height - 0,
              padding: const EdgeInsets.only(top: 40),
              color: Colors.white,
              child: WebView(
                initialUrl: authUrl.toString(),
                javascriptMode: JavascriptMode.unrestricted,
                userAgent: 'Flutter;Webview',
                navigationDelegate: (navigation) {
                  //Listen for callback URL
                  if (navigation.url == "https://standard.paystack.co/close") {
                    Navigator.of(context).pop(); //close webview

                    // _txnRef is my glabally created variable to handle my reference
                    _txnRef = _ref;
                    _submit();
                  }
                  if (navigation.url ==
                      "github.com/gikwegbu?trxref=$_ref&reference=$_ref") {
                    Navigator.of(context).pop();
                    _txnRef = _ref;
                    _submit();
                  }
                  if (navigation.url == "https://www.google.com/") {
                    Navigator.of(context).pop();
                  }
                  return NavigationDecision.navigate;
                },
              ),
            ));
          });
    }
  }

Enter fullscreen mode Exit fullscreen mode
The _submit(), is a function that sends the reference to 
my backend to complete the purchase transaction on the 
selected item.
Enter fullscreen mode Exit fullscreen mode

💾 Listening For Navigation url

From the above code snippet, you'd have noticed the navigationDelegate section, this is where you'll handle listening for the callback_url and also, in the case the user is making payments with a Card, and the 3Ds Authentication will have to redirect you to the 'https://standard.paystack.co/close'. Other than that, we will listen for our custom callback_url, and then pop our screen.

💙 Important Note For Release apk

The application will actually work while in debug mode, but will through an error or not work at all in released build, as you'd only be seeing a gray overlay.

Steps Taken to Resolve this.

  1. Add
<uses-permission android:name="android.permission.INTERNET" />
Enter fullscreen mode Exit fullscreen mode

in your android/app/src/main/AndroidManifest.xml.

  1. Add
if (Platform.isAndroid) WebView.platform = AndroidWebView();
Enter fullscreen mode Exit fullscreen mode

Inside of your initState(){} function of your file. This means you'd have to be using a "Stateful" widget.

  1. This is the most important. Run
flutter run --release
Enter fullscreen mode Exit fullscreen mode

This would help you build your app as in 'release mode', but you can still be seeing your debugs in your console. Now watch closely if you see an error like I/flutter (18782): Another exception was thrown: Instance of 'DiagnosticsProperty<void>', if so, then please look for where Expanded widget was used in your implementation and remove it.

Finally

We have successfully integrated our paystack payment system with multiply option into our flutter application. To experience the multiple option, please change from your test secret key to your live secret key, only then will you see the

Latest comments (1)

Collapse
 
_7thrichard profile image
Richard Iwo

Hello @gikwegbu can I get the source code?