webview 中文文档 下载 App

JS 与 App 的双向桥接:addJavascriptInterface 和 evaluateJavascript

App → JS:evaluateJavascript

// App 端
webView.evaluateJavascript(
    "document.title",
    value -> Log.d("WebView", "页面标题:" + value)
);

注意:value 是 JSON 字符串(包括引号),直接 Log.d 会看到带引号的 "页面标题",需要手动 strip。

注入 JS 函数:

webView.evaluateJavascript(
    "myFunction('hello from Android')",
    null // 不关心返回值
);

JS → App:addJavascriptInterface

// App 端,一个普通类 + @JavascriptInterface 注解
class Bridge {
    @JavascriptInterface
    public void showToast(String msg) {
        Toast.makeText(MainActivity.this, msg, Toast.LENGTH_SHORT).show();
    }
}

// 暴露给 WebView
webView.addJavascriptInterface(new Bridge(), "AndroidBridge");

网页 JS 里调用:

// 点击按钮时调用
document.getElementById("btn").addEventListener("click", () => {
    window.AndroidBridge.showToast("你好,原生世界");
});

注意安全:@JavascriptInterface 从 Android 4.2 (API 17) 开始强制要求。低于 4.2 的设备不加注解也能调用,但这是个已知的安全漏洞——恶意网页可以通过反射访问 Android Runtime,不要忽视这个注解。

调用时机问题

正确顺序:

// 1. 先注册接口
webView.addJavascriptInterface(new Bridge(), "AndroidBridge");

// 2. 再注册 WebViewClient
webView.setWebViewClient(new WebViewClient() {
    @Override
    public void onPageFinished(WebView view, String url) {
        // 3. onPageFinished 里注入 JS
        view.evaluateJavascript("initPage()", null);
    }
});

// 4. 最后 loadUrl
webView.loadUrl("file:///android_asset/index.html");

实战场景

场景用哪个
网页要调相机 / 定位 / 支付addJavascriptInterface 暴露原生 API
App 要读取网页 DOM(标题、输入框内容)evaluateJavascript + return JS 表达式
App 要控制网页行为(触发某个 JS 函数)evaluateJavascript
双向事件通信JS 调 @JavascriptInterface 传数据 → App 处理 → App evaluateJavascript 回调

安全忠告

永远不要暴露敏感方法 —— 只要网页代码跑在你的 WebView 里,恶意 JS 理论上可以调用任何被 addJavascriptInterface 暴露的方法。暴露的接口必须只做"轻量、无副作用"的事。

→ 下一页:远程调试 WebView:chrome://inspect