Android 与 H5 交互的几种方式全解析:addJavascriptInterface、shouldOverrideUrlLoading、evaluate

87 阅读3分钟

在现代 App 中,混合开发(Hybrid) 已成为常见架构:前端用 Web 技术(H5/JS),后端或容器层使用原生 Android。
要让两端能「互相调用」,就需要桥梁 —— Android 与 H5 的交互机制

本文将全面讲解常见的三种交互方式:

  1. addJavascriptInterface —— 双向通信桥
  2. 🌐 shouldOverrideUrlLoading —— 拦截 URL 方式
  3. evaluateJavascript —— 原生主动调用 JS

并配合优缺点分析和实用示例,让你彻底掌握 Hybrid 通信!

🧭 一、Android 与 H5 交互的常见方式

交互方向实现方式说明
Android → H5webView.loadUrl("javascript:...") / evaluateJavascript()调用 JS 方法
H5 → AndroidaddJavascriptInterface() / shouldOverrideUrlLoading()JS 调用原生方法

🧩 二、方式一:addJavascriptInterface()(推荐)

✅ 原理

通过注入一个带有 @JavascriptInterface 注解的对象,让 H5 页面可以直接调用原生方法。
属于 JS 调用 Android 原生代码 的官方方式。

📘 使用示例

1️⃣ 注入接口对象

class JsBridge(private val context: Context) {

    @JavascriptInterface
    fun showToast(msg: String) {
        Toast.makeText(context, msg, Toast.LENGTH_SHORT).show()
    }

    @JavascriptInterface
    fun getAppVersion(): String {
        return "1.0.0"
    }
}

2️⃣ WebView 中注入

val webView = findViewById<WebView>(R.id.webView)
webView.settings.javaScriptEnabled = true
webView.addJavascriptInterface(JsBridge(this), "AndroidBridge")

3️⃣ H5 调用方式(JS 中)

// 调用 Android 方法
AndroidBridge.showToast("你好,来自H5!");

// 获取返回值(可配合回调)
var version = AndroidBridge.getAppVersion();
console.log("App Version:", version);


⚙️ 优点

✅ 方式正规,支持直接调用原生方法(包括参数传递)。
✅ 返回值可直接同步获取(String、Int等)。
✅ 不依赖 URL Scheme,代码清晰。
✅ Android 4.2+ 提供 @JavascriptInterface 安全控制。

⚠️ 缺点

❌ Android < 4.2 存在安全漏洞(任意代码执行风险)。
❌ 数据传输性能不高(JS 与 Java 层通过反射通信)。
❌ 不能在 WebView 进程之外调用(仅限主线程)。

🔒 安全建议

  • 仅对受信任的页面使用(不要对外部网页暴露)。
  • Android 4.2+ 必须使用 @JavascriptInterface 注解。

🧩 三、方式二:shouldOverrideUrlLoading()(常用于拦截 URL)

✅ 原理

H5 页面通过 改变 URL(Scheme) 传递参数,Android 在 WebViewClient 中拦截 URL,解析指令执行原生逻辑。
属于 URL Scheme 通信机制

📘 使用示例

1️⃣ H5 调用方式(JS)

// 通过改变URL触发原生拦截
window.location.href = "jsbridge://showToast?msg=来自H5的问候";

2️⃣ Android 拦截解析

webView.webViewClient = object : WebViewClient() {
    override fun shouldOverrideUrlLoading(view: WebView?, url: String?): Boolean {
        if (url != null && url.startsWith("jsbridge://")) {
            val uri = Uri.parse(url)
            val action = uri.host
            val msg = uri.getQueryParameter("msg")

            when (action) {
                "showToast" -> Toast.makeText(view?.context, msg ?: "", Toast.LENGTH_SHORT).show()
                "openPage" -> { /* 打开原生页面逻辑 */ }
            }
            return true // 拦截,不让WebView继续加载
        }
        return super.shouldOverrideUrlLoading(view, url)
    }
}


⚙️ 优点

✅ 简单直观,适配所有 Android 版本。
✅ 易于调试(直接通过 URL 查看指令)。
✅ 不存在 @JavascriptInterface 的安全隐患。

⚠️ 缺点

❌ 无法直接返回结果(单向通信)。
❌ 参数传递复杂(需手动 URL 编解码)。
❌ 大量通信时性能较差(频繁 loadUrl)。
❌ H5 改变 location.href 会导致页面跳转或刷新。


