Skip to content
NEWCollect for MSMEs: UPI Autopay, eNACH & remindersExplore app ↗

Android

Use Android WebView when you want to launch the Jodo-hosted flow inside your native Android app.

  1. Fetch the Jodo redirect_url from your backend.
  2. Load the URL in a WebView.
  3. Enable JavaScript, DOM storage, and multiple windows.
  4. Handle UPI deep links using Android intents.
  5. Detect your callback_url and return the user to your app flow.
  6. Confirm final status from your backend.

The app should not call Jodo directly with server credentials. Call your ERP or backend API, and let that backend create the Jodo flow and return the redirect_url.

Include a callback_url that your WebView can identify after the payment flow completes.

Handle these cases explicitly:

  • UPI intent: When a user selects a UPI app, Android should open the UPI intent instead of trying to load upi:// inside the WebView.
  • Bank authentication: Net banking and card flows may open popups or new windows.
  • Callback redirect: Detect your callback_url and close checkout or show a status screen.
  • Back navigation: Decide whether back should navigate WebView history, close a child WebView, or exit checkout.
package com.example.jodocheckout;
import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Message;
import android.view.View;
import android.webkit.WebChromeClient;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
private static final String CALLBACK_URL = "https://example.com/jodo/callback";
private WebView parentWebView;
private WebView childWebView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
parentWebView = findViewById(R.id.parentWebView);
childWebView = findViewById(R.id.childWebView);
configureWebView(parentWebView);
configureWebView(childWebView);
String redirectUrl = "<redirect_url_from_your_backend>";
parentWebView.loadUrl(redirectUrl);
parentWebView.setWebChromeClient(new CheckoutChromeClient(childWebView));
}
private void configureWebView(WebView webView) {
webView.getSettings().setJavaScriptEnabled(true);
webView.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);
webView.getSettings().setSupportMultipleWindows(true);
webView.getSettings().setDomStorageEnabled(true);
webView.setWebViewClient(new WebViewClient() {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
if (url.startsWith(CALLBACK_URL)) {
handleCheckoutComplete(url);
return true;
}
if (url.startsWith("http://") || url.startsWith("https://")) {
return false;
}
if (url.startsWith("upi://pay")) {
openIntent(url);
return true;
}
openIntent(url);
return true;
}
});
}
private void openIntent(String url) {
try {
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
startActivity(intent);
} catch (ActivityNotFoundException error) {
Toast.makeText(this, "No app found to complete this action.", Toast.LENGTH_SHORT).show();
}
}
private void handleCheckoutComplete(String callbackUrl) {
// Close checkout and ask your backend for final status.
}
}
class CheckoutChromeClient extends WebChromeClient {
private final WebView childWebView;
CheckoutChromeClient(WebView childWebView) {
this.childWebView = childWebView;
}
@Override
public boolean onCreateWindow(WebView view, boolean isDialog, boolean isUserGesture, Message resultMsg) {
WebView.WebViewTransport transport = (WebView.WebViewTransport) resultMsg.obj;
transport.setWebView(childWebView);
resultMsg.sendToTarget();
childWebView.setWebChromeClient(new CheckoutChromeClient(childWebView));
childWebView.setVisibility(View.VISIBLE);
return true;
}
@Override
public void onCloseWindow(WebView window) {
childWebView.setVisibility(View.INVISIBLE);
}
}

Add internet permission. If your app handles deep links or UPI return flows, configure the relevant intent filters for your application.

<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.INTERNET" />
<application>
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
  • UPI app selection and return to checkout
  • Net banking popup creation and closure
  • Card authentication redirects
  • Callback URL detection
  • User closes checkout before completion
  • Backend status remains pending after callback