Custom Checkout Integration - Android

The integration can be completed in three steps and should not take more than 30 minutes.

  • Create Order Create an order in Cashfree's system from your backend
  • Pay Order - Do a form submit from your app’s webview as mentioned in this document.
  • Handle redirection Detect URL redirection to return URL and close the webview

📘

Reach out to your account manager as this integration requires your application's package name to be whitelisted by Cashfree.

Create Order

Please follow the steps mentioned in this link to create an order.

This will return a "payment_session_id" value which will be used later.

📘

Don't forget to provide the return URL while creating the order as this will be used to detect payment completion.

Pay Order

String platform = "chxx-c-x-x-x-w-x-a-" + android.os.Build.VERSION.SDK_INT;
String paymentSessionID = "PAYMENT_SESSION_ID";
String env = "SANDBOX"; // or "PROD"
String formURL = env.equals("SANBOX")? "https://sandbox.cashfree.com/pg/view/sessions/checkout" : "https://api.cashfree.com/pg/view/sessions/checkout"

String htmlForm = "<html>\n" +
                "\n" +
                "<body>\n" +
                "    <form id=\"redirectForm\" method=\"post\" action=\""+formURL+"\"> \n" +
                "        <input\n" +
                "            type=\"hidden\" name=\"payment_session_id\"\n" +
                "            value=\""+paymentSessionID+"\" />\n" +
                "     
                "        <input type=\"hidden\" name=\"platform\"\n" +
                "            value=\""+platform+"\" /></form>\n" +
                "    <script\n" +
                "        type=\"text/javascript\">\twindow.onload = function () { const form = document.getElementById(\"redirectForm\"); const meta = { userAgent: window.navigator.userAgent, }; const sortedMeta = Object.entries(meta).sort().reduce((o, [k, v]) => { o[k] = v; return o; }, {}); const base64Meta = btoa(JSON.stringify(sortedMeta)); FN = document.createElement('input'); FN.setAttribute('type', 'hidden'); FN.setAttribute('name', 'browser_meta'); FN.setAttribute('value', base64Meta); form.appendChild(FN); form.submit(); }  </script>\n" +
                "</body>\n" +
                "\n" +
                "</html>";

yourWebView.getSettings().setJavaScriptEnabled(true);
yourWebView.getSettings().setDomStorageEnabled(true);
loadDataWithBaseURL("", htmlForm, "text/html", Xml.Encoding.UTF_8.name(), "");

Handle Redirection

Once the payment flow has ended cashfree page will redirect to the URL you have specified while creating the order. Detect the URL redirection to this return URL and close the webview appropriately.

yourWebView.setWebViewClient(new WebViewClient(){
            @Override
            public boolean shouldOverrideUrlLoading(WebView view, String url) {
                //Find if the url is the return URL you gave while creating the order 
                // and close the webview
                return super.shouldOverrideUrlLoading(view, url);
            }
        });

UPI Intent from Checkout

If you are doing a custom integration of Cashfree's Web Checkout in Android and want to add UPI intent functionality, then follow the steps below. Read more about UPI Intent functionality from here.

  1. Add the queries element in AndroidManifest file.
  2. Add the JSBridge functions for the checkout page to get the list of UPI apps installed and for opening the UPI app selected by the user.
  3. Once the user comes back from the UPI app, inside onActivityResult function notify the checkout page by calling a javascript function inside the checkout page.

You need to add the following to your AndroidManifest.xml

<manifest package="com.example.game">
<queries>
    <intent>
        <action android:name="android.intent.action.VIEW" />
        <data android:scheme="upi" android:host="pay"/>
    </intent>
    <package android:name="com.android.chrome" />
</queries>
    ...
</manifest>

Sample Code

import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.ResolveInfo;
import android.net.Uri;

import org.json.JSONArray;
import org.json.JSONObject;

import java.util.List;

public class CFWebIntentJSInterface {
    private final CFWebIntentInterface cfWebIntentInterface;

    public CFWebIntentJSInterface(CFWebIntentInterface cfWebIntentInterface) {
        this.cfWebIntentInterface = cfWebIntentInterface;
    }

    public interface CFWebIntentInterface {
        List<ResolveInfo> getAppList(String link);

        String getAppName(ApplicationInfo pkg);

        void openApp(String appPkg, String url);

        void enableDisableCancelButton(Boolean flag);
    }

    @android.webkit.JavascriptInterface
    public void enableCancelButton() {
        this.cfWebIntentInterface.enableDisableCancelButton(true);
    }

    @android.webkit.JavascriptInterface
    public void disableCancelButton() {
        this.cfWebIntentInterface.enableDisableCancelButton(false);
    }

    @android.webkit.JavascriptInterface
    public String getAppList(String name) {
        final List<ResolveInfo> resInfo = cfWebIntentInterface.getAppList(name);
        JSONArray packageNames = new JSONArray();
        try {
            for (ResolveInfo info : resInfo) {
                JSONObject appInfo = new JSONObject();
                appInfo.put("appName", cfWebIntentInterface.getAppName(info.activityInfo.applicationInfo));
                appInfo.put("appPackage", info.activityInfo.packageName);
                packageNames.put(appInfo);
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }

        return packageNames.toString();
    }

    @android.webkit.JavascriptInterface
    public boolean openApp(String upiClientPackage, String upiURL) {
        cfWebIntentInterface.openApp(upiClientPackage, upiURL);
        return true;
    }
}
public class YourWebViewActivity extends AppCompatActivity implements CFWebIntentJSInterface.CFWebIntentInterface {
    private boolean backEnabled = true;
  private WebView yourWebView;
    private static final int REQ_CODE_UPI = 9901;

  @SuppressLint({"SetJavaScriptEnabled", "AddJavascriptInterface"})
  @Override
  protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
    ...

        yourWebView.getSettings().setJavaScriptEnabled(true);
        yourWebView.getSettings().setDomStorageEnabled(true);

        CFWebIntentJSInterface wbInInterface = new CFWebIntentJSInterface(this);
        yourWebView.addJavascriptInterface(wbInInterface, "Android");

    ...
      
    }
  
  
  @Override
  public List<ResolveInfo> getAppList(String link) {
        ArrayList<ResolveInfo> resolveInfos = new ArrayList<>();
        Intent shareIntent = new Intent(Intent.ACTION_VIEW);
        shareIntent.setData(Uri.parse(link));
        final List<ResolveInfo> resInfos = getPackageManager().queryIntentActivities(shareIntent, 0);
        if (resInfos != null) {
            resolveInfos = new ArrayList<>(resInfos);
        }
        return resolveInfos;
    }
  
  @Override
  public String getAppName(ApplicationInfo pkg) {
        return (String) getPackageManager().getApplicationLabel(pkg);
  }
      
  @Override
  public void openApp(String appPkg, String url) {
        final Intent intent = new Intent();
        intent.setAction(Intent.ACTION_VIEW);
        intent.setData(Uri.parse(url));
        runOnUiThread(() -> {
            if ("others.upiapp".equals(appPkg)) {
                Intent chooser = Intent.createChooser(intent, "Pay with");
                startActivityForResult(chooser, REQ_CODE_UPI);
            } else {
                intent.setPackage(appPkg);
                startActivityForResult(intent, REQ_CODE_UPI);
            }
        });
    }

    @Override
    public void enableDisableCancelButton(Boolean flag) {
        backEnabled = flag;
    }
  
  @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && requestCode == REQ_CODE_UPI) {
            yourWebView.evaluateJavascript("window.showVerifyUI()", (ValueCallback<String>) s -> {});
        }
    }
  
  @Override
    public void onBackPressed() {
        if (backEnabled)
            super.onBackPressed();
  }
}