从技术深度 、安全意识 和 实战经验来介绍。以下是分层次的回答策略,从基础到高级逐步深入:
1. 基础实现
回答要点 :
"Android 和 JavaScript 的交互主要通过 WebView
的两种方式实现:
-
Android 调用 JS:
kotlin
webView.evaluateJavascript("javascript:showToast('Hello')") { result -> // 处理JS返回结果 }
需注意:
-
必须在主线程调用
-
确保 WebView 已加载完成(监听
onPageFinished
)
-
-
JS 调用 Android:
-
定义带
@JavascriptInterface
的类:kotlin
class JsBridge { @JavascriptInterface fun showToast(msg: String) { Toast.makeText(context, msg, Toast.LENGTH_SHORT).show() } }
-
绑定到 WebView:
kotlin
webView.addJavascriptInterface(JsBridge(), "AndroidBridge")
-
JS 端调用:
javascript
AndroidBridge.showToast("Hello from JS"); ```"
-
加分点:
- 提到
@JavascriptInterface
是 Android 4.2(API 17)后的强制要求,防止反射攻击。
2. 安全增强(进阶)
回答要点 :
"在实际项目中,必须考虑安全性:
-
限制 JS 接口暴露:
-
避免在接口中传递
Activity
或Context
,防止内存泄漏。 -
使用最小权限原则,仅暴露必要的功能。
-
-
协议校验 :
在
shouldOverrideUrlLoading
中拦截并校验自定义 Scheme(如jsbridge://action?params=xxx
),防止恶意 URL 跳转:kotlin
override fun shouldOverrideUrlLoading(view: WebView, url: String): Boolean { if (url.startsWith("jsbridge://")) { parseAndHandle(url) // 解析并执行原生逻辑 return true } return false }
-
禁用敏感功能:
kotlin
webView.settings.javaScriptEnabled = true // 按需开启 webView.settings.domStorageEnabled = false // 默认禁用 ```"
加分点:
- 提到 Android 8.0 后需额外处理
WebView
的静态注册安全问题。
3. 性能优化(高阶)
回答要点 :
"大规模交互时需优化性能:
-
双向通信优化:
-
使用
WebMessagePort
(API 23+)替代传统接口,减少全局对象污染:kotlin
val ports = webView.createWebMessageChannel() ports[0].setWebMessageCallback { message -> // 处理JS消息 } webView.postWebMessage(WebMessage("init", arrayOf(ports[1])), Uri.EMPTY)
-
-
避免频繁调用:
-
合并多次 JS 调用为单次(如通过 JSON 传递批量数据)。
-
使用
debounce
或throttle
控制高频事件(如滚动事件)。
-
-
内存管理:
-
在
onDestroy
中移除 JS 接口绑定:kotlin
webView.removeJavascriptInterface("AndroidBridge") ```"
-
加分点:
- 对比
evaluateJavascript
和loadUrl("javascript:...")
的性能差异(前者支持返回值,后者兼容旧版本)。
4. 复杂场景实战(项目经验)
回答示例 :
"在电商 App 中,我们通过 WebView 实现商品详情页的混合开发:
-
JS 调用原生相册:
-
JS 触发
AndroidBridge.openGallery()
,Android 端返回图片 Base64 给 JS。 -
处理大图时改用文件路径传递,避免内存溢出。
-
-
原生支付完成后回调 JS:
kotlin
webView.evaluateJavascript("javascript:onPaymentSuccess('$orderId')", null)
-
错误监控:
-
覆盖
WebViewClient.onReceivedError
统一处理 JS 加载失败。 -
通过
ConsoleMessage
捕获 JS 错误日志。"
-
加分点:
- 提到如何调试混合页面(Chrome DevTools 远程调试 WebView)。
5. 回答模板
1. **基础交互**:
- Android 调 JS:`evaluateJavascript`
- JS 调 Android:`@JavascriptInterface`
2. **安全措施**:
- 接口最小化、协议校验、禁用敏感设置
3. **性能优化**:
- WebMessagePort、调用合并、内存管理
4. **实战经验**:
- 举例说明项目中如何解决具体问题(如支付回调、图片上传)
5. **延伸思考**:
- 对比 Flutter/React Native 的 JS 交互方案
- 未来趋势(如 Google 的 WebView 沙盒化)
常见问题应对
Q: 为什么推荐 WebMessagePort
?
"A: 它通过 MessageChannel
实现双向通信,无需暴露全局对象,避免命名冲突和安全隐患,且性能更高。"
Q: 如何兼容低版本 Android?
"A: 降级方案:
-
使用
loadUrl("javascript:...")
-
通过
prompt()
拦截实现回调(需重写onJsPrompt
)"
Q: JS 接口如何调试?
"A: 三种方式:
-
Chrome DevTools 远程调试
-
在 JS 中捕获错误并通过接口通知 Android
-
日志拦截
ConsoleMessage
"