Ionic Platform - SDK Integration

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

This integration will support the following flows:

  • App Flow: In case the PhonePe app is installed, The bottom pop up PhonePe payment page
    called QCLite flow 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, The android web view will be
    launched to complete the transaction and give the response back to your app.

Android Project of Ionic app

  1. Add the below code to 'repositories' section of your project level build.gradle file
// Top-level build file where you can add configuration options common to all sub-projects/modules.

allprojects {
   repositories {
       google()
       maven {
			url  "https://phonepe.mycloudrepo.io/public/repositories/phonepe-intentsdk-snapshots"
       }
   }
}
//https://dash.readme.com/project/phonepe-docs/v1/docs/android-pg-sdk-integration Top-level build file where you can add configuration options common to all sub-projects/modules.

allprojects {
   repositories {
       google()
       maven {
			url  "https://phonepe.mycloudrepo.io/public/repositories/phonepe-intentsdk-android"
       }
   }
}
  1. Add the below line to the 'dependencies' section of your app build.gradle.
implementation 'phonepe.intentsdk.android.snapshot:IntentSDK:1.6.8-478638-SNAPSHOT@aar’
implementation 'phonepe.intentsdk.android.release:IntentSDK:1.6.8@aar’

🚧

For, SDK version 1.6.8

We have compileSdkVersion: 28, minSdkVersion: 21, targetSdkVersion: 28

  1. Add below lines of code inside the 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"/>

<!-- The value will be the MID-->
<meta-data
   android:name="com.phonepe.android.sdk.MerchantId"
   android:value="MID"/>

<!-- 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 PhonePeSDKPlugin to your project (see Appendix at the end of this document).

  2. In the pre-existing MainApplication class while creating an instance of IonicHost there is a method
    onCreate(). In this method add PhonePeSDKPlugin class in ionic Package List.

  3. Update handleOnActivityResult method in PhonePeSDKPlugin class as per your response
    the requirement in the ionic native app.

  4. Call the startPaymentTransaction method from your Ionic Native app to invoke the PhonePe module.

Ionic Native Code

  1. Import Plugins from the capacitor package.
import { Plugins } from '@capacitor/core';
  1. Declare PhonePeSDKPlugin as per the ionic standards.
const { PhonePeSDKPlugin } = Plugins;
  1. In the ionic app.js
PhonePeSDKPlugin.doesPhonePeExists();
const isPhonePeAvailableListener =
Plugins.PhonePeSDKPlugin.addListener('isPhonePeAvailableListener', (value:any) =>
{
	/* Display PhonePe option in the checkout page only if variable display returns true */
	console.log('myPluginEvent was fired = '+value.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.

  3. Remove the listener from the PhonePeSDKPlugin object:
    isPhonePeAvailableListener.remove();

  1. Initiate the payment process by calling PhonePeSDKPlugin.startPaymentTransaction with the
    appropriate parameters.
var data =
{
	"base64EncodedData": “/* Pass the encoded base 64 data*/“,
	"checksum": “/“* Pass the checksum value */,
	"endpoint": “/* “End point */“,
	"xCallbackUrl": “/* Pass the server url */“
};

PhonePeSDKPlugin.startPaymentTransaction(data);
  • base64EncodedBody - pass the encoded payload request

  • checksum - pass the checksum value

  • endPoint - 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.

  1. Once you receive the UI callback from the handleOnActivityResult method. Kindly perform the
    following:
  • 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

PhonePeSDKPlugin.java

package io.ionic.starter;
import android.content.Intent;
import com.getcapacitor.JSObject;
import com.getcapacitor.NativePlugin;
import com.getcapacitor.Plugin;
import com.getcapacitor.PluginCall;
import com.getcapacitor.PluginMethod;
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 java.util.HashMap;
@NativePlugin(
    requestCodes = {
        PhonePeSDKPlugin.PHONEPE_REQUEST
    } // register request code(s) for
    intent results
)
public class PhonePeSDKPlugin extends Plugin {
    /**
     * variables
     */
    public static final int PHONEPE_REQUEST = 777;
    public void load() {
        // Called when the plugin is first constructed in the bridge
        PhonePe.init(getContext());
    }
    /**
     * Method to set whether PhonePe app is installed or not and send the event to the Ionic Code
     */
    @PluginMethod
    public void doesPhonePeExists(PluginCall call) {
        try {
            PhonePe.isUPIAccountRegistered(new ShowPhonePeCallback() {
                @Override
                public void onResponse(boolean b) {
                    JSObject mJSObject = new JSObject();
                    mJSObject.put("isPhonePeAvailable", "" + b);
                    notifyListeners("isPhonePeAvailableListener", mJSObject);
                }
            });
        } catch (PhonePeInitException e) {
            e.printStackTrace();
        }
    }
    /**
     * Method to launch the PhonePe payment page from the Ionic Native code
     * @param call
     */
    @PluginMethod
    public void startPaymentTransaction(PluginCall call) {
        saveCall(call);
        String base64Body = call.getString("base64EncodedData");
        String checksum = call.getString("checksum");
        String endPoint = call.getString("endpoint");
        String xCallbackUrl = call.getString("xCallbackUrl");
        HashMap < String, String > headers = new HashMap();
        headers.put("X-CHANNEL-ID", "phonepe_ionic_sdk");
        TransactionRequest mTransactionRequest;
        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();
        }
        try {
            startActivityForResult(call, PhonePe.getTransactionIntent(mTransactionRequest), 777);
        } catch (PhonePeInitException e) {}
        call.success();
    }
    // in order to handle the intents result, you have to @Override handleOnActivityResult
    @Override
    protected void handleOnActivityResult(int requestCode, int resultCode, Intent data) {
        super.handleOnActivityResult(requestCode, resultCode, data);
        // Get the previously saved call
        PluginCall savedCall = getSavedCall();
        if (savedCall == null) {
            return;
        }
        if (requestCode == PHONEPE_REQUEST) {
            // Send the UI callback to the ionic app
        }
    }
}

MainActivity.java

package io.ionic.starter;
import android.os.Bundle;
import com.getcapacitor.BridgeActivity;
import com.getcapacitor.Plugin;
import java.util.ArrayList;

public class MainActivity extends BridgeActivity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // Initializes the Bridge
        this.init(savedInstanceState, new ArrayList < Class << ? extends Plugin >> () {
            {
                // Additional plugins you've installed go here
                add(PhonePeSDKPlugin.class);
            }
        });
    }
}