# JsBridge: Bidirectional Java and JavaScript Communication for Android WebView

> JsBridge is an Android library that connects Java code to JavaScript running in a WebView, supporting calls in both directions, persistent multi-response callbacks, and an optional domain whitelist that restricts which origins can invoke native methods.

**happydog-intj/JsBridge** — android java and javascript bridge, inspired by wechat webview jsbridge

- Repository: https://github.com/happydog-intj/JsBridge
- Stars: 9,908 · Forks: 2,001
- Language: Java
- License: not declared
- Published: 2026-09-21 · Updated: 2026-09-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/happydog-intj-jsbridge

## What JsBridge Solves in Android WebView Development

Android's WebView provides a built-in addJavascriptInterface() method for exposing Java objects to JavaScript, but it has well-documented security issues in older API levels and an awkward callback model. When JavaScript needs to invoke Java code and receive a response, the standard interface provides no direct mechanism: the developer must manage response routing manually.

JsBridge addresses this with a handler-based messaging system that works in both directions with explicit callbacks. Java code can call a JavaScript handler by name and receive a response through a callback interface. JavaScript code can call a Java handler and receive a response the same way. The callback mechanism is explicit rather than implicit, and the response routing is managed by the library rather than by application code.

The README describes the library as a bridge between Android Java and JavaScript for WebView, inspired by the WeChat WebView JSBridge. The target user is an Android developer embedding a WebView that needs to exchange data between the native layer and the web content it displays, whether that content is a local HTML file or a remote page.

Android's raw evaluateJavascript() method lets Java call into JavaScript but provides no structured way to receive a response. The developer has to invent a calling convention, typically by having JavaScript call back through another evaluateJavascript or addJavascriptInterface invocation with the result. JsBridge formalizes that pattern: every call has a named handler on the receiving side and a callback on the calling side, so the response arrives at a predictable location without any custom routing code in the application. This removes a class of bugs where responses arrive at the wrong callback or in the wrong order when multiple asynchronous calls are in flight simultaneously. The library manages a callback registry keyed by call identifier, and each callback is matched to its call by that identifier rather than by sequencing.

## Installing JsBridge via JitPack

JsBridge is distributed through JitPack rather than Maven Central. The installation requires two Gradle changes. First, add the JitPack repository to the project-level settings.gradle or build.gradle:

```groovy
repositories {
    maven { url "https://jitpack.io" }
}
```

Then add the dependency at the module level:

```groovy
dependencies {
    implementation 'com.github.happydog-intj:JsBridge:v2.1.0'
}
```

The library is in the library/ directory of the repository. The example/ directory contains a working Android application that demonstrates both the BridgeWebView and BridgeHelper integration paths.

## BridgeWebView: The Drop-In Integration Path

For projects that can replace their standard WebView with a custom subclass, BridgeWebView is the primary integration point. Add it to the layout:

```xml
<com.github.lzyzsd.jsbridge.BridgeWebView
    android:id="@+id/webView"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />
```

In the Activity, initialize it and register the JavaScript interface:

```java
BridgeWebView webView = findViewById(R.id.webView);
webView.setGson(new Gson());

webView.addJavascriptInterface(
    new MainJavascriptInterface(
        webView.getCallbacks(),
        webView.getPersistentCallbacks(),
        webView),
    "WebViewJavascriptBridge");

webView.loadUrl("file:///android_asset/demo.html");
```

The bridge JavaScript is injected automatically on page load. The JavaScript side does not need to include a separate script file. The WebViewJavascriptBridge object becomes available globally in the page context once injection completes.

The BridgeWebView subclass configures the underlying WebView with JavaScript enabled and a WebViewClient implementation that injects the bridge JavaScript on every page load. The injection happens in onPageStarted, so the bridge is available before the page's own JavaScript runs, and the WebViewJavascriptBridge global is present by the time any inline scripts execute. The setGson call on line four of the initialization block supplies a Gson instance for Java-side serialization. Any Java object passed as data to callHandler is serialized to JSON using that Gson instance before being handed to the JavaScript side. This means the data parameter in JavaScript always arrives as a JSON string, not a raw Java object, and the JavaScript side is responsible for parsing it with JSON.parse() if the data is structured. The README's examples pass a user object from Java, which Gson converts to a JSON string before the bridge sends it.

