Android WebView实现JS Bridge时如何用Kotlin/Java判断网页JS函数是否存在
Android WebView 原生侧检测指定JS函数存在性的实现方案
原生运行时和JS执行上下文是完全隔离的,无法直接在Kotlin/Java代码中跨域访问JS环境的变量定义,必须通过WebView提供的JS执行通道,将判断逻辑注入JS运行环境执行,再将检测结果回传给原生,完成后续兜底逻辑。
核心实现前提
- 检测逻辑必须在页面完全加载完成后触发:所有JS函数的定义都依赖页面脚本的解析执行流程,需将检测动作绑定到WebViewClient的
onPageFinished回调中,禁止在onPageStarted阶段执行,否则会出现100%的误判。 - 检测逻辑需要保证无副作用:判断函数存在性时只做读取操作,不要修改页面全局变量、触发额外的页面逻辑。
可落地的实现方案
方案1:全版本兼容的JS接口回传模式
该方案适配所有Android版本的WebView,稳定性最高,不需要依赖高版本WebView的API特性。
- 第一步:初始化WebView时注册专用的JS桥接接口,用于接收JS侧返回的检测结果:
webView.addJavascriptInterface(object { @JavascriptInterface fun onFuncCheckResult(funcExist: Boolean, targetFunc: String) { // JS接口回调默认在子线程,涉及UI操作需切回主线程 mainHandler.post { if (!funcExist) { // 执行原生兜底逻辑 runNativeFallback(targetFunc) } } } }, "NativeFuncCheckHelper")
- 第二步:在
onPageFinished回调中注入检测JS片段:
override fun onPageFinished(view: WebView?, url: String?) { super.onPageFinished(view, url) // 替换为实际需要检测的目标JS函数名 val checkTargetFunc = "jsBridgeEntry" val checkScript = """ (function() { // 严格判断函数类型,避免未声明变量抛出ReferenceError val funcExist = typeof window.$checkTargetFunc === 'function'; // 将结果回传给原生桥接对象 window.NativeFuncCheckHelper.onFuncCheckResult(funcExist, "$checkTargetFunc"); })(); """.trimIndent() // 高版本WebView用evaluateJavascript执行 view?.evaluateJavascript(checkScript, null) // 兼容API 19以下低版本WebView,用loadUrl方式执行JS // view?.loadUrl("javascript:$checkScript") }
方案2:API 19+ 简化版结果回调模式
从Android 4.4(API 19)开始,WebView的evaluateJavascript接口可以直接拿到JS执行的返回值,不需要额外注册JS桥接对象,代码逻辑更简洁。
override fun onPageFinished(view: WebView?, url: String?) { super.onPageFinished(view, url) val checkTargetFunc = "jsBridgeEntry" val checkScript = """ (function() { return typeof window.$checkTargetFunc === 'function'; })(); """.trimIndent() view?.evaluateJavascript(checkScript) { checkResult -> // 回调默认在主线程,可直接处理业务逻辑 val funcExist = checkResult.toBoolean() if (!funcExist) { runNativeFallback(checkTargetFunc) } } }
常见踩坑规避
- 严格使用
typeof做类型判断:如果直接访问未声明的全局变量,JS会直接抛出ReferenceError导致执行中断,typeof操作符对未声明变量的判断会安全返回"undefined",不会触发报错。 - 跨域iframe场景适配:如果需要检测的JS函数定义在子iframe的全局作用域,需要将检测脚本注入到对应iframe的执行上下文,仅在顶层window检测会出现漏判。
- 避免污染全局作用域:检测JS片段需要用立即执行函数包裹,不要在全局作用域声明临时变量,避免和页面原有脚本产生变量冲突。
内容的提问来源于stack exchange,提问作者Gabyola Lim
相关产品推荐
相关产品推荐

