Stuff & Nonsense

Self signed SSL certificates in phonegap (android)

So this week I ran into a wonderful problem while working on jNag, namely how to connect to servers over SSL using phonegap (which jNag relies heavily on).

Phonegap is a wrapper around Android’s native webview class so (I thought!) the answer lay in somehow getting the webview to accept a self signed certificate.

My first port of call was this blog post, which explains that while Webviews in Android 2.2 (and up) have a public method for dealing with SSL Errors (such as self signed certificates), previous versions don’t expose this functionality.  To make use of it you have to import some private APIs and so on..  which I did.

At this point I found out that while phonegap is in fact a wrapper around the native webview class, it doesn’t allow you to override methods of the webview.  So this approach wouldn’t work.  After some digging around I concluded there wasn’t an ‘easy’ way to do this, so I sat down and thought about it for a while.

I’d already had some experience with ‘native’ HTTP connections in android, that is getting HTTP data into a string within native code (the widget in the jNag paid app does this to check problems) and according to this discussion on stackoverflow it’s fairly easy to sidestep SSL errors using native code.  This got me thinking… I know how to call native code from javascript code in phonegap (I already do this in the android app) hmmm.

So, here’s my solution:

First we add a new class to our project called ‘webGetter’.  This class is going to do our actual grunt work of going getting the web data, and ignoring the HTTPS error (using the method described in the stackoverflow discussion). It includes a single method (in addition to the SSL stuff)

        public String get(String parameters){
		String returnedVal;
		//get url, username, password from a different jNag class, you'll need to change this to reuse it obviously
        sc = new settingsClass(context);
        String data_url = sc.getSetting("data_url");
        final String password = sc.getSetting("password");
        final String username = sc.getSetting("username");
        Authenticator.setDefault(new Authenticator(){
            protected PasswordAuthentication getPasswordAuthentication() {
                return new PasswordAuthentication(username,password.toCharArray());
            }});
        HttpURLConnection c;       
        try {
       	if (data_url.toLowerCase().contains("https")){
        		trustAllHosts();
        		c = (HttpsURLConnection) new URL(data_url + parameters).openConnection();
        		((HttpsURLConnection) c).setHostnameVerifier(DO_NOT_VERIFY); //this relies on the bypass ssl cert stuff
        	} else {
        		c = (HttpURLConnection) new URL(data_url + parameters).openConnection();
        	}
			InputStream in = new BufferedInputStream(c.getInputStream());		    
		    BufferedReader r = new BufferedReader(new InputStreamReader(in));
			StringBuilder total = new StringBuilder();
			String line;
			while ((line = r.readLine()) != null) {
			    total.append(line);
			}
			returnedVal = total.toString();
			c.disconnect();
		} catch (Exception e) {
			Log.d("jNag","connection error " + e.getLocalizedMessage() + "in webgetter");
			return "";
		}
		Log.d("jNag","webGetter returning: " + returnedVal);
		return returnedVal.replace("\", "").trim();
	}

So, basically we can call the method ‘get’ with some parameters (like ‘key=var&key=var’) and get a string back.

Now, we need a way to call this from the javascript side of our application.  Luckily Phonegap makes this incredibly easy, this snippet is out of the onCreate of my main app class:

        wg = new webGetter(this.getApplicationContext()); //my class uses a context, hence I need to pass in the application context
        appView.addJavascriptInterface(wg, "webGetter");

That declares a javascript object (window.webGetter) that we can access from our javascript code.  All we need to do now is call it:

        var somedata = window.webGetter('mykey=mydata');

And we’ve just got some data in native code and passed it into our javascript application. As a bonus, in my initial testing doing this seems to be quicker than doing it normally via ajax in the webview.

This approach definitely has some drawbacks. For a start it’s not asynchronous, so the javascript app pauses while the native code is off getting data… but I think I can work around that with a bit more effort.

 

2 thoughts on “Self signed SSL certificates in phonegap (android)

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.