## Calling Between Java and JavaScript in Both Directions

Calls from Java to JavaScript work by registering a named handler on the JavaScript side, then calling it by name from Java. On the JavaScript side:

```javascript
WebViewJavascriptBridge.registerHandler("functionInJs", function(data, responseCallback) {
    document.getElementById("show").innerHTML = "data from Java: = " + data;
    responseCallback("Javascript Says Right back aka!");
});
```

From Java, call the registered handler:

```java
webView.callHandler("functionInJs", new Gson().toJson(user), new OnBridgeCallback() {
    @Override
    public void onCallBack(String data) {
        Log.d(TAG, "response from JS: " + data);
    }
});
```

Calls from JavaScript to Java work in the opposite direction. A class implementing BridgeWebView.BaseJavascriptInterface handles incoming calls:

```java
public class MainJavascriptInterface extends BridgeWebView.BaseJavascriptInterface {
    @Override
    public String send(String data) {
        return "default response";
    }
}
```

From JavaScript, invoking the Java handler:

```javascript
WebViewJavascriptBridge.callHandler(
    'submitFromWeb',
    {'param': 'value'},
    function(responseData) {
        document.getElementById("show").innerHTML = "response: " + responseData;
    }
);
```

Data is serialized as strings in both directions. The README examples use Gson for Java-side serialization and plain JSON in JavaScript.

## Persistent Callbacks for Multi-Response Scenarios

By default, a callback is removed from the registry after its first invocation. This is the standard request-response pattern. For scenarios where JavaScript needs to receive multiple responses from a single call, such as real-time updates, event streams, or progress notifications, the library provides persistent callbacks:

```java
webView.callHandlerPersistent("functionInJs", data, new OnBridgeCallback() {
    @Override
    public void onCallBack(String data) {
        Log.d(TAG, "called again: " + data);  // can be called multiple times
    }
});
```

The persistent callback remains in the registry until explicitly removed, so the JavaScript side can call the response callback multiple times and each call will reach the Java handler.

The distinction matters in practice: a file upload progress bar, a streaming text display, or a continuous sensor update all require the JavaScript side to push multiple data points back to Java without opening a new call for each one. Standard callbacks would require either one call per update or a polling model.

## Domain Whitelist Security and the BridgeHelper Path

The domain whitelist is a security feature that restricts which origins can invoke @JavascriptInterface methods through the bridge. By default, the whitelist is empty, meaning all origins are allowed. This preserves backward compatibility but leaves the bridge open to any page loaded in the WebView.

To restrict access:

```java
webView.addAllowedHost("example.com");
webView.addAllowedHost("*.example.com");  // wildcard for subdomains
```

Or use BridgeConfig for full control:

```java
BridgeConfig config = new BridgeConfig();
config.addAllowedHost("example.com");
webView.setBridgeConfig(config);
```

For projects using a custom WebView subclass that cannot extend BridgeWebView, the BridgeHelper class provides the same functionality without requiring the class hierarchy change. The custom WebView implements the IWebView interface, and BridgeHelper is held as a member:

```java
private BridgeHelper bridgeHelper = new BridgeHelper(this);
```

The whitelist applies to BridgeHelper through the same API:

```java
webView.bridgeHelper.addAllowedHost("example.com");
```

For projects that load content from URLs outside their own domain, setting the whitelist is the only mechanism the library provides to prevent third-party pages from calling native methods.

## JavaScript Bridge Readiness and Comparison with addJavascriptInterface

The bridge JavaScript is injected automatically on page load, but the injection is asynchronous. The README documents two patterns for checking readiness before using the bridge in JavaScript:

```javascript
function setupWebViewJavascriptBridge(callback) {
    if (window.WebViewJavascriptBridge) {
        return callback(WebViewJavascriptBridge);
    }
    if (window.WVJBCallbacks) {
        return window.WVJBCallbacks.push(callback);
    }
    window.WVJBCallbacks = [callback];
}
```