🧩 四、方式三:evaluateJavascript()(Android → H5,异步调用)

✅ 原理

Android 通过执行 JS 代码的方式调用 H5 方法,并可接收返回值(Android 4.4+ 支持)。

📘 示例

webView.evaluateJavascript("javascript:showMessage('Hello from Android')") { result ->
    Log.d("JS_CALLBACK", "H5 返回: $result")
}

H5 端 JS:

function showMessage(msg) {
  alert("JS 收到:" + msg);
  return "OK";
}


⚙️ 优点

✅ 异步执行,不会阻塞 UI 线程。
✅ 可获取 JS 执行结果。
✅ 安全性高,无需注入对象。

⚠️ 缺点

❌ 仅 Android 4.4+ 支持。
❌ 调用 JS 代码需拼接字符串,易出错。
❌ 调试稍不便。


🧩 五、三种方式对比总表

类型调用方向实现方式优点缺点适用场景
addJavascriptInterfaceH5 → AndroidJS 调原生对象方法正规、高兼容、支持返回值旧版有安全风险双向通信、需要数据交互
shouldOverrideUrlLoadingH5 → Android拦截 URL Scheme兼容性高、安全、易调试无返回值、参数需解析简单事件调用,如跳转、Toast
evaluateJavascriptAndroid → H5执行 JS 代码异步安全、支持回调仅 4.4+ 支持原生调用 JS、获取返回值

🧰 六、实战建议(最佳实践)

场景推荐方案说明
简单调用(H5 调原生功能)shouldOverrideUrlLoading用 URL Scheme 定义协议,简单直观
双向交互(需传参或回调)addJavascriptInterface + evaluateJavascript 组合官方推荐写法,数据安全
H5 调原生高频事件(如扫码、登录)addJavascriptInterface性能更优,返回值支持
兼容旧 WebViewshouldOverrideUrlLoading不依赖 JS 注入机制

💡 七、综合总结

特性addJavascriptInterfaceshouldOverrideUrlLoadingevaluateJavascript
调用方向JS → AndroidJS → AndroidAndroid → JS
返回值支持✅ 支持❌ 不支持✅ 支持
安全性⚠️ Android <4.2 不安全✅ 安全✅ 安全
兼容性Android 4.2+所有版本Android 4.4+
性能中等慢(需跳转)快(异步)
使用难度简单简单
典型场景支付、扫码、数据交互点击跳转、Toast 提示原生调用 JS 方法

🧩 八、综合使用建议

🧠 实际应用建议

场景推荐方式
简单通知类交互(如关闭页面、提示)shouldOverrideUrlLoading
复杂业务调用(如支付、分享、登录)addJavascriptInterface
原生主动触发 JS(如刷新页面数据)evaluateJavascript
高安全需求的混合页面自定义协议 + 加密通信 + 校验签名

🔐 安全第一,通信第二。
在真实项目中,建议配合统一的 JSBridge 框架(如 WebViewJavascriptBridge)进行封装,统一协议、加密通信,提升可维护性与安全性。

✅ 推荐组合方案:

  • JS 调用原生 → addJavascriptInterface
  • 原生回调 JS → evaluateJavascript
  • 简单点击或跳转 → shouldOverrideUrlLoading

🔧 实战总结代码结构

class WebViewBridge(context: Context, private val webView: WebView) {

    @JavascriptInterface
    fun showToast(msg: String) {
        Toast.makeText(context, msg, Toast.LENGTH_SHORT).show()
    }

    @JavascriptInterface
    fun getUserInfo(): String {
        return "{"name":"Jeled","id":123}"
    }

    // 原生回调 JS 方法
    fun notifyJs(message: String) {
        webView.evaluateJavascript("javascript:onNativeMessage('$message')", null)
    }
}

webView.settings.javaScriptEnabled = true
webView.addJavascriptInterface(WebViewBridge(this, webView), "AndroidBridge")

// H5 调用原生
AndroidBridge.showToast("来自H5的问候");
// 原生回调H5
function onNativeMessage(msg) {
    console.log("收到原生消息:" + msg);
}


总结:

类型特点
addJavascriptInterface功能最强,但要防漏洞
shouldOverrideUrlLoading简单安全,推荐入门使用
evaluateJavascript现代 API,适合原生调用 JS

addJavascriptInterface —— 官方正统,功能强大。

shouldOverrideUrlLoading —— 简单安全,适合轻交互。

evaluateJavascript —— 原生主动调用 H5 的利器。