Flutter Platform - SDK Integration

To merchants who have built their app on the Flutter platform, PhonePe provides a bridge to conveniently integrate PhonePe SDK. On this page, we will highlight the steps required to integrate PhonePe SDK with the Flutter platform for your app. This platform helps you to build a seamless and responsive checkout experience for your application.

This integration will support the following flows:

  • App Inoke Flow: In case the PhonePe app is installed, it will be launched to complete the
    transaction and give the response back to your app.

  • Redirection Flow: In case the PhonePe app is not installed, PhonePe SDK will open a web-view
    to process transactions and give the response back to your app.

Follow the steps below to integrate PhonePe SDK in the Flutter app:

Android Project of Flutter

  1. Add the line below to the ‘repositories’ section of project-level build.gradle file.
maven {
    url "https://phonepe.mycloudrepo.io/public/repositories/phonepe-intentsdk-android"
}
  1. Add the line below to the ‘dependencies’ section of app build.gradle
implementation 'phonepe.intentsdk.android.release:IntentSDK:1.6.4'
implementation 'com.google.android.gms:play-services-ads-identifier:16.0.0'
  1. Add below lines of code inside application tag in the AndroidManifest.xml file
<!-- Keep it false in production environment-->
<meta-data
    android:name="com.phonepe.android.sdk.Debuggable"
    android:value="true"/>

<!-- Keep it false in production environment-->
<meta-data
    android:name="com.phonepe.android.sdk.isUAT"
    android:value="true"/>

<!-- Get the App Id from PhonePe-->
<meta-data
  android:name="com.phonepe.android.sdk.AppId"
  android:value="<your app id given by PhonePe>"/>
  1. Add CheckoutActivity in your project (see Appendix at the end of this document).

  2. Add OnActivityResult method in CheckoutActivity class as per your response requirement in the
    Flutter app.

Flutter App Code

  1. Import the services package in the main.dart file of the Flutter app.
import 'package:flutter/services.dart';
  1. Declare method channel to communicate with the native code from the Flutter App.
static const platform = const MethodChannel("Your channel name");
  1. In the main.dart file add the following to check whether PhonePe app is installed or Not:
void shouldShow() async{
    String isPhonePeAvailable;
    try{
        isPhonePeAvailable = await platform.invokeMethod("shouldShow");
    }catch(e){
        print(e);
    }
    print(isPhonePeAvailable);
}

🚧

Note

  1. Install the PhonePe PreProd app. Refer to this link.

  2. If returns true then display the PhonePe option on the checkout page or if returns false then do not display the PhonePe option on the checkout page.

  1. In the main.dart file add the following code to initiate the payment process.
    Pass all the parameters as shown below:
var data = <String, dynamic> {
    "base64Body" : “/“* pass the base64Body value */,
    "checksum" : “/“* pass the checksum value */,
    "apiEndPoint" : “/“* pass the api endpoint value */,
    "x-callback-url" : “/“* pass the callback url */
};

Below code calls the native method to initiate the payment process:

String uiCallbackValue;
try{
    uiCallbackValue = await platform.invokeMethod("startPaymentTransaction",data);
}catch(e){
    print(e);
}
  • base64EncodedBody - pass the encoded payload request

  • checksum - pass the checksum value

  • apiEndPoint - pass the endpoint

  • xCallbackUrl - This can be “” or else you can send your custom callback URL where you
    will receive the server to server callback response to your custom callback URL. Once
    the response is received you have to validate the checksum and invalid amount. Refer to this
    link for more details.

  • uiCallbackValue - This is a variable that will receive a user interface callback response
    from the startPaymentTransaction method.

👍

/This callback indicates only about completion of UI flow.
Inform your server to make the transaction
status call to get the status. Update your app with the
success/failure status.
/

🚧

Note

  • If data returns User Completed it indicates the payment has been completed.
  • If data returns User Cancelled it indicates the payment has been canceled just in case if the user presses the back button or aborts the transaction.
  • Inform merchant server about the completion of the transaction flow from merchant app

  • Merchant server should check the status with server to server callback or make the Check
    Transaction Status API call to the PhonePe server to check the transaction status (Even
    for User Cancelled callback)

  • The app should get the transaction status from the backend

  • Based on the result, the merchant must inform the user about the success or failure status
    of the transaction

