How To Integrate PayTM Payment Gateway in Flutter App?

Payment integration in Flutter

This modernized era is all on the Internet, from shopping to booking to hiring a cab. The online shopping trends are evolving tremendously with time and competition among e-sellers is increasing continuously. Therefore, it has been essential for online retailers or e-commerce owners to opt for the latest technology trends to make shopping easier for their customers.

The online payment system has made online shopping convenient for customers and is being adopted by many e-commerce businesses. However, taking payments online is a big task and hence you need to integrate a payment gateway that would handle all the security and other aspects of collecting payment for you.

Since, the Flutter is an emerging technology stack in the market, because, before Flutter, cross-platform app development was a tough deal for the developers. Flutter being the best in terms of performance, won the market of cross-platform app development. Flutter is loaded with easy to implement tools and has become the primary choice for MVP development. Flutter has many advantages like:

  • Material Design & Cupertino widgets Support
  • Hot Reload makes the development instantaneous
  • Performance is similar to Native features
  • Easy to Learn & Implement

Flutter is a brainchild of Google and is backed by a lot of investment, time and energy. As Google is behind the Flutter, we can be sure that Flutter is the future of app development.

Flutter relies on the Dart programming language and has Firebase libraries which allow an easy backend development for MVP. So, we can say that Flutter is loaded with revolutionary features and tactics, to make the cross-platform app development an easy and convenient process. Also, the app development with Flutter is more cost-effective than Native platforms.

Payment Gateway Integration is a soaring trend in the app development industry. This has made online purchasing easier for both sellers and buyers as a seller does not need to wait for the payment and the buyer can make a hassle-free online payment. Integrating payment gateways in an application allows a successful payment in just a few clicks. Nowadays many services require an option of online payment and many payment gateways are available for the same.

Now, let’s talk about PayTM payment gateway integration in Flutter. Flutter is a cross-platform app development framework which supports Android and iOS platform. Apps on Flutter are built using a high-performance language called Flutter.

And, PayTM is a rising Indian online payment system that comes with the feature of a digital wallet. This payment gateway is used by many vendors and customers and hence, it’s essential to know how to integrate this in a Flutter application.

The Magic Sauce- Platform Channels on Flutter

One of the things that make Flutter so great for Cross-platform app development is the fact that you can easily integrate platform-specific code in your Flutter app. This is made possible thanks to Platform Channels. This indigenous invention can be handy in tricky places where Flutter lacks functionally. 

In our case, we’re going to use Platform Channels to call Native Android code written in Java from the Flutter app. This is how it’s going to work-

Paytm Integration in Flutter App
  • Get Checksum from the Server
  • Start Android channel with necessary parameters
  • Get results from the channel to Flutter
  • Send appropriate response back to the server

Here’s how you can integrate the PayTM payment gateway in Flutter App for Android-

  • Install the PayTM SDK (add the below lines to android/app/build.gradle)
dependencies {
    compile('com.paytm:pgplussdk:1.4.4') {
        transitive = true; 
    }
}
  • Here’s how your MainActivity (which extends FlutterActivity) should look like-   
public class MainActivity extends FlutterActivity implements MethodChannel.MethodCallHandler {

 private static final String CHANNEL = "package_name/payment";

 private PaytmPGService service;
 private Map<String, String> mapCredentials;
 private PaytmOrder paytmOrder;

 private String orderId;
 private MethodChannel.Result result;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   GeneratedPluginRegistrant.registerWith(this);

