It is possible to measure the load time of all the resources of a webview?
For example for loading the complete web, I use:
public void onPageStarted(WebView view, String url, Bitmap favicon) {
startingTime = System.currentTimeMillis();
super.onPageStarted(view, url, favicon);
}
public void onPageFinished(WebView view, String url) {
timeElapsed = System.currentTimeMillis() - startingTime;
super.onPageFinished(view, url);
}
but to measure the load of CSS, images, etc. I use
public HashMap<String, Long> resources = new HashMap<String, Long>();
public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request){
resources.put(request.getUrl().toString(), System.currentTimeMillis());
WebResourceResponse response = super.shouldInterceptRequest(view, request);
return response;
}
public void onLoadResource(WebView view, String url) {
if(resources.containsKey(url)){
Long timeStartResource = resources.get(url);
Long timeElapseResource = System.currentTimeMillis() - timeStartResource;
}
super.onLoadResource(view, url);
}
I thought the onLoadResource method is executed when the resource was loaded but according to documentation
public void onLoadResource (WebView view, String url).
Notify the host application that the WebView will load the resource specified by the given url.
And
public WebResourceResponse shouldInterceptRequest (WebView view, WebResourceRequest request)
Notify the host application of a resource request and allow the application to return the data. If the return value is null, the WebView will continue to load the resource as usual. Otherwise, the return response and data will be used.
Both they run before loading the resource. Is there any way to measure these times?
There is a great HTML5 API for that accessible to your page. See http://www.sitepoint.com/introduction-resource-timing-api/
Starting from KitKat, WebView is based on Chromium, which supports this API. To check that, open remote web debugging for your app (assuming that you have enabled JavaScript for your WebView), and try evaluating in console:
window.performance.getEntriesByType('resource')
You will get an array of PerformanceResourceTiming objects for each resource your page has loaded.
In order to transport your information to Java side, you can use an injected Java object.
That you can done using onPageFinished() and answer of this question is already given description here.
Related
I usualy use shouldOverrideUrlLoading to block ads in webview, but this time, the ads links in a new website doesn't captured in
public boolean shouldOverrideUrlLoading(WebView view, String url)
and
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request)
but it captured in
public WebResourceResponse shouldInterceptRequest(final WebView view, String url)
so, i used this method
#RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
#Override
public WebResourceResponse shouldInterceptRequest(final WebView view, String url) {
Log.d("soidfzs", url);
WebResourceResponse webResourceResponse = null;
if (url.contains("https://googleads") || url.contains("doubleclick") || url.contains("google-analytics.com") || url.contains("adservice") || url.contains("securepubads")) {
Log.d("soidfzs", "here");
return webResourceResponse;
} else {
return super.shouldInterceptRequest(view, url);
}
}
but, links still loading and ads showing
So, what should i return ?
You are returning webResourceResponse which you set to null prior to your if statement where you check whether the request might be for an ad.
The documentation for shouldInterceptRequest however states:
* #return A {#link android.webkit.WebResourceResponse} containing the
* response information or {#code null} if the WebView should load the
* resource itself.
So in returning null, you are telling the WebViewClient to load the resource itself, i.e., fulfil the ad request and load the ad.
In order to let the request slide and return your own value, you have to return your own WebResourceResponse instance which must not be null for this to work.
return new WebResourceResponse(
"text/html",
"UTF-8",
null
);
Here, I set the mimeType (first argument) to "text/html", although it could probably also be something else, like "text/plain".
I set the second argument—encoding—to "UTF-8"(same as before: could probably be something else).
And now for the most important part: I set data, the third argument, to null.
This results in the WebView getting a valid WebResourceResponse instance which is not null but has no data which in turn results in nothing loading.
Be aware that this will trigger WebViewClient#onReceivedError as the WebView client essentially couldn’t load anything. This is not a problem per se, but something to look out for in case you override onReceivedError.
I am trying to parse every click event, intercept the http url that attempts to load into the webview, and decide if it should be shown depending on a set of logic as per how the url parses. I have followed the advice on these 3 StackOverflow links:
1) Intercept and override HTTP requests from WebView
2) Android Web-View shouldOverrideUrlLoading() Deprecated.(Alternative)
3) https://stackoverflow.com/a/32711309/2480714
without it fixing my issue. The main issue is that a user clicks on the webview to load a hyperlink and it is seems like the shouldOverrideUrlLoading method is not being called or is not intercepting the url properly every time.
I created my Custom WebViewClient and overrode it first with the intent of stopping all loads without my approval, but I have run into a snag; some urls are loading and bypassing my override methods and some are not. I have no clue why this is happening.
Here is my WebviewClient class:
public class CustomWebViewClient2 extends WebViewClient {
public CustomWebViewClient2(){
}
#Override
public void onPageFinished(WebView view, String url) {
Log.d("log", "(CustomWebViewClient) onPageFinished, URL == " + url);
}
#SuppressLint("NewApi")
#Nullable
#Override
public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
Log.d("log", "shouldInterceptRequest hit");
return null;
}
#Nullable
#Override
public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
Log.d("log", "shouldInterceptRequest hit");
return null;
}
#Override
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
Log.d("log", "(CustomWebViewClient) shouldOverrideUrlLoading");
return true;
}
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
Log.d("log", "(CustomWebViewClient) shouldOverrideUrlLoading");
return true;
}
#Override
public void onLoadResource(WebView view, String url) {
Log.d("log", "intercepting onLoadResource, url == " + url);
}
#Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
Log.d("log", "onPageStarted url == " + url);
}
}
As you can see, it is overriding the correct methods and should (in theory) never load a URL unless I pass it to the webview to load, but unfortunately some websites are loading, and others are not.
I also tried disabling the cache as per this comment in one of the answers:
"A word of CAUTION! If you intercept an attempt by the browser to
retrieve an image (or probably any resource) and then return null
(meaning let the WebView continue retrieving the image), any future
requests to this resource might just go to the cache and will NOT
trigger shouldInterceptRequest(). If you want to intercept EVERY image
request, you need to disable the cache or (what I did) call
WebView.clearCache(true)"
but to no avail. Why are some URLs loading in and bypassing the override, but others are not?
Update 1: Here is a sample URL https://cookpad.com/us that mirrors the issue I am referring to. It seems to be related to Turbolinks being implemented on the server-side.
In my android app I am connecting to a secure site where my login credentials are contained in custom headers. I am able to log in successfully because the custom headers are sent with the new page request.
Based on my custom header information there is specific page functionality which is enabled for my device. The problem is that when I load resources from the home page after login the custom headers that I specify in the webview.LoadUrl(); are not sent. So the end result is that I can log in but do not receive the special functionality that is associated with my device.
I have tried both of these overrides. shouldOverrideUrlLoading seems to work when changing URL's but shouldInterceptRequest does not seem to get called on resource requests? If it is my implementation does not work?
#Override
public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
request.getRequestHeaders().putAll(getExtraHeaders());
return super.shouldInterceptRequest(view, request);
}
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url, getExtraHeaders());
return false;
}
See if this works a little better for you:
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.post(new Runnable() {
#Override
public void run() {
view.loadUrl(url, getExtraHeaders());
}
});
// true means: yes, we are overriding the loading of this url
return true;
}
This additional code is just a suggestion/outline and should not be taken as cut/paste ready code
#Override
public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
String mimetype;
String encoding;
Map<String, String> headers = new HashMap<>();
headers.putAll(request.getRequestHeaders());
headers.putAll(getExtraHeaders());
URL url = request.getUrl().toString();
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
for (String key : headers.keySet()) {
conn.setRequestProperty(k, headers.get(k));
// TODO look for the mimetype and encoding header information and set mimetype and encoding
}
return new WebResourceResponse(mimetype, encoding, conn.getInputStream());
// return null here if you decide to let the webview load the resource
}
Maybe try a different approach, store whatever your need in a cookie for your host using WebKit's CookieManager and use the request's cookie header instead of your custom headers
I load HTML to my WebView with
this.webViewer.loadDataWithBaseURL(BASE_URL, completeNewsTemplate,
"text/html", "UTF-8", null);
Where BASE_URL = "http://www.example.ru" i use it for WebView loading images with relative images src's
if in HTML soruce i got href link like
Example
Then it's just reload current webview, and target attribute does make anything for open new window.
How make webview open link in new window?
Here is solution.
If your link equals base url WebView think that you want work with current page only.
You can try catch it like
webViewer.setWebViewClient(new WebViewClient() {
#Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
System.out
.println("DetailViewActivity.onCreate(...).new WebViewClient() {...}.onPageStarted()");
super.onPageStarted(view, url, favicon);
}
#Override
public void onPageFinished(WebView view, String url) {
System.out
.println("DetailViewActivity.onCreate(...).new WebViewClient() {...}.onPageFinished()");
super.onPageFinished(view, url);
}
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
System.out
.println("DetailViewActivity.onCreate(...).new WebViewClient() {...}.shouldOverrideUrlLoading()");
return false;
}
});
But then you click to your link in webView you never get fired shouldOverrideUrlLoading or onPageStarted only onPageFinished with your base_url.
So my solition is use for base url another domain without www prefix.
Here example if you domain www.example.com use base url example.com
webview in android loads more than once while loading the url.
Below is the code.
public boolean shouldOverrideUrlLoading(WebView view, String url)
{
if (url.contains(".pdf")) {
String[] spliturl = url.split("http://someurl/");
String googleurl = "http://docs.google.com/viewer?embedded=true&url=";
System.out.println("Google Url"+googleurl);
System.out.println("spliturl"+spliturl[1]);
view.loadUrl(googleurl+spliturl[1]);
}
else
view.loadUrl(url);
return true;
}
});
I am splitting the url as it contains more than one url to be passed on google document viewer for rendering the pdf document.
First time the url is correctly split and the url is concatenated to open in google docs but the webview executes again there by giving an ArrayIndexOutOfBoundsException at spliturl[1].
Could anybody let me know why is this executing again.
thanks.
I don't know why it gets called multiple times, but the solution is to handle it in onPageStarted rather than in shouldOverrideUrlLoading
boolean calledOnce=false;
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return true;
}
public void onPageStarted(WebView view, String url, Bitmap favicon) {
if (url.contains(".pdf") && !calledOnce) {
String[] spliturl = url.split("http://someurl/");
String googleurl = "http://docs.google.com/viewer?embedded=true&url=";
System.out.println("Google Url"+googleurl);
System.out.println("spliturl"+spliturl[1]);
url = googleurl+spliturl[1];
calledOnce = true;
}
super.onPageStarted(view, url, favicon);
}
You should always check if an array has a size more than the index requested:
if (url.contains(".pdf") && url.split("http://someurl/").size()>2){
// your code
}
Don't know why it gets called though - probably multiple redirections.