Alternatively, listen for the DOM event:

```javascript
document.addEventListener('WebViewJavascriptBridgeReady', function() {
    // bridge is now ready
}, false);
```

Compared to Android's built-in addJavascriptInterface(), JsBridge adds explicit callback management, named handler registration on both sides, persistent callbacks, and the whitelist security model. The trade-off is that both the Java layer and the JavaScript page must follow the bridge pattern: pages that do not register handlers cannot receive calls from Java, and Java code must use the bridge API rather than evaluateJavascript() directly. For a new project, this is straightforward. For a project with existing direct evaluateJavascript() calls, adopting JsBridge requires reworking those call sites.

## Repository Structure and What to Expect from the Example App

The repository is organized with the library in the library/ directory and a complete working example application in the example/ directory. The example app demonstrates all the integration patterns documented in the README: BridgeWebView initialization, Java-to-JavaScript calls, JavaScript-to-Java calls, persistent callbacks, and the domain whitelist.

The top-level build.gradle and settings.gradle configure the multi-module Android project. The library/build.gradle builds the JsBridge library module itself. Developers who want to inspect the bridge source code rather than consume it through JitPack can clone the repository and import the project into Android Studio directly.

The README includes a Chinese documentation section in addition to the English section, covering the same API with the same code examples. Both sections are part of the same README file, indicated by the [English] and [中文文档] anchor navigation at the top. The architecture diagram at the top of the README (JsBridgeWork.png) illustrates the two-way message flow between the JavaScript and Java layers.

The library README does not document the minimum Android API level required or a maximum tested version. The JitPack dependency uses version v2.1.0 as shown in the install example; the dependency version string com.github.happydog-intj:JsBridge:v2.1.0 is the current reference point from the README. There are no GitHub releases published in the repository; JitPack resolves the library version from the v2.1.0 git tag.

For projects that load content from a Content Security Policy-restricted domain, the domain whitelist feature interacts with the WebView's own origin model. The whitelist in BridgeConfig uses host strings and supports wildcard subdomain patterns (*.example.com), but the README does not document interaction with Android's WebSettings.setAllowFileAccessFromFileURLs() or WebSettings.setAllowUniversalAccessFromFileURLs() settings. Projects that load local HTML files from assets and also load remote pages should test the whitelist behavior against their specific URL patterns before relying on it as a security boundary.

## Conclusion

JsBridge fits Android projects that embed a WebView and need reliable two-way communication between Java code and JavaScript, without rewriting the WebView from scratch. The BridgeWebView drop-in path covers most cases. For teams using a custom WebView subclass, the BridgeHelper approach integrates without requiring a class hierarchy change. The domain whitelist is a meaningful security control that is off by default: any project loading untrusted URLs into the WebView should set allowed hosts explicitly. The repository has no license file listed and no GitHub releases; versioning is managed through JitPack against tags like v2.1.0. The last push was on 2026-09-12.

## FAQ

### What is JsBridge for Android?

JsBridge is an Android library that provides bidirectional communication between Java code and JavaScript running inside a WebView. It replaces direct addJavascriptInterface() usage with a named handler system that supports callbacks in both directions.

### What is a JsBridge method and how does it work?

A JsBridge method is a named handler registered on either the Java or the JavaScript side. Java registers @JavascriptInterface methods; JavaScript registers handlers with WebViewJavascriptBridge.registerHandler(). Callers on either side invoke a handler by name and pass a callback to receive the response.

### How do I handle the JsBridge method not found error?

This error occurs when one side calls a handler name that has not been registered on the other side. Verify that the JavaScript or Java handler is registered before any call is made to it. For JavaScript handlers, use the setupWebViewJavascriptBridge pattern documented in the README to ensure the bridge is ready before registering handlers.

## Sources

- [happydog-intj/JsBridge on GitHub](https://github.com/happydog-intj/JsBridge)
- [Issues](https://github.com/happydog-intj/JsBridge/issues)
- [README](https://github.com/happydog-intj/JsBridge/blob/master/README.md)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/happydog-intj-jsbridge
