
本文档旨在解决 Android WebView 中 `onCreateWindow` 方法无法直接获取 `window.open()` 打开的新窗口 URL 的问题。通过重写 `WebViewClient` 的 `shouldOverrideUrlLoading` 方法,并结合 `WebChromeClient` 的 `onCreateWindow` 方法,提供了一种可靠的方案来捕获和处理新窗口的 URL,并提供了示例代码和配置说明。
在 Android WebView 开发中,WebChromeClient 的 onCreateWindow 方法用于处理 JavaScript 的 window.open() 调用,创建新的 WebView 窗口。然而,onCreateWindow 方法本身并不直接暴露新窗口的 URL。本文将介绍如何通过结合 WebChromeClient 和 WebViewClient 来获取并处理新窗口的 URL。
解决方案:利用 shouldOverrideUrlLoading 拦截 URL
核心思路是利用 WebViewClient 的 shouldOverrideUrlLoading 方法拦截新窗口的 URL 请求。当 window.open() 被调用时,新的 WebView 会尝试加载 URL,此时 shouldOverrideUrlLoading 方法会被触发,从而可以获取到 URL。
以下是具体的实现步骤:
- 配置 WebView 设置:
首先,确保 WebView 启用了 JavaScript,并允许 JavaScript 打开新窗口,同时支持多窗口。
webView.apply {
settings.javaScriptEnabled = true
settings.javaScriptCanOpenWindowsAutomatically = true
settings.setSupportMultipleWindows(true)
}- 实现 WebChromeClient 的 onCreateWindow 方法:
在 onCreateWindow 方法中,创建一个新的 WebView,并设置自定义的 WebViewClient。
webChromeClient = object : WebChromeClient() {
override fun onCloseWindow(window: WebView?) {
super.onCloseWindow(window)
}
override fun onCreateWindow(
view: WebView?,
isDialog: Boolean,
isUserGesture: Boolean,
resultMsg: Message?
): Boolean {
if (view?.context == null) {
return false
}
if (resultMsg == null) {
return false
}
// Use CustomTabs to open the link when the hitTestResult is not null
if (view.hitTestResult.extra != null) {
val colorParam = CustomTabColorSchemeParams.Builder().setToolbarColor(getColor(context, R.color.blue)).build()
val intent = CustomTabsIntent.Builder()
.setDefaultColorSchemeParams(colorParam)
.setShowTitle(true)
.build()
intent.launchUrl(view.context, Uri.parse(view.hitTestResult.extra))
return false
}
// Use a new webViewClient to handle window.open() case
val newWebView = WebView(view.context)
newWebView.webViewClient = object : WebViewClient() {
override fun shouldOverrideUrlLoading(
view: WebView?,
request: WebResourceRequest?
): Boolean {
if (request?.url == null) {
return true
}
val url = request.url.toString()
if (url.contains("example.com")) {
// Here you can handle “example.com” and do whatever you want
return true
}
return true
}
}
val transport = resultMsg.obj as WebView.WebViewTransport
transport.webView = newWebView
resultMsg.sendToTarget()
return true
}
}- 实现 WebViewClient 的 shouldOverrideUrlLoading 方法:
在自定义的 WebViewClient 中,重写 shouldOverrideUrlLoading 方法。在该方法中,可以获取到新窗口的 URL,并进行相应的处理。
newWebView.webViewClient = object : WebViewClient() {
override fun shouldOverrideUrlLoading(
view: WebView?,
request: WebResourceRequest?
): Boolean {
if (request?.url == null) {
return true
}
val url = request.url.toString()
if (url.contains("example.com")) {
// 在这里处理包含 "example.com" 的 URL
// 例如,打开一个新的 Activity 显示该 URL
return true
}
return true
}
}代码解释
- settings.javaScriptEnabled = true: 启用 JavaScript。
- settings.javaScriptCanOpenWindowsAutomatically = true: 允许 JavaScript 自动打开窗口。
- settings.setSupportMultipleWindows(true): 支持多窗口。
- onCreateWindow: 创建新窗口的回调,在这里创建新的 WebView 并设置 WebViewClient。
- shouldOverrideUrlLoading: 拦截 URL 加载请求,在这里获取 URL 并进行处理。
注意事项
- 安全问题: 启用 JavaScript 可能会引入安全风险,需要谨慎处理用户输入和加载的 URL。
- 性能问题: 创建过多的 WebView 可能会影响性能,需要合理管理 WebView 的生命周期。
- URL 处理: 在 shouldOverrideUrlLoading 方法中,需要根据实际需求处理 URL。可以打开新的 Activity 显示 URL,或者执行其他操作。
- Context 兼容性: 确保在创建 WebView 时使用正确的 Context,避免内存泄漏。
- CustomTabs 的使用: 代码中使用了 CustomTabs 来打开链接,需要引入相应的依赖,并处理好兼容性问题。如果 view.hitTestResult.extra 不为空,表示用户点击了链接,此时使用 CustomTabs 打开链接可以提供更好的用户体验。
总结
通过结合 WebChromeClient 的 onCreateWindow 方法和 WebViewClient 的 shouldOverrideUrlLoading 方法,可以有效地获取并处理 Android WebView 中 window.open() 打开的新窗口 URL。这种方法简单易用,可以满足大多数场景的需求。在实际应用中,需要根据具体情况进行调整和优化,以确保安全性和性能。










