I've defined a private class that extends WebViewClient and set my WebView's client to an instance of that class (webView01.setWebViewClient(new Callback());).
The class definition is as follows:
private class Callback extends WebViewClient {
public void onLoadResource (WebView view, String url) {
}
public void onPageStarted (WebView view, String url, Bitmap favicon) {
}
public void onPageFinished (WebView view, String url) {
Animation anim = AnimationUtils.loadAnimation(MyNews.this, R.anim.webviewanim);
view.startAnimation(anim);
}
public void onReceivedError (WebView view, int errorCode, String description, String failingUrl) {
}
public boolean shouldOverrideUrlLoading (WebView view, String url) {
Log.e("loading url", url);
return false;
}
}
My problem is that onPageFinished is definitely getting called, but shouldOverrideUrlLoading is never being called.
What am I doing wrong here?
6/13/2010
A little more information.
I'm loading the initial page from a string ( webView01.loadDataWithBaseURL("fake://fake", myHTML, "text/html", "UTF-8", null);
).
The page loads (and there are several calls to onLoadResource) and onPageFinished is being called at page load completion.
When the user taps on an Anchor link in the page, instead of calling shouldOverrideUrlLoading, onLoadResource is called.
I need to invoke the full web browser when the user taps on the link, but I never get the chance to override url loading.
From what i have featured in webview till now, the shouldOverrideUrlLoading() doesn't get called when you call webview.load("website"), but if this website has redirection to another it works.
So the work around is to do what you want to be done when you call webview.load("website") (like calling a function that writes to the log Log.e("loading url", url)) since you already know the url and what needs to be done, shouldOverrideUrlLoading() only intercepts the requests sent from the webview it self.
Hope i was helpful.
Related
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.
Edit:
I found out that the web site is a single page website and that's probably the reason I didn't catch the change of the url so now my question is: Can I know the url changed on a single page website?
I have a webView which load a web site.
shouldOverrideUrlLoading called only once, on the first load of the page but not when it redirected inside the web.
This is the code of the webClient I use:
private class WebViewClientServiceGuide extends MyWebViewClient {
private WebView wv;
public WebViewClientServiceGuide(WebView _wv) {
wv = _wv;
Log.d(TAG, "WebViewClientServiceGuide.ctor");
}
public void onLoadResource(WebView view, String url) {
Log.d(TAG, "WebViewClientServiceGuide - onLoadResource: " + url);
super.onLoadResource(view, url);
}
#Override
public void onPageFinished(WebView view, String url) {
//Add history to history manager if needed
Log.d(TAG, "WebViewClientServiceGuide - onPageFinished");
super.onPageFinished(view,url);
}
#Override
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
Log.d(TAG, "WebViewClientServiceGuide - shouldOverrideUrlLoading(WebView view, WebResourceRequest request)");
return super.shouldOverrideUrlLoading(view, request);
}
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
Log.d(TAG, "WebViewClientServiceGuide - shouldOverrideUrlLoading");
return false;
}
}
Lets say I visited these pages: page1, page2, page3 but catches only page1 on shouldOverrideUrlLoading. But when I examined the history of the webView (copyBackForwardList) I saw all the list (page1, page2, page3).
Why does it happens? (I tried to use other website and catches there all the pages - I know the web site developer should fix it but I want to know why the history stack is different than the urls I catch on shouldOverrideUrlLoading )
Thank you
Found the solution:
I overrode a method of WebViewClient called doUpdateVisitedHistory which gets a url, even on single page website
Usually, when you click inside Android WebView page and transfer to another page, WebViewClient receives call to shouldOverrideUrlLoading method. But, this doesn't work with money.cnn.com. When I browse on money.cnn.com, I receive callbacks only into onPageStarted and into onPageFinished. Both only once. Browsing inside the site after doesn't give any callbacks to WebViewClient. If I browse only inside the money.cnn.com my log shows only these two lines. No more, no less.
> 10-14 14:10:25.581 28886-28886/com.myapp I/MyApp: onPageStarted
> 10-14 14:10:36.822 28886-28886/com.myapp I/MyApp: onPageFinished
My code is:
mWebView.setWebViewClient(mSWWebViewClient);
mWebView.getSettings().setJavaScriptEnabled(true);
mWebView.getSettings().setDomStorageEnabled(true);
mWebView.loadUrl(getUrl());
WebViewClient mSWWebViewClient = new WebViewClient() {
#Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
super.onPageStarted(view, url, favicon);
Log.d("MyApp", "onPageStarted ");
}
#Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
Log.d("MyApp", "onPageFinished ");
}
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
Log.d("MyApp", "shouldOverrideUrlLoading ");
}
};
My question is why shouldOverrideUrlLoading doesn't receive callback at all, and how can I detect a change of the content of this site while browsing through it?
Edition
Finally, I have finished with the solution https://stackoverflow.com/a/40551880/955321
In webview android I am trying to load a url and in order to check if the load of this url is done successfully (internet connection was available, the server was up etc) I was under the impression that webview.loadUrl would throw exceptions, but wrong! as it explicitly is stated in here "an exception will NOT be thrown".
So how can I check to see if webview.loadUrl did not fail ?
Unfortunately, currently there is no easy way in WebView to ensure that everything on the page has been loaded successfully. We are hoping for a better API to come up in future version. Let me explain what you can do now.
First of all, in order to detect any problems that prevent WebView from making a connection to the server for loading your main page (e.g. bad domain name, I/O error, etc.), you should use WebViewClient.onReceivedError callback as other people correctly suggest:
public class MyWebViewClient extends WebViewClient {
#Override
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
// Make a note about the failed load.
}
}
myWebView.setWebViewClient(new MyWebViewClient());
If the server connection was successful, and the main page was retrieved and parsed, you will receive WebView.onPageFinished callback, so you also need to have this in your WebViewClient subclass:
public class MyWebViewClient extends WebViewClient {
...
#Override
public void onPageFinished(WebView view, String url) {
// Make a note that the page has finished loading.
}
...
}
The caveat here is that if you have received an HTTP error from the server (e.g. a 404 or a 500 error), this callback will be called anyway, it's just the content that you will get in your WebView will be a server error page. People suggest different ways of how to deal with it, see the answers here: How can I check from Android WebView if a page is a "404 page not found"? Basically, it really depends on what you expect to be a "good" page and a "error" page. Unfortunately, there is currently no way for the app to get the HTTP response code from WebView.
The callbacks WebViewClient.onPageStarted and WebViewClient.onProgressChanged are only useful if you want to draw a progress bar as you are loading the page.
Also note that the way of overriding WebViewClient.shouldOverrideUrlLoading that people usually suggest is not correct:
public class MyWebViewClient extends WebViewClient {
...
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
// !!! DO NOT DO THIS UNCONDITIONALLY !!!
view.loadUrl(url);
return true;
}
...
}
What few developers realize is that the callback is also called for subframes with non-https schemes. If you'll encounter something like <iframe src='tel:1234'>, you will end up executing view.loadUrl('tel:1234') and your app will show an error page, since WebView doesn't know how to load a tel: URL.
It is recommended to simply return false from the method, if you want WebView to do the loading:
public class MyWebViewClient extends WebViewClient {
...
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
// Returning 'false' unconditionally is fine.
return false;
}
...
}
This doesn’t mean you should not call WebView.loadUrl from shouldOverrideUrlLoading at all. The specific pattern to avoid is doing so unconditionally for all URLs.
public class AppWebViewClient extends WebViewClient {
#Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
// TODO Auto-generated method stub
super.onPageStarted(view, url, favicon);
setProgressBar(true);
}
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return true;
}
#Override
public void onPageFinished(WebView view, String url) {
//Page load finished
super.onPageFinished(view, url);
setProgressBar(false);
}
}
and then you can do
webView.setWebViewClient(new AppWebViewClient());
For the error part you can override the onReceivedError method
#Override
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
// TODO Auto-generated method stub
super.onReceivedError(view, errorCode, description, failingUrl);
}
Here is what I came up with, it works like a charm.
Boolean failedLoading = false;
WebView webView = view.findViewById(R.id.webView);
webView.loadUrl("www.example.com");
webView.setWebViewClient(new WebViewClient() {
#Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
if (!failedLoading) {
webView.setVisibility(View.VISIBLE);
webView.setAlpha(0f);
ObjectAnimator anim = ObjectAnimator.ofFloat(webView, "alpha",1f);
anim.setDuration(500);
anim.start();
}
}
#Override
public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
super.onReceivedError(view, request, error);
failedLoading = true;
}
});
It will also work great if you add some kind of a refresh button and then you can call the code above inside a function to try again.
You can check if a URL is loaded successfully by using onProgressChanged()
mWebView.setWebChromeClient(new WebChromeClient() {
public void onProgressChanged(WebView view, int progress) {
progressBar.setProgress(progress);
if (progress == 100) {
//your url is loaded successfully
}
}
});
I have some logic I want my WebView to apply whenever I try to change its url. For links within loaded pages it's fine, I can just do it by using shouldOverrideUrlLoading method on my custom WebViewClient.
But when I explicitly call loadUrl on my WebView, shouldOverrideUrlLoading is not fired (obviously, or it would produce an endless loop when calling loadUrl from within this method).
Is there a way to "preload" a url manually so the shouldOverrideUrlLoading method is called?
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
if(url.startsWith("myapp://")
{
//Do something
}
else {
view.loadUrl(url);
}
return true;
}
This works fine when I click a link from within the rendered page. But if I call:
mWebView.loadUrl("myapp://whatever");
shouldOverrideUrlLoading() is not called. What I am asking is whether there's a way that I can pass a url to my webView so it gets passed through to shouldOVerrideUrlLoading() before actually loading it. (i.e. shouldOVerrideUrlLoading() is called whenever a new url is about to be loaded. That's the event I want to fire)
REF: Android's official WebView documentation
if your app version greater then 'N' you should use this function
shouldOverrideUrlLoading(WebView view, WebResourceRequest request)
check you function and version
If all you're trying to do is re-use your logic, just extract it into your WebViewClient and use that to load the url and then just delegate to this in shouldOverrideUrlLoading():
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
return loadUrl(view, url);
}
public boolean loadUrl(WebView view, String url) {
if(url.startsWith("myapp://")
{
//Do something
}
else {
view.loadUrl(url);
}
return true;
}
Then instead of
mWebView.loadUrl("myapp://whatever");
You do:
mWebViewClient.loadUrl(mWebView, "myapp://whatever");