I'm using a Webview that redirects to a Paypal transaction. The problem is that in Android devices before 4.4, the URL
https://www.sandbox.paypal.com/webscr?cmd=_express-checkout&token=sometokenprovided
gets me an ERROR_FAILED_SSL_HANDSHAKE error. I read some possible solutions, but none worked. Some say that this error only occours with the sandbox, not in production, but I want to be prepared if they change the production server too.
So I'm asking if there is a known working way to fix this issue.
Also, have in account I'm not getting this method called:
public void onReceivedSslError(WebView view, final SslErrorHandler handler, SslError error)
but instead this one is the one called:
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl)
Can someone help with this?
Thanks in advance,
João
You need to make sure your HTTP requests are happening over TLS 1.2 instead of SSLv3. It's a server software stack issue.
Related
I am updating my Android App to work with the latest version (it was developed with Lollipop). On inspecting the code I see several deprecated methods. Thanks to previous questions I have understood how to handle calls to depercated methods (check for targetSdkVersion > Build.VERSION_CODES.. etc)
However there are several overrodes to deprecated methods. How do I handle this?
for e.g. I use a WebViewClient() in which i override the onReceivedError(..) method
#Override
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
...
super.onReceivedError(view, errorCode, description, failingUrl);
}
The documentation says tis method was deprecated in API23, and I now need to use onReceivedError(WebView view, WebResourceRequest request, WebResourceError error)
My question is, how do I go about writing the check for the deprecated method?
Could I simply do:
#TargetApi(Build.VERSION_CODES.M)
#Override
onReceivedError(WebView view, WebResourceRequest request, WebResourceError error){...}
#SuppressWarnings("deprecation")
onReceivedError(WebView view, WebResourceRequest request, WebResourceError error){..}
Is there any additional check I need?
You can check it by similar statement as this:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
do some work for LOLLIPOP
} else {
do some work for older versions
}
My question is, how do I go about writing the check for the deprecated method?
For callbacks? You don't. If your minSdkVersion is high enough, just use the newer callback. Otherwise, just use the older callback. The exception would be if the documentation tells you to do otherwise, perhaps based on targetSdkVersion, though I cannot think of any scenarios where this happens.
For backwards compatibility, the old callbacks still work. On newer devices, they automatically "fall back" to using the old callbacks if the newer one is not implemented.
I have an android WebView set up with a WebViewClient as suggested by other threads to cover e.G. a 500 HTTP error from android 6 and above by using onHttpErrorReceived as follows:
webview.setWebViewClient(new WebViewClient() {
#Override
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
Log.d("FREEBROWSER", "----------------- ERROR deprecated ---------------");
}
#Override
#TargetApi(android.os.Build.VERSION_CODES.M)
public void onReceivedError(WebView view, WebResourceRequest req, WebResourceError rerr) {
Log.d("FREEBROWSER", "----------------- ERROR " + rerr.getDescription() + " ---------------");
// Redirect to deprecated method, so you can use it in all SDK versions
onReceivedError(view, rerr.getErrorCode(), rerr.getDescription().toString(), req.getUrl().toString());
}
#Override
#TargetApi(android.os.Build.VERSION_CODES.M)
public void onReceivedHttpError(WebView view, WebResourceRequest request, WebResourceResponse errorResponse) {
onReceivedError(view, errorResponse.getStatusCode(), errorResponse.getReasonPhrase(), request.getUrl().toString());
}
});
This works perfectly fine for devices running API level 23 and above (as it was also mentioned by the docs and other threads here, but this is of course unsatisfying if you want to catch a 500 error also for devices below API Level 23.
I get absolutely NO error callback with my android 4.4.2 device. Neither the version
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl)
nor the version
public void onReceivedError(WebView view, WebResourceRequest req, WebResourceError rerr)
is beeing called on a 500 error.
By looking at possible solutions for devices lower than API 23 I basically found 2 solutions in many variants (I don't want to explain them here again):
Catch "shouldOverrideUrlLoading" and/or other callbacks and perform a kind of "HEAD" request in advance to see if the webpage is reachable or not, then display custom error page.
Use JavaScript injection and ajax to determine reachability
Also as far as i could read there are no plans to release a supportlib version of this callback so that it could be used in older versions.
My question is: Are there other clean ways to support catching HTTP error status codes with devices running Android versions lower than API Level 23? Has anybody implemented a suitable solution for customers which at best exclude an additional request or JavaScript injection?
You can try to download HTML String and check the response header with this initial request. Use e.g. HttpURLConnection (or OkHttpClient) to do that. There you can check response with HttpURLConnection.getResponseCode(). If response code is good for you, load downloaded string with WebView.loadDataWithBaseURL(), see https://developer.android.com/reference/android/webkit/WebView.html#loadDataWithBaseURL
In the Android SDK 23 onReceivedError(WebView view, int errorCode, String description, String failingUrl) has been deprecated and replaced with onReceivedError(WebView view, WebResourceRequest request, WebResourceError error). However if I put my phone in Airplane mode and load an url on my WebView, only the deprecated version of the method is called.
onReceivedHttpError (WebView view, WebResourceRequest request, WebResourceResponse errorResponse) is also not useful, as it only detects errors higher than 500, and I am getting a 109 status code.
Is there a non-deprecated way of detecting that my WebView failed to load?
You could also do following:
#SuppressWarnings("deprecation")
#Override
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
// Handle the error
}
#TargetApi(android.os.Build.VERSION_CODES.M)
#Override
public void onReceivedError(WebView view, WebResourceRequest req, WebResourceError rerr) {
// Redirect to deprecated method, so you can use it in all SDK versions
onReceivedError(view, rerr.getErrorCode(), rerr.getDescription().toString(), req.getUrl().toString());
}
Make sure you import android.annotation.TargetApi
Please note that the mobile device where you are testing needs to actually run Android Marshmallow (API 23). Even if you develop your app on API 23 SDK, but then run the app on Android Lollipop, you will still be getting the "old" onReceivedError, because it's the feature of the OS, not of an SDK.
Also, the "error code 109" (I guess, this is net::ERR_ADDRESS_UNREACHABLE) is not an HTTP error code, it's Chrome's error code. onReceivedHttpError is only called for the errors received from the server via HTTP. When the device is in airplane mode, it can't possibly receive a reply from a server.
I have a webview in my Layout. By default, a search form is opened in it. On search, a listing section appears below the search form. If any link in the list is clicked, the details page opened. Now I want to controlled the back navigation for the webview. I placed this code in Activity.
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
Log.d("TYPE", TYPE);
WebView myWebView = null;
if (TYPE.equalsIgnoreCase("REPORT_ACTIVITY"))
myWebView = reportView;
if (TYPE.equalsIgnoreCase("FEEDBACK_ACTIVITY"))
myWebView = feedbackView;
if (myWebView != null)
// Check if the key event was the Back button and if there's history
if ((keyCode == KeyEvent.KEYCODE_BACK) && myWebView.canGoBack()) {
myWebView.goBack();
return true;
}
// If it wasn't the Back key or there's no web page history, bubble up
// to the default
// system behavior (probably exit the activity)
return super.onKeyDown(keyCode, event);
}
private WebViewClient webViewClient = new WebViewClient() {
public void onPageStarted(WebView view, String url, Bitmap favicon) {
Log.d("onPageStarted", "onPageStarted");
loadProgressBarBox.setVisibility(View.VISIBLE);
//view.setVisibility(View.GONE);
}
public void onPageFinished(WebView view, String url) {
Log.d("onPageFinished", "onPageFinished");
loadProgressBarBox.setVisibility(View.GONE);
}
public void onReceivedError(WebView view, int errorCode,
String description, String failingUrl) {
Log.d("Error", "Error code: " + errorCode + "/" + description);
}
}
I have also set a WebViewClient with the WebView. When I going back using back button it is working fine for any version 4.4. But when I am trying in Android 4.4, it is coming back fine from details page to listing page. But as soon as I am trying to go back again, its throwing error code -1 and ERR_CACHE_MISS in description. No page is displayed.
09-04 06:59:05.666: D/Error(1102): Error code: -1/net::ERR_CACHE_MISS
How to solve this problem in Android 4.4?
This error actually stems from outside of your application in most cases (occasionally it's just a missing INTERNET permission, but that doesn't sound like the case here).
I was typing out an explanation, but found a much more straightforward example that doubles as an explanation in this answer to another question. Here's the relevant bits, re-hashed a little:
Joe fills in an order form with his credit card information
The server processes that information and returns a confirmation/receipt page that's marked with no-cache in the header, meaning it will always be requested from the server.
Joe goes to another page.
Joe clicks back because he wants to double check something, taking him to the confirmation page.
The problem arises from that last step. The confirmation page was marked with no-cache, so it has to be requested from the server again. But to show the same page correctly, the same data that was passed the first time needs to get sent again.
This results in Joe getting billed twice, since a new request is being made with the same information as last time. Joe will not be a happy camper when he finds two charges on his account and an extra pair of tents on his doorstep.
It seems this situation was common enough that it is now a standard error across most browsers, and apparently, newer versions of Android. The error actually originates from Chromium, which is why you'll see the same error in Google Chrome, and why you only see it in 4.4 (which introduced a new version of the WebView based on Chromium).
In fact, you have actually probably seen it before, it's the message that shows up in most browsers warning you with something along the lines of "To refresh this page, the browser will have to resend data...yada yada yada".
This is Android 4.4's way warning you of what's going on. How to fix it really depends on what you're connecting to, but if you search for this situation, you'll find that it's fairly common, and has fixes. The exact trigger of the error is actually when the request can't be serviced from cache (in this case, no-cache is causing that).
Depending on the nature of the request, maybe no-cache isn't actually needed.
But from your application's perspective, the main problem is, onReceiveError is a sort of "last resort" for the WebView. Errors you get there have propagated from underlying system. And once you end up there, you can't continue the page load as it stands. So you don't have a chance to allow that resend, and you can't give the user that option, unlike, say Google Chrome does.
I ran into the same issue because in my manifest folder I had the Internet permission capitalized:
I had (error)
<uses-permission android:name="ANDROID.PERMISSION.INTERNET"/>
Should have (no error)
<uses-permission android:name="android.permission.INTERNET"/>
Use
if (Build.VERSION.SDK_INT >= 19) {
mWebView.getSettings().setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);
}
It will fix ERR_CACHE_MISS in the WebView.
Maybe you will need to change it to SDK_INT == 19 after some Lollipop WebView updates, but it works for now.
this permission in your andriodManifest.xml file
<uses-permission android:name="android.permission.INTERNET"/>
I have an application that mostly is a webview that will try to connect to my companies webpage. The page is an https and requires authentication. The current code that I'm using works when I'm running on a device or emulator which has ICS, but it does not work on 2.3.3. I've tried building it for 2.3.3, this version has been tested on both 2.3.3 and 4.x and only works on ICS. So it doesn't matter if I build it for ICS or Gingerbread.
I've tried different solutions to similar problems, but I'm not able to get it to work.
BrowserActivity:
public void onCreate(Bundle savedInstanceState) {
...
mWebView.setWebChromeClient(new WebChromeClient());
mWebView.setWebViewClient(new myWebClient());
mWebView.getSettings().setJavaScriptEnabled(true);
...
mWebView.loadUrl(urlString); //urlString is an https site
}
My webclient class:
public class myWebClient extends WebViewClient{
public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, String host, String realm){
handler.proceed(username, password);
}
public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error){
handler.proceed();
}
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl){
super.onReceivedError(view, errorCode, description, failingUrl);
}
}
This is the basic content of my application. I've tried logging in the different callbacks and I'm not getting any SSL error or an "regular" error. The only thing I see in my logcat is that when I'm running on Gingerbread the onReceivedHttpAuthRequest is called over and over again. I've checked to see that the credentials are correct and they are. I can also mention that I've got <uses-permission android:name="android.permission.INTERNET"></uses-permission> in my manifest.
I've checked with the IT department to see if the server is using SNI but they are telling me that it ain't using it.
Is there anyone that knows a reason to why this doesn't work? As mentioned earlier, it seems as the authentication doesn't work for some reason, as I see the onReceivedHttpAuthRequest being called over and over again in Gingerbread.
The problem is that the page doesn't load, the webview stays blank.