   new MethodChannel(getFlutterView(), CHANNEL)
           .setMethodCallHandler(this);


 }

 @Override
 public void onMethodCall(MethodCall methodCall, MethodChannel.Result result) {
   this.result = result; //save the reference to result object to be used later
   HashMap args = (HashMap) methodCall.arguments; //passed from Flutter code

   orderId = args.get("order_id").toString();

   service = PaytmPGService.getStagingService();
   mapCredentials = new HashMap<>();
   mapCredentials.put("MID", args.get("mid").toString());
   mapCredentials.put("ORDER_ID", args.get("order_id").toString());
   mapCredentials.put("CUST_ID", args.get("customer_id").toString());
   mapCredentials.put("MOBILE_NO", args.get("customer_phone").toString());
   mapCredentials.put("EMAIL", args.get("customer_email").toString());
   mapCredentials.put("CHANNEL_ID", "WAP");
   mapCredentials.put("TXN_AMOUNT", args.get("amount").toString());
   mapCredentials.put("WEBSITE", "WEBSTAGING");
   mapCredentials.put("INDUSTRY_TYPE_ID", "Retail");
   mapCredentials.put("CALLBACK_URL", args.get("callback_url") + orderId);
   mapCredentials.put("CHECKSUMHASH", args.get("checksum").toString());

   paytmOrder = new PaytmOrder((HashMap<String, String>) mapCredentials);
   service.initialize(paytmOrder, null);
   service.startPaymentTransaction(MainActivity.this, true, true, new PaytmPaymentTransactionCallback() {
     @Override
     public void onTransactionResponse(Bundle inResponse) {
       if(inResponse.getString("STATUS").equals("TXN_FAILURE")) {
         result.error("TXN_FAILURE", "Transaction Failure", null);
       }
       else {
         result.success(1);
       }
       Log.d("PayTM", inResponse.toString());
     }

     @Override
     public void networkNotAvailable() {
       result.success(0);
       Toast.makeText(getApplicationContext(), "Network Not Available please check your internet", Toast.LENGTH_LONG).show();
     }

     @Override
     public void clientAuthenticationFailed(String inErrorMessage) {
       result.success(0);
       Toast.makeText(getApplicationContext(), "Client Authentication failed " + inErrorMessage.toString(), Toast.LENGTH_LONG).show();
     }

     @Override
     public void someUIErrorOccurred(String inErrorMessage) {
       result.success(0);
       Toast.makeText(getApplicationContext(), "Error response " + inErrorMessage.toString(), Toast.LENGTH_LONG).show();
     }

     @Override
     public void onErrorLoadingWebPage(int iniErrorCode, String inErrorMessage, String inFailingUrl) {
       result.success(0);
       Toast.makeText(getApplicationContext(), "Error response " + inErrorMessage.toString(), Toast.LENGTH_LONG).show();
     }

     @Override
     public void onBackPressedCancelTransaction() {
       result.success(0);
       Toast.makeText(getApplicationContext(), "onBackPressedCancelTransaction", Toast.LENGTH_LONG).show();
     }

     @Override
     public void onTransactionCancel(String inErrorMessage, Bundle inResponse) {
       result.success(0);
       Toast.makeText(getApplicationContext(), "Error response " + inErrorMessage.toString(), Toast.LENGTH_LONG).show();
     }
   });
 }

}

And this is how you should call the above channel from Flutter-

Future<void> _startPayment(Map orderMap) async {
 //1. Create a channel
 //2. Pass the parameters
//3. Check for results

 final params = {
   "order_id": orderMap['id'],
   "customer_id": orderMap['customer_id'],
   "amount": _shippingCharges['final_amount'],
   "customer_email": orderMap['billing']['email'],
   "customer_phone": orderMap['billing']['phone']
   "callback_url": orderMap[“callback_url”]
   "checksum": orderMap[“checksum”]
 };
 try {
   final int result = await platform.invokeMethod("startPayment", params);
   if (result == 1) {
     Fluttertoast.showToast(msg: "Payment Successful!");
     if (order != null) {
    //Payment done
     }
   }
 } on PlatformException catch (e) {
   Fluttertoast.showToast(msg: e.toString());
 }
 return null;
}

The most important part is saving the reference to the result object as a class variable so that it can be used again in the payment callbacks.

By using the above coding you can integrate the PayTm system in a Flutter application. Just a bit of coding and your application becomes all digitized.