Frontend Development 11 min read

Common Patterns for H5 and Native App Interaction via WebView Bridge

This article explains the typical interaction models between H5 (HTML5) pages embedded in mobile apps and native code, covering basic bridge interfaces, single‑direction and bi‑directional calls, implementation styles, and the trade‑offs of H5‑driven versus native‑driven architectures, with concrete code examples.

360 Tech Engineering
360 Tech Engineering
360 Tech Engineering
Common Patterns for H5 and Native App Interaction via WebView Bridge

The article, originally published in the 360 Qiwu Weekly, introduces the concept of H5 (HTML5) as the term used in China for web pages embedded inside mobile applications and explains that such pages run inside a WebView (UIWebView, WKWebView on iOS or Android WebView).

Interaction between the H5 page and the native app is achieved through two bridge objects injected into the WebView: NativeBridge (provided by the native side) and JSBridge (exposed by the H5 side). Each bridge defines a single method:

NativeBridge.callNative(action, params, whoCare) – called by JavaScript to request native functionality.

JSBridge.callJS(action, params, whoAmI) – called by native code to invoke JavaScript.

Typical parameters are:

action : a string identifying the operation.

params : a JSON object carrying data.

whoCare / whoAmI : numeric flags indicating which side should respond.

Basic Android example – adding a Java object to the WebView:

public void addJavascriptInterface(Object object, String name)

And a sample Java object:

class JsObject {
    @JavascriptInterface
    public String toString() { return "injectedObject"; }
}
webView.getSettings().setJavaScriptEnabled(true);
webView.addJavascriptInterface(new JsObject(), "injectedObject");
webView.loadData("", "text/html", null);
webView.loadUrl("javascript:alert(injectedObject.toString())");

On iOS the same principle applies using WKWebView to inject a native object.

Implementation patterns :

Attach all actions to JSBridge.callJS and dispatch them with a simple one‑liner:

window.JSBridge = {};
window.JSBridge.callJS = function({action, params, whoAmI}) {
    return window.JSBridge[action](params, whoAmI);
};

Or use a switch…case dispatcher to map actions to concrete functions.

function callJS(action, params, whoAmI) {
    params = JSON.parse(JSON.stringify(params));
    switch(action) {
        case 'showSkill':
            const category = params.category;
            JSBridge.showSkill(category);
            break;
        case 'showSkillDetail':
            const id = params.id;
            JSBridge.showSkillDetail(id);
            break;
        // …other actions
        default:
            // no‑op
    }
}

Single‑direction calls (JS → Native):

loadUrl – ask the native side to navigate to another URL.

loadContent – ask the native side to open a native screen.

NativeBridge.callNative({
    action: 'loadUrl',
    params: {url: 'https://example.com'},
    whoCare: 0
});

Native side parses the action and performs the requested operation.

Native → JS single‑direction call (e.g., back‑button handling):

JSBridge.callJS({
    action: 'can_back',
    params: {},
    whoAmI: 1/2
});
// Returns {can: true, target: 'prev'} or {can: false, target: 'prev'}

Bi‑directional calls involve JS invoking a native component and the native side later calling back with results. Example – showing a location picker:

NativeBridge.callNative({
    action: 'loadComponent',
    params: {type: 'location', value: null, callbackName: 'set_location'},
    whoCare: 0
});
// After user picks a city, native calls back:
JSBridge.callJS({
    action: 'set_location',
    params: {value: '北京市朝阳区'},
    whoAmI: 1
});

Another bi‑directional example is the displayNextButton protocol, where JS tells native to show a “Next/Save/Done” button and optionally disables it:

NativeBridge.callNative({
    action: 'displayNextButton',
    params: {name: '下一步', enable: false, callbackName: 'save_form'},
    whoCare: 0
});
// When the user taps the button, native calls back:
JSBridge.callJS({action: 'save_form', params: {}, whoAmI: 1});

The article concludes with a discussion on which side should lead the interaction. In the presented examples the H5 side is dominant, keeping most business logic inside the WebView and letting the native app act as a thin coordinator, which simplifies version management for the native side.

frontendmobileWebViewH5JavaScript Bridge
360 Tech Engineering
Written by

360 Tech Engineering

Official tech channel of 360, building the most professional technology aggregation platform for the brand.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.