References

  • For Accept Payment API, Refer to this link.

  • Use the Check Transaction Status API to check the status of the payment transaction. Refer to
    this link.

  • For refund API, Refer to this link.

Appendix

CheckoutAcitivity.java

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.phonepe.intent.sdk.api.PhonePe;
import com.phonepe.intent.sdk.api.PhonePeInitException;
import com.phonepe.intent.sdk.api.ShowPhonePeCallback;
import com.phonepe.intent.sdk.api.TransactionRequest;
import com.phonepe.intent.sdk.api.TransactionRequestBuilder;
import io.flutter.app.FlutterActivity;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugins.GeneratedPluginRegistrant;
import java.util.*;
public class CheckoutActivity extends FlutterActivity {
    private static final String CHANNEL = "Your channel name";
    private static final int DEBIT_REQUEST_CODE = 777;
    MethodChannel.Result mResult;
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        GeneratedPluginRegistrant.registerWith(this);
        // Initiate the PhonePe SDK
        PhonePe.init(this);
        new MethodChannel(getFlutterView(), CHANNEL).setMethodCallHandler(new MethodChannel.MethodCallHandler() {
            @Override
            public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
                mResult = result;
                if (call.method.equals("shouldShow")) {
                    try {
                        PhonePe.isUPIAccountRegistered(new ShowPhonePeCallback() {
                            @Override
                            public void onResponse(boolean b) {
                                mResult.success("" + b);
                            }
                        });
                    } catch (PhonePeInitException e) {
                        e.printStackTrace();
                    }
                } else if (call.method.equals("startPaymentTransaction")) {
                    final Map < String, Object > arguments = call.arguments();
                    TransactionRequest mTransactionRequest;
                    String base64Body = (String) arguments.get("base64Body");
                    String checksum = (String) arguments.get("checksum");
                    String endPoint = (String) arguments.get("apiEndPoint");
                    String xCallbackUrl = (String) arguments.get("x-callback-url");
                    HashMap < String, String > headers = new HashMap();
                    headers.put("X-CHANNEL-ID", "phonepe_flutter_sdk");
                    if (xCallbackUrl != null && xCallbackUrl.length() != 0 && !xCallbackUrl.isEmpty()) {
                        headers.put("X-CALLBACK-URL", xCallbackUrl);
                        headers.put("X-CALL-MODE", "POST");
                        mTransactionRequest = new TransactionRequestBuilder()
                            .setData(base64Body)
                            .setChecksum(checksum)
                            .setUrl(endPoint)
                            .setHeaders(headers)
                            .build();
                    } else {
                        mTransactionRequest = new TransactionRequestBuilder()
                            .setData(base64Body)
                            .setChecksum(checksum)
                            .setHeaders(headers)
                            .setUrl(endPoint)
                            .build();
                    }
                    //For Intent SDK call below function
                    try {
                        startActivityForResult(PhonePe.getTransactionIntent(
                            mTransactionRequest), DEBIT_REQUEST_CODE);
                    } catch (PhonePeInitException e) {}
                }
            }
        });
    }
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == DEBIT_REQUEST_CODE) {
            if (resultCode == Activity.RESULT_OK) {
                mResult.success("User Completed");
            } else if (resultCode == Activity.RESULT_CANCELED) {
                mResult.success("User Cancelled");
            }
        }
    }
}

Main.dart

void startPaymentTransaction() async {
    var data = < String,
        dynamic > {
            "base64Body": " /* pass the base64 body value */ ",
            "checksum": " /* pass the checksum value */ ",
            "apiEndPoint": " /* pass the api endpoint */ ",
            "x-callback-url": " /* pass the callback url value */ "
        };
    String uiCallbackValue;
    try {
        uiCallbackValue = await platform.invokeMethod("startPaymentTransaction", data);
    } catch (e) {
        print(e);
    }
    print(uiCallbackValue);
}
}