Custom Checkout Integration - Android

Learn in detail about our custom checkout integration for android.

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

Integration Flow

  • Create Order - Create an order in Cashfree Payments system from your backend.
  • Pay Order - Submit the form from your application's web-view as mentioned in this document.
  • Handle redirection - Detect the URL redirection and close the web view.

πŸ“˜

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


Step 1: 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.


Step 2: 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(), "");

Step 3: Handle Redirection

Once the payment flow has ended, Cashfree Payments will redirect you to the URL specified while creating the order. Detect the URL redirection and close the web view 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 Payments Web Checkout in Android and want to add UPI intent functionality, follow the steps below. Read more about UPI Intent functionality 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, the onActivityResult function notifies 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();
  }
}