Saturday 28 September 2013

Android WebView with https loadUrl shows blank/empty page

I recently encountered this problem while trying to develop a WebView that is supported on Doughnut (1.6) and above. When presented with a https url the WebView just renders a blank page.
It seems that until Froyo, Android didn’t provide a public API to let you manually decide if you wanted to proceed to an untrusted web site via a WebView.
Note that in this case it is not even that the web site was untrusted (in the conventional sense) – it is because Thawte is not in the default list of trusted certificate authorities on Android. If you use the standard web browser on Android, the browser presents a typical warning dialog (as presented below) that enables you to accept the certificate and carry on.

If you are using Froyo as the target SDK then you can use:
mWebView = (WebView) findViewById(R.id.my_webview);
mWebView.setWebViewClient(new WebViewClient() {
 public void onReceivedSslError (WebView view, SslErrorHandler handler, SslError error) {
 handler.proceed() ;
 }
}
However, if you are not using Froyo then it seems you are out of luck. After some research, I concluded that I had the following options:

a) intercept all page requests and forward to external web browser if url begins with https (not a clean or nice user experience and totally unnecessary for Froyo and above)

b) add certificate of website to local keystore (in this case I am serving multiple web pages and the origin of many of these is not known until runtime)

c) make Froyo the minSDK and discard previous versions of Android (not a suitable option)

d) hack and use some private apis (the option described below)

To solve this problem we have to use a private interface (not published on SDK but present in real SDK runtime). As you can see in the Android src tree, the onReceivedSslError is indeed present (and used – it simply cancels the request) in Doughnut. However, this method is not presented to us in the SDK  - it is hidden because it contains a parameter type SslError which is located in a hidden package.  Therefore, we need to copy these src files into our project so that we can access them:

1) Copy WebViewClient.java into the package “android.webkit” within your src folder.

2) Copy SslError.java into the package “android.net.http” within your src folder.



3) Since we replicated the paths to the src files in the SDK, our code to override onSslError above now works on Android 1.6.



Caution: bear in mind that we are using a private API and Google reserve the right to change private APIs at any time – though in this case it is unlikely since they’ve now made this available in Froyo.

1 comment: