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
Related
In My Android mobile app, I have webview and I have loaded some third party URL. The problem is that web-page have login page when press login with details entered it returns the same login page again . Is anyone, can help me how to solve this problem? or why its redirected again to same login page? or how to find the url loding in same page of webview or different page of webview?
Add WebViewClient to your webview it will override public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) in which you get every loaded url by webResourceRequest object which have getUrl(), getMethod() and other methods. getUrl()
mWebView.setWebViewClient(new WebViewClient() {
#Override
public boolean shouldOverrideUrlLoading(
WebView view, WebResourceRequest webResourceRequest) {
webResourceRequest.getUrl()
// Here you will get every url which is loaded
webView.loadUrl(request.getUrl().toString());
return true;
}
#Override
public void onPageStarted(
WebView view, String url, Bitmap favicon) {
super.onPageStarted(view, url, favicon);
//SHOW LOADING IF IT ISNT ALREADY VISIBLE
}
#Override
public void onPageFinished(WebView view, String url) {
}
});
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.
First i surfed the web but no answer was found matching my case.
I want to grab a specific redirect url from a webview and then keep the webview from opening it. The case is an Instagram redirect url after the user authorized my app. How to do it? Here is my code:
webView = (WebView) findViewById(R.id.webView1);
webView.getSettings().setJavaScriptEnabled(true);
webView.getSettings().setLoadWithOverviewMode(true);
webView.getSettings().setUseWideViewPort(true);
webView.getSettings().setBuiltInZoomControls(true);
webView.setWebViewClient(new WebViewClient());
webView.loadUrl("https://api.instagram.com/oauth/authorize/?client_id=my_client_id&redirect_uri=my_redirect_uri&response_type=code");
You will have to set your custom WebviewClient overriding shouldOverrideUrlLoading method for your webview before loading the url.
mWebView.setWebViewClient(new WebViewClient()
{
#SuppressWarnings("deprecation")
#Override
public boolean shouldOverrideUrlLoading(WebView webView, String url)
{
return shouldOverrideUrlLoading(url);
}
#TargetApi(Build.VERSION_CODES.N)
#Override
public boolean shouldOverrideUrlLoading(WebView webView, WebResourceRequest request)
{
Uri uri = request.getUrl();
return shouldOverrideUrlLoading(uri.toString());
}
private boolean shouldOverrideUrlLoading(final String url)
{
Log.i(TAG, "shouldOverrideUrlLoading() URL : " + url);
// Here put your code
return true; // Returning True means that application wants to leave the current WebView and handle the url itself, otherwise return false.
}
});
mWebView.loadUrl("Your URL");
Checkout the example code for handling redirect urls and open PDF without download, in webview.
https://gist.github.com/ashishdas09/014a408f9f37504eb2608d98abf49500
You should override shouldOverrideUrlLoading:
webView.setWebViewClient(new WebViewClient() {
#Override
public boolean shouldOverrideUrlLoading(WebView wView, String url) {
if (url.indexOf('api.instagram.com') > -1) //check if that's a url you want to load internally
{
webView.loadUrl(url);
return true;
}
else
{
return false; //Let the system handle it
}
}
});
Finally thanks to the answer given to my question by Udi I, with a little change, i managed to find a solution to the problem. Here is the code which worked for me:
webView.setWebViewClient(new WebViewClient(){
#Override
public boolean shouldOverrideUrlLoading(WebView wView, String url) {
return (url.indexOf("some part of my redirect uri") > -1);
}
});
webView.loadUrl(myUrl); //myUrl is the initial url.
Using the above code, if there will be any url containing redirect uri, webView won't load it. Else, webView will load it. Also thanks to Kamil Kaminski.
Simply set WebViewClient for your WebView, and override shouldOverrideUrlLoading in WebViewClient. In that method you can grab your url, and decide whether or not your WebView should follow redirection url. Here's example:
webView.setWebViewClient(new WebViewClient() {
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
// here you can assign parameter "url" to some field in class
// return true if you want to block redirection, false otherwise
return true;
}
});
You can compare URL strings / particular word, and take actions accordingly -
public boolean shouldOverrideUrlLoading(WebView view, String url) {
super.shouldOverrideUrlLoading(view, url);
if (url.contains(".pdf")
openPDF(url); // handle pdf opening
if(url.startsWith("tel:")
callNumber(url); // handle call processing
...
}
Just to add more, you can prevent webview from showing traditional error message screens, or bypass known errors -
#Override
public void onReceivedError(WebView view, int errorCode,
String description, String failingUrl) {
if (errorCode == -10) {
System.out.println("Error occured: Error code: "
+ errorCode + "..Ignoring this error");
return;
}
else
{
// Show your custom screen to notify error has occured
}
...
}
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'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.