我正在尝试基于
WebView
实现自定义浏览器。它在大多数网站上运行良好,但在 https://smittenkitchen.com/ 上我可能遗漏了一些关键的东西:
它可以很好地加载和显示主页,但是当输入搜索词(例如“carrot”)时,它首先登陆一个丑陋的“搜索表单”页面,然后显示一个空白覆盖! (在 Logcat 中没有覆盖显示/重定向的痕迹!)
在任何标准的网络浏览器上,它首先登陆那个丑陋的“搜索表单”页面,然后在 0.5-2 秒后显示一个覆盖层,搜索结果逐渐被填充。
我试图了解我在实施中遗漏了什么:
在 MyWebViewClient 中,我覆盖:
但是,前 3 种方法(
onPageStarted
、onPageFinished
、shouldOverrideUrlLoading
)仅在调用时记录 Logcat 消息,它们不会执行任何自定义操作。
做一些自定义的唯一重写方法 (
onPageCommitVisible
) 只调用 WebView 的loadUrl()
:
javascript:window.HTMLOUT.processHTML(document.getElementsByTagName('html')[0].innerHTML)
促成:
webView.addJavascriptInterface(new MyJavascriptInterface(this, webView), "HTMLOUT");
请注意,
shouldOverrideUrlLoading
永远不会被 Android WebView 框架调用,尽管有明显的重定向(可能是因为它是客户端重定向,而不是更改 URL?)
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
Log.d("", "url: " + url + ", view: " + view.getUrl());
}
@Override
public void onPageFinished(WebView view, String url) {
Log.d("", "url: " + url + ", view: " + view.getUrl());
}
@Override
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest webResourceRequest) {
Log.d("", "webResourceRequest: " + webResourceRequest.getUrl() + ", view: " + view.getUrl());
return false;
}
@Override
public void onPageCommitVisible(WebView view, String url) {
super.onPageCommitVisible(view, url);
view.loadUrl("javascript:window.HTMLOUT.processHTML(document.getElementsByTagName('html')[0].innerHTML)"); // convert all javascript to HTML
Log.v("", "url (passed): " + url + " < view.getUrl(): " + view.getUrl());
}
Javascript当然是启用的:
webSettings.setJavaScriptEnabled(true);
webSettings.setSupportZoom(false);
webSettings.setBlockNetworkLoads(false);
webSettings.setDomStorageEnabled(true);
webSettings.setLoadWithOverviewMode(true);
webSettings.setUseWideViewPort(false);
webSettings.setBuiltInZoomControls(true);
webSettings.setDisplayZoomControls(false);
webSettings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
webSettings.setCacheMode(WebSettings.LOAD_DEFAULT);
相关的Logcat代码片段如下:
11:12:03.716 D url: https://smittenkitchen.com/, view: https://smittenkitchen.com/ (called from: MyWebViewClient.onPageFinished)
11:12:03.988 D url: https://smittenkitchen.com/, view: https://smittenkitchen.com/ (called from: MyWebViewClient.onPageStarted)
11:12:05.646 E net::ERR_CONNECTION_REFUSED(-6) on request: https://ssc.33across.com/api/v1/hb?guid=cYCh20L9Or64olaKj0P0Le, https://smittenkitchen.com/ (called from: MyWebViewClient.onReceivedError)
11:12:05.787 MyWebView V javascript:window.HTMLOUT.processHTML(document.getElementsByTagName('html')[0].innerHTML); (called from: MyWebView.loadUrl < MyWebViewClient.onPageCommitVisible)
11:12:05.790 MyWebViewClient V url (passed): https://smittenkitchen.com/ < view.getUrl(): https://smittenkitchen.com/ (called from: MyWebViewClient.onPageCommitVisible)
11:12:08.097 D url: https://smittenkitchen.com/, view: https://smittenkitchen.com/ (called from: MyWebViewClient.onPageFinished)
11:12:23.824 D url: https://smittenkitchen.com/?s=carrot, view: https://smittenkitchen.com/?s=carrot (called from: MyWebViewClient.onPageStarted)
11:12:24.083 MyWebView V javascript:window.HTMLOUT.processHTML(document.getElementsByTagName('html')[0].innerHTML); (called from: MyWebView.loadUrl < MyWebViewClient.onPageCommitVisible)
11:12:24.085 MyWebViewClient V url (passed): https://smittenkitchen.com/?s=carrot < view.getUrl(): https://smittenkitchen.com/?s=carrot (called from: MyWebViewClient.onPageCommitVisible)
11:12:25.176 E net::ERR_CONNECTION_REFUSED(-6) on request: https://ssc.33across.com/api/v1/hb?guid=cYCh20L9Or64olaKj0P0Le, https://smittenkitchen.com/?s=carrot (called from: MyWebViewClient.onReceivedError)
11:12:26.583 D url: https://smittenkitchen.com/?s=carrot, view: https://smittenkitchen.com/?s=carrot (called from: MyWebViewClient.onPageFinished)
知道我在实现中可能会遗漏什么,以便我的基于 WebView 的浏览器像 Chrome 一样显示覆盖吗?
我认为这个问题可能与页面加载时间和 JavaScript 执行有关。
在您的
MyWebViewClient
实施中,您仅捕获初始页面加载,而不捕获搜索结果的后续动态加载。要正确捕获此类动态负载,您可以选择在您的 shouldInterceptRequest
中实施 WebViewClient
方法。
这样你就可以拦截 WebView 发出的请求并在加载之前修改它们。
还有
onPageCommitVisible
方法被用来执行JavaScript代码,但它可能在页面完全加载之前被调用。这可能会导致 JavaScript 代码在不完整或不正确的页面状态下执行,从而导致意外行为。
为确保您的代码仅在页面完全加载时执行,您可以将 JavaScript 执行移至
onPageFinished
方法。页面加载完成后将调用该方法。
这是包含新修改的
MyWebViewClient
类的示例:
public class MyWebViewClient extends WebViewClient {
private Context context;
private WebView webView;
public MyWebViewClient(Context context, WebView webView) {
this.context = context;
this.webView = webView;
}
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
Log.d("", "url: " + url + ", view: " + view.getUrl());
}
@Override
public void onPageFinished(WebView view, String url) {
Log.d("", "url: " + url + ", view: " + view.getUrl());
view.loadUrl("javascript:window.HTMLOUT.processHTML(document.getElementsByTagName('html')[0].innerHTML)");
}
@Override
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest webResourceRequest) {
Log.d("", "webResourceRequest: " + webResourceRequest.getUrl() + ", view: " + view.getUrl());
return false;
}
@Override
public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
super.onReceivedError(view, request, error);
Log.e("", error.toString() + " on request: " + request.getUrl() + ", " + view.getUrl());
}
}
请注意,
onReceivedError
方法也已更新为包括 super
调用,这是正确处理错误所必需的。
试试这个更新后的实现,看看它是否解决了叠加层未正确显示的问题。