Android WebView - Intercept URL loading - android

I'm trying to determine the successful payment event from the payment portal.
You might know this process: you send a 'callback URL' as one of other parameters to the payment website. When the payment is made the website re-directs the browser to your 'callback URL'.
Since this is Android application I specify a custom url with a custom scheme ('myapp://order/123') as a 'callback URL'
Then I use the following technique to intercept the re-direct to my 'callback URL' to do some custom action.
mWebView.setWebViewClient(new WebViewClient() {
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
LOG.info("Inside shouldOverrideUrlLoading(), url: {}", url);
if (url.startsWith("myapp://")) {
onPaymentPerformed();
return true;
} else {
return false;
}
}
}
It worked for many months but recently it started failing. I don't know why but probably due to device updates. This method has stopped being called for 'myapp://' url. I've checked the logs and found the following message
I/chromium: [INFO:CONSOLE(2174)] "Mixed Content: The page at 'https://www.liqpay.com/en/checkout/success/xxxx' was loaded over a secure connection, but contains a form which targets an insecure endpoint 'myapp://order/7'. This endpoint should be made available over a secure connection.", source: https://static.liqpay.com/checkout/160922113118/js/index.js (2174)
Then I tried to change 'myapp://order/123' to 'https://order/123' but the method shouldOverrideUrlLoading() is also not called for this url, instead I see a standard error message in the webview:
The webpage at https://order/123 could not be loaded because: net::ERR_NAME_NOT_RESOLVED
I found nothing similar to this on Internet, please help

You could subclass the WebClient and override the onReceiveSslError method.
private class SSLTolerentWebViewClient extends WebViewClient {
public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
handler.proceed(); // proceed ignoring ssl error.
}
}
See if that works.

Related

Webview onReceivedError called even if loading from cache

I've set my Webview to cache every page it visits (while online). I also need to display a custom view on top of the Webview in case the device goes offline and the users tries to load a webpage and it's not been cached.
It seems that the onReceivedError() method of the WebViewClient class is called even if the page has been loaded from cache, and it sets the same error code, i.e. -2 whick apparently means ERROR_HOST_LOOKUP
Is there a way to determine if the webpage failed and it was NOT loaded from cache, so I can then display a custom view to the user ? And no, I can't disable caching, I need to keep it.
I had to tackle this recently and hacked around it: I noticed that when loading cached content; the WebViewClient's onLoadResource() was called multiple times before onReceivedError(). When there was no cached content; onLoadResource() was only called once before onReceivedError().
I used this behaviour difference to set a flag which was used in onReceivedError() to determine if I should show my error view or not.
E.g:
public class CustomWebViewClient extends WebViewClient {
private int onLoadResourceCount = 0;
#Override
public void onLoadResource(WebView view, String url) {
super.onLoadResource(view, url);
onLoadResourceCount++;
}
#Override
public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
if (onLoadResourceCount <= 1) {
showErrorView();
}
}
}
EDIT: THIS IS A HACK AND IS BY NO MEANS A GOOD SUBSTITUTE FOR A WORKING API...but this is the best I could do lacking one.
This version is less hacky and still works. Use this to extend your WebViewClient():
override fun onReceivedError(view: WebView, request: WebResourceRequest, error: WebResourceError) {
if (request.url.toString() == view.url) {
// showInternetConnectionError()
webView.loadUrl("file:///android_asset/error_state.html")
}
super.onReceivedError(view, request, error)
}

logging HTTP request start and finish from embedded Android WebView

I'm looking for a way to log the requests and start/end times made by an embedded webview. I'm not able to find a way to do it so far other than rooting the phone and running tcpdump. That works for me, but I need to run this in the field, so that's not really viable. There are lots of ways to log the URL and start time, but I can't see the finish (or, bonus, the full response metadata).
shouldLoadResource could work if I could wrap the current request, but I'd have to fetch it myself with HTTP support in order to return it en masse, because there isn't enough API exposed to fully forward to the inner request. (I don't want to do that for a number of reasons, including that webview on devices doesn't use the same network stack as the HTTP classes, and because it will change the timing of subresources.)
I've been trying to find ways to turn on chromium_net debug flags to do this, but I can't figure out how do do that in the context of the WebView or system properties.
I would really rather not ship my own webcore to do this, but if needs must...
override method shouldInterceptRequest()
#Override
public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
Log.d(LOG_TAG, "shouldInterceptRequest: " + url);
return super.shouldInterceptRequest(view, url);
}
In that case, you could also add a WebViewClient (see http://developer.android.com/reference/android/webkit/WebViewClient.html). Which would look something like
WebView webView.setWebViewClient(new MyWebViewClient());
.
.
.
public class MyWebViewClient extends WebViewClient
{
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url)
{
// Note time
// Return false to say we want the WebView to handle the url.
return false;
}
#Override
public void onPageFinished (WebView view, String url)
{
super.onPageFinished(view, url);
// Note time
}
}
Note that both shouldOverrideUrlLoading and onPageFinished are only called only for the main frame - they will not be called for iframes or framesets. But this should give you what you need.

Android WebView Protocol Handler

I am trying to develop an Android browser application using WebView which enables users to access content from a custom protocol. The custom protocol could be foobar://
I want to intercept all requests to this custom protocol. This means:
GET requests
POST requests
and I need to be able to hand the results of these operations back to the WebView.
The GET requests can be handled using shouldInterceptRequest (available from API level 11).
Now my problem is: How can I incercept and handle POST requests?
Nearly the same question has been asked here and here, however no solutions for their problems have been found.
have you tried overriding for the post method doing something like:
private class ViewerWebViewClient extends WebViewClient {
#Override
public void onPageFinished( WebView view, String url ) {
}
#Override
public boolean shouldOverrideUrlLoading( WebView view, final String url ) {
if(!url.contains(MYKEYWORD))
{
Toast.makeText(getActivity(),POSTING, Toast.LENGTH_LONG).show();
return true;
}
return super.shouldOverrideUrlLoading(view, url);
}
}
its just an idea. that maybe could help you.

shouldOverrideUrlLoading in WebView for Android not running

-Edit: Solution Found-
Figured it out after some heavy searching - one person (I literally mean one) said they instead used onPageLoad(); which worked perfectly for my purposes. The difference is that onPageLoad() runs later than shouldOverrideUrlLoading, but It doesn't make a difference in my code.
I'm trying to set up Twitter authorization with OAuth for an Android app, and thus far I can successfully send the user to the authorization URL, however, what I am trying to do now is intercept the redirect to the callback (which would just lead to a 404 error, our callback URL isn't going to have an associated page on our servers). What I'm attempting to do is check if the URL is our callback, then extract the OAuth Verifier from the URL. I setup my WebView with this code:
view = (WebView)findViewById(R.id.twitterWbVw);
view.setWebViewClient(new WebViewClient(){
#Override
public boolean shouldOverrideUrlLoading(WebView wView, String url)
{
String urlHolder;
String[] verifExtrctr;
urlHolder = url.substring(0, url.indexOf('?'));
System.out.println("url");
if(urlHolder.equalsIgnoreCase(CALLBACK_URL))
{
verifExtrctr = urlHolder.split("?");
verifExtrctr = verifExtrctr[2].split("=");
if(verifExtrctr[0].equalsIgnoreCase("oauth_verifier"))
{
params[5] = verifExtrctr[1];
return true;
}
else
{
System.out.println("Inocorrect callback URL format.");
}
}
else
{
wView.loadUrl(url);
}
return true;
}
});
view.loadUrl(urlAuthorize.toExternalForm());
Thing is even System.out.println("url");(which I'm using to debug)doesn't run! So I'm pretty much dry on ideas, and can't find anyone with a similar problem. The authorization URL goes through fine, and I can successfully authorize the app, however the redirect to the callback URL for some reason never get's intercepted. Any help would be appreciated, this is in my onResume() if that matters.
After some research I conclude that despite what most of the tutorials out there say, shouldOverrideUrlLoading() does not get called when:
You load a URL like
loadUrl("http://www.google.com");
The browser redirects the user automatically via an HTTP Redirect. (See the comment from #hmac below regarding redirects)
It does however, get called when you you click on a link inside a webpage inside the webview. IIRC the twitter authorization uses an HTTP Redirect.. Bummer, this would be helpful if it worked how all the tutorials say it does. I think this is from a very old version the Android API...
You might want to consider overriding the onProgressChanged method of a WebChromeClient like here: How to listen for a WebView finishing loading a URL? or the onPageFinished() method of the WebViewClient.
I've found what I think is a reasonable way to do this thanks to the previous answer and comments pointing me in the right direction.
What I did is override onPageStarted and onPageFinished in a custom WebViewClient.
The code goes something like this...
#Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
if (pendingUrl == null) {
pendingUrl = url;
}
}
#Override
public void onPageFinished(WebView view, String url) {
if (!url.equals(pendingUrl)) {
Log.d(TAG, "Detected HTTP redirect " + pendingUrl + "->" + url);
pendingUrl = null;
}
}
And of course along with the Log.d you would put any specific code you want to run upon detecting the redirect.
For people stumbling across this, when the method shouldOverrideUrlLoading(WebView view, WebResourceRequest request) is not being called, look up your minSdkVersion. If you use below API 24 you should use shouldOverrideUrlLoading(WebView view, String url).

shouldOverrideUrlLoading(...) not executed if "window.location.href" modified in a timeout callback

I have a javascript function 'gotoMainPage()'
function gotoMainPage( ) {
window.location.href = "main/main.do";
}
Now, WebViewClient's shouldOverrideUrlLoading(..) gets called if gotoMainPage( ) is executed as a result of a 'direct user interaction', such as user clicking on this div:
<div.... onclick='gotoMainPage();'/>
However, if the execution is done via setTimeout( gotoMainPage, 100 ); or via an XMLHttpRequest callback, shouldOverrideUrlLoading(..) is never called but the requested page is loaded into the webview.
Am I missing an obvious explanation or is this a bug?
Anyone?
In my case, when using window.location = "http://xxx" in my webpage, the event shouldOverrideUrlLoading() is not triggered.
However, if I use a custom url scheme or protocol such as "androidurl://", shouldOverrideUrlLoading() is fired. My workaround would to be use a custom protocol and add the following code in the shouldOverrideUrlLoading() method:
if (url.startsWith("androidurl://")) {
url = url.replaceAll("androidurl://", "http://");
}
This will change the custom protocol back to the "http://" protocol and you can handle the correct url from there.
This works for me.
I've seen this come up myself as well, which imho, its clearly a bug.
Perhaps you can latch on to :
#Override
public void onLoadResource (WebView view, String url)
{
}
and/or
#Override
public void onPageFinished(WebView webView, String url)
{
}
I tried this myself, and found that onLoadResource would be triggered, even if shouldOverride wasnt.

Categories

Resources