17

I would like to create an Android Webview that connects to a website via a secured HTTPS connection with the use of credentials.

First difficulty was to accept the certificate (private), it was solved with this very useful post.

Second difficulty is to use credentials, I found this post.

(first answer from dparnas) which seems to deal pretty well with it, but it talks about HTTP connection and not HTTPS. I ve tried it, but it doesnt work, I just reach the sign-in form page without any error message, just the normal blank form.

Here is my code:

import android.app.Activity;
import android.net.http.SslError;
import android.os.Bundle;
import android.webkit.HttpAuthHandler;
import android.webkit.SslErrorHandler;
import android.webkit.WebView;
import android.webkit.WebViewClient;

public class ConnectorWebView extends Activity {
  WebView mWebView;
  String mUsrName;
  String mPassC;

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.connwebview);

    // Getting info from Intent extras
    // Get it if it s different from null
    Bundle extras = getIntent().getExtras();            
    mUsrName = extras != null ? extras.getString("username") : null;
    mPassC = extras != null ? extras.getString("passcode") : null;

    mWebView = (WebView) findViewById(R.id.webview);
    mWebView.getSettings().setJavaScriptEnabled(true);
    mWebView.setHttpAuthUsernamePassword("myhost.com", "myrealm", mUsrName, mPassC);

    mWebView.setWebViewClient(new WebViewClient() {
        @Override 
        public void onReceivedHttpAuthRequest  (WebView view, HttpAuthHandler handler, String host, String realm){ 
          handler.proceed(mUsrName, mPassC);
        } 

        public void onReceivedSslError (WebView view, SslErrorHandler handler, SslError error) {
          handler.proceed() ;
        }
      });

    mWebView.loadUrl("https://myhost.com/secured_area");
  }
}
Community
  • 1
  • 1
Mbolland
  • 285
  • 1
  • 3
  • 4

3 Answers3

15

As it seems that WebView cannot natively handle Basic authentication when using HTTPS, I started toying with the idea of setting the Authorization header (containing the encoded username/password) manually.

Here's how I think this can be done:

import org.apache.commons.codec.binary.Base64;

// ...

@Override
public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.connwebview);

  // Getting info from Intent extras
  // Get it if it s different from null
  Bundle extras = getIntent().getExtras();            
  mUsrName = extras != null ? extras.getString("username") : null;
  mPassC = extras != null ? extras.getString("passcode") : null;

  mWebView = (WebView) findViewById(R.id.webview);
  mWebView.getSettings().setJavaScriptEnabled(true);
  // mWebView.setHttpAuthUsernamePassword("myhost.com",
  //                                   "myrealm",
  //                                   mUsrName,
  //                                   mPassC);

  mWebView.setWebViewClient(new WebViewClient() {
      @Override 
      public void onReceivedHttpAuthRequest(WebView view,
                                            HttpAuthHandler handler,
                                            String host,
                                            String realm){ 
        handler.proceed(mUsrName, mPassC);
      } 

      public void onReceivedSslError(WebView view,
                                     SslErrorHandler handler,
                                     SslError error) {
        handler.proceed() ;
      }
    });

  String up = mUserName +":" +mPassC;
  String authEncoded = new String(Base64.encodeBase64(up.getBytes()));
  String authHeader = "Basic " +authEncoded;
  Map<String, String> headers = new HashMap<String, String>();
  headers.put("Authorization", authHeader);
  mWebView.loadUrl("https://myhost.com/secured_area", headers);
}

This takes advantage of the WebView.loadUrl (String url, Map<String, String> additionalHttpHeaders) method and for this example I'm using the Base64Encoder from Apache Commons. The Base64Encoder part is quite trivial and if you didn't want to include external libraries in your application (for whatever reason), you could always write your own (reference).

Also note that the aforementioned WebView.loadUrl (String url, Map<String, String> additionalHttpHeaders) method is only available in API 8+. For reference, see also the Wikipedia article on Basic Authentication (which discusses the headers, etc).

Marvin Pinto
  • 30,138
  • 7
  • 37
  • 54
  • Great solution! In my case, I have implemented on server auto login form, when user is not recognized, so the solution with webviewclient was not working, but headers map is working well! Thanks! – Krystian Dec 29 '16 at 14:02
4

The WebView class doesn't provide as much flexibility in its connectivity as using the low level classes (such as HttpPost or the like) directly.

If you need to fully control the connection to the server -- or deal with complicated authorization scenarios such as this one -- use the low level classes, retrieve the data, then use WebView.loadData() to load and show the HTML.

Here is a good example of loading content using SSL and a BasicCredentialProvider. The result of this could be loaded into the WebView as described above.

Community
  • 1
  • 1
elijah
  • 2,904
  • 1
  • 17
  • 21
  • It doesn't look like there are going to be any more answers so I'm going to award the bounty to you. No point in losing it :) – Marvin Pinto Jan 10 '12 at 14:33
  • "complicated authorization scenarios" hahahahhah, this is completely standard RFC from years ago, webview should handle this... – Nappy Feb 13 '12 at 11:28
  • while I agree it "should" -- and I wish it would! - webview only exposes a certain subset of the behavior that the full HTTP library supports... – elijah Feb 13 '12 at 19:45
0

Alternative Scenario:

If willing to write roundabout 10 lines of javascript using jQuery, this scenario is rather simple.

Inject your javascript code into the webview or in case you're controlling the html page you are displaying, include it there.

If you need to interface back from javascript, you can do that. For heavier command exchange, use the CordovaWebView-Interface which has a lower delay depending on api level.

Community
  • 1
  • 1
Philzen
  • 3,945
  • 30
  • 46