Uw betrouwbare partner voor (mobiele) web applicaties
TwitterEmailRSS

PhoneGap ActionSheet plugin

Cordova PhoneGap ActionSheet plugin for iOS and Android

Recently I was wondering how hard it could be to add a Cordova plugin for showing a native ActionSheet like Twitter on iOS does:

Twitter ActionSheet iOS

.. so I gave it a try

The idea is to show the user a list of options and have the plugin return the selected index back to the JavaScript callback.

iOS implementation

The iOS implementation is based on UIActionSheet. It’s the exact same thing Twitter uses (and loads of other app by Apple and third parties). It supports these things, all of the labels can be passed in by the plugins JavaScript API:

– A title, on top of the dialog.

– Multiple options, shown in blue.

– A ‘desctructive option’, shown in red. This does the same as the other buttons, but can be used to indicate to the user this action can not be undone.

– A cancel button.

actionsheet-plugin-ios

Android implementation

Before I could ever get around to implementing an Android version,  Brill Pappin stepped up and created a great implementation of an ActionSheet for Android. It’s based on the AlertDialog.

There are two differences to keep in mind when using this plugin on Android:

– The cancel button is hidden by default, even when a label for the cancel button was passed in. This is common Android behavior as all devices have a dedicated backbutton which can be used to close the popup as well. If you want a cancel button (like the screenshots), there is an option in the API to tell the plugin to do so.

– The ‘destructive option’ (the red ones in the iOS screenshots) don’t have  a different color.

actionsheet-plugin-android

Cool, gimme!

Head over to the GitHub repo, star it, and follow the instructions to install it.

What about PhoneGap Build?

Check out the plugin page and search for the ActionSheet plugin (I would have provided a deeplink, but the URL changes with every update of the plugin). Android support was added in version 1.0.0 which has not yet been approved at the time of writing.

PhoneGap Toast plugin

PhoneGap Toast plugin for iOS, Android and WP8

It’s always a good idea to show your mobile app user feedback about his actions. I have used the alert function of the Notification plugin a lot, but never really liked its blocking in-your-face behavior. You even force the user to click a button to continue using your app 🙁

Native Android apps have  a lovely little gem called a Toast and that’s exactly what this plugin tries to bring to PhoneGap apps. Now I can finally show feedback like ‘Logout succeeded’ or ‘Account created’ without annoying the user with a blocking popup, or showing an HTML message which may or may not be inside the viewport (don’t you hate it when your error message is rendered offscreen?). If you want feedback messages like this, use the PhoneGap Toast plugin:

PhoneGap Toast plugin on iOS

PhoneGap Toast plugin in action on iOS

PhoneGap Toast plugin on Android

PhoneGap Toast plugin in action on Android

Display text inside a native popup

Showing a Toast using some sensible default values would have been sufficient for most users, but I wanted to make it a bit more flexible than simply passing a message.. so let’s see what else we need.

Positioning the Toast

On Android, Toasts are often shown at the bottom of the app, but this may not satisfy all usecases. If you have a menubar at the bottom, it could block those buttons for a few seconds. Or what if the message is very important? Then you’d want to show it in the center of the screen. So I need the plugin to have a ‘position’ parameter.

Showing the Toast a bit longer

When you want to display more than a few words, you’ll want to show the Toast a bit longer. So I also need a ‘duration’ parameter. Since Android only supports ‘short’ (2 seconds) and ‘long’ (5 seconds), we have to settle with that. Note that you can use an arbitrary length on iOS, but I like uniform API’s.

Putting it all together: the Toast Javascript API

Now that the requirements are clear, it’s time to show the final API:

toast.show('Hello!', 'long', 'center')

Since there are only six options, I’ve added a few convenience methods:

toast.showShortBottom('I hit rock bottom..')
toast.showLongTop('I'm at the top of the app!')

What about PhoneGap Build?

Check out the plugin page and search for the Toast plugin (I would have provided a deeplink, but the URL changes with every update of the plugin).

PhoneGap share plugin for Facebook, Twitter and other social media

PhoneGap share plugin

Adding social media to your PhoneGap app is always a good idea – you can draw attention to your app by letting your users do the promotional work for you. All you need to do is adding share buttons for Twitter, Facebook and other social media to your app. BUT how does this work on PhoneGap.. and what about PhoneGap Build? Use this PhoneGap share plugin and you get stuff like this:

PhoneGap share plugin in action on iOS7

SocialSharing plugin in action on iOS 7

PhoneGap share plugin in action on Android

SocialSharing plugin in action on Android 4.4 (Kitkat)

Share text using the native sharing widget

Using this plugin, you can have your iOS or Android device open the native share widget, so the user can choose where to share the content to. For example, sharing a message ‘My message’ can be started by clicking a button:

<button onclick="window.plugins.socialsharing.share('My message')">share!</button>

Sharing a link

Sharing text is nice, but why not spice it up a little? Let’s add a link:

  share('My message',
        null,
        null,
        'http://www.x-services.nl')

Sharing an image

What about sharing an image? That’s possible as well. You can share links from the internet and from the local device. You can even share base64 encoded image which you just grabbed from the Camera!

  share('My message',
        'PhoneGap share plugin',
        'https://www.google.nl/images/srpr/logo4w.png', // check the repo for other usages
        'http://www.x-services.nl')

Sharing text, a subject, a link and an image together

Let’s combine all options and share like a boss! A subject can be used for the email client, but other apps may use it as well, but that’s up to the receiving app:

  share('My message',
        'PhoneGap share plugin',
        'https://www.google.nl/images/srpr/logo4w.png',
        'http://www.x-services.nl')

Skipping the share dialogue

If you don’t want your user to choose where to share to, you can skip the share widget and directly share to Twitter, Facebook, or other apps:

  shareViaTwitter('My message');

  shareViaFacebook('Message via Facebook',
                   null,
                   null,
                   console.log('share ok'), // success callback
                   function(errormsg){alert(errormsg)}) // error callback

  shareVia('com.apple.social.sinaweibo' // for options, see the repo
           'Message via Weibo on iOS',
           null,
           null,
           console.log('share ok'), // success callback
           function(errormsg){alert(errormsg)}) // error callback

What about PhoneGap Build?

Check out the plugin page and search for the SocialSharing plugin (it’s one of the most used plugin thanks to you all!).

Certificate Pinning Plugin for PhoneGap to prevent Man in the Middle Attacks

A while ago my colleagues and I were working on a PhoneGap app which required a high level of security. Among other measures, we implemented certificate pinning to prevent Man in the Middle attacks. In this blog I’ll tell you what we’ve done and give you a link to a certificate pinning PhoneGap plugin I recently wrote.

Man in the Middle attackman-in-the-middle-attack

Ofcourse you have secured communication with an SSL certificate on the server. With a desktop browser, you will normally see the green certificate bar next to the URL. In a mobile app however, there is no such bar, so you won’t notice when it suddenly turns red because an attacker is impersonating the server with a self signed certificate. This may happen when f.i. you use the app via a compromised public WiFi hotspot. The attacker intercepts all traffic without the user noticing it.

Certificate pinning

A good way to make sure your app connects directly to your server, is by checking the fingerprint of the SSL certificate. In our app we implemented this purely in native code for iOS and Android and it works great; intercepting traffic via a proxy is no longer possible. (Note that we also encrypt the data itself, just in case this solution gets compromised.)

Native iOS and Android implementation

So what the code needs to do is fetch the certificate from the endpoint the app connects to and compare its fingerprint to a list of fingerprints your app allows to connect to. In Java, it looks a bit like this (simplified):

boolean isConnectionSecure(url, expectedFingerprint) {
  return expectedFingerprint.equals(getFingerprint(url));
}

String getFingerprint(String httpsURL) {
  HttpsURLConnection cnx = (HttpsURLConnection) new URL(httpsURL).openConnection();
  Certificate cert = cnx.getServerCertificate();
  MessageDigest md = MessageDigest.getInstance("SHA1");
  md.update(cert.getEncoded());
  return getHex(md.digest());
}

PhoneGap plugin

I’ve wanted to enable fellow PhoneGap developers to use this feature via a plugin and finally took the time to create the plugin. With the plugin, developers can create a Javascript call like this one to verify the connection with the server:

var server = "https://build.phonegap.com";
var fingerprint = "8F A5 FC 33 20 2D 45 B4 EC 95 87 F0 50 F0 18 14 DF 98 50 64"; // valid until sep 2014

window.plugins.sslCertificateChecker.check(
          successCallback,
          errorCallback,
          server,
          fingerprint);

Once the successCallback is invoked, you can be pretty sure there is no Man in the Middle attack going on.

The SSLCertificateChecker plugin can be found here, on Github.

What about PhoneGap Build?

PhoneGap Build is fully supported by the plugin.

Oh, and if you are using PhoneGap Build, I highly recommend our Buildmeister app, which will make your development cycle a bit shorter:

Android app on Google Play

Buildmeister - X-Services

Phonegap Android splash screen: using 9patch images

When working on your new killer app, most of the time you are focussing on its functionality. Making wireframes and implementing that cool feature that makes the app different from all other apps. And eventually, when the implementation is almost finished you start working on the other stuff that is needed for your app, like the App store images and texts and the splash screens. At least, that is what it comes down too for us most of the times 🙂

However, configuring and implementing some nice splash screens for your Phonegap app appeared to be quite a challenge. Especially the Phonegap Android splash screen configuration is not that easy. How did we manage to get the Android splash screens in our app without being stretched? Turned out we had to use 9patch images. This blog describes how to create and configure 9patch splash screens for your Phonegap application.

Creating your 9patch image

The Android SDK comes with a tool called draw9patch, which is located in the tools directory of the Android SDK. This tool can be used to create your 9patch image. Follow the steps below to create your 9patch splash screen image.

  1. Open the draw9patch tool
  2. Open the PNG file you want to use as source for your splash screen
  3. Add the black dots on the outer side of the image for the part of the image you want to be stretched (see the example below). It is important that the right and bottom side of the image are completely filled with black (otherwise some strange stretched results might be visible).
  4. Verify the results in the preview pane of the tool (on the right side of your screen).

Phonegap Android splash screen

Configure Phonegap Android splash screen

What configuration do you need to add to your Phonegap app to use the 9patch splash screen you just created?

  1. Create splash.xml
  2. Configure the splash screen in your DroidGap activity
  3. Copy the splash screens in your drawable directories

splash.xml

A file named splash.xml should be created in your res/drawable folder. An example is listed below. You need to refer to the 9patch splash screen you’ve made earlier (use the filename without the extension).

<nine-patch 
xmlns:android="http://schemas.android.com/apk/res/android"
android:scr="@drawable/<splash_screen_name_without_extension>"
android:dither="false"/>

Configure the splash screen in your DroidGap extension

Next, you need to refer to the splash screen in your App’s Main Activity, which extends the Phonegap DroidGap class. Note that R.drawable.splash refers to splash.xml. Renaming splash.xml means changing this lines accordingly.

super.setIntegerPoperty("splashscreen", R.drawable.splash);

Copy the splash screens  in your drawable directory

Since we have created only one 9patch splash screen, first I though it was enough to simply put in the res/drawable folder of your app. However, it appeared that Android takes this to be a mdpi splash screen and it will still rescale and resize it to ie. hdpi density before the 9patch streching becomes active. To prevent this, copy the 9patch splash screen to all density subfolders in your res folder (drawable-mpdi, drawable-hpdi, etc.). Of course, it possible to create a different 9patch per density too, since you have more space available for higher densities.

And what about Phonegap Build?

The instructions above describe how to create and configure your Phonegap Android splash screen using a 9patch image. Can we use 9patch splash screens when using Phonegap Build?
Nope, you can’t 🙁 But there is hope… They have an open issue on their issue list so 9patch support will probably be added in the future.

Phonegap camera implementation

We are currently working on the implementation of a new App for a customer using the Phonegap framework to simplify development for multiple platforms. One of the requirements the customer came up with is the possiblity for a user of the App to upload photo’s that he made with the camera of his mobile device. Is this possible using the Phonegap framework? Of course it is, and this blog will show you how.

Photo upload using the Phonegap camera object

Several steps are needed to implement the photo upload functionality:

  1. Make sure your App has access to the mobile device’s camera functionality.
  2. Get you App to open the device’s native camera dialog.
  3. Get the photo from the native camera dialog.
  4. Upload the photo to your server.

1. Access to the device’s camera functionality

It is necessary to configure in your Apps’s Phonegap configuration that you’ll be using the Phonegap camera plugin.We are using Phonegap Build, which means that a single configuration file (config.xml) can be used for both Android and iOS.

The following lines have to be added to the config.xml:

<feature name="http://api.phonegap.com/1.0/camera"/>
<feature name="http://api.phonegap.com/1.0/file"/>

Note that the second line is needed because on Android you need to configure the user permission WRITE_EXTERNAL_STORAGE, see the Phonegap API documentation. This is needed to store the picture taken with the camera on the local file system.

When you are not using Phonegap Build, this needs to be done differently for Android and iOS.

Android:

Config.xml:
<plugin name="Camera" value="org.apache.cordova.CameraLauncher" />
AndroidManifest:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

iOS:

Config.xml:
<plugin name="Camera" value="CDVCamera" />

2. Open the device’s native camera dialog

First, you want to tell the user that it is possible to upload a photo in the App. We added a camera icon to the page and added an onclick event to that icon. This onclick event opens a confirm dialog asking the user if he wants to 1) Make a photo and upload it or 2) Select a photo from the device’s gallery and upload it. After that, the Javascript method listed below is executed.

function onConfirm(buttonIndex) {
  if(buttonIndex == 1) { 
    // User wants to make a photo using the camera
    sourceType = Camera.PictureSourceType.CAMERA;
    captureImage();
  } else if (buttonIndex == 2) {
    // User wants to select a photo from the gallery
    sourceType = Camera.PictureSourceType.PHOTOLIBRARY;
  } else {
    // cancelled
  }
}

As you can see, this method does nothing more than setting the correct sourceType, which is a global var in the Javascript file and executing the method captureImage, which contains the magic. captureImage is listed below.

function captureImage() {
  navigator.camera.getPicture(
    onSuccess, 
    onFail,
    { quality:60,
      allowEdit:true, // ignored by Android
      destinationType:Camera.DestinationType.DATA_URL, //base64
      encodingType:Camera.EncodingType.JPEG,
      sourceType:sourceType,
      targetWidth:160,
      targetHeight:160
    }
  );
}

The captureImage method calls the Phonegap navigator.camera.getPicture method, which is the bridge to the native camera functionality of your mobile device. Some configuration settings are provided, i.e. the destinationType that tells Phonegap we want a base64 encoded image String, the encodingType to configure the image encoding type and the sourceType to tell the device that we want to make a new picture or select an existing image from the gallery. See the Phonegap API documentation for the complete list of configuration properties.

3. Get the photo from the native camera dialog

In order to obtain the photo from the native camera dialog, the onSuccess callback function listed in the captureImage method above needs to be implemented. Our implementation of the onSuccess method is listed below.

function onSuccess(imageData) {
  var theImage = "data:image/jpeg;base64,"+imageData;

  // immediately change the image in the view 
  clickedImage.src = theImage;

  // And now upload the photo to the server
}

4. Upload the photo to your server

To actually upload the photo to the server, we have extended the onSuccess callback function with an Ajax call to our server, which is shown in the listing below.

function onSuccess(imageData) {
  var theImage = "data:image/jpeg;base64,"+imageData;

  // immediately change the image in the view 
  clickedImage.src = theImage;

  $.mobile.loading('show'); // Show the spinner
  doPost(
    '/user/uploadphoto',
    {
       'personid': getUser().personID,
       'photo': imageData
    },
    function(data) {
      if (data.success) {
        alert('Saving photo succeeded');
      } else {
        alert('Saving photo failed');
      }
      $.mobile.loading('hide'); // Hide the spinner
    }
  );
}

On our server we store the base64 encoded JPEG file in our database for the user that uploaded it. The server side code is not included here.

Phonegap camera

As we described above, it is very easy to implement a photo upload mechanism in your Phonegap application using the Phonegap camera object. A few simple lines of Javascript code in your App is enough. Enjoy!

Using PhoneGap Build? You should.. if possible

Unless you need to add your own native code to your PhoneGap project, you can use the excellent PhoneGap Build service. If you do, you may also want to use our nice new app: Buildmeister, a mobile app for easily managing your PhoneGap Build apps.

Download Buildmeister for these platforms:

Android app on Google Play

Buildmeister - X-Services

Phonegap barcode scanner implementation

This article describes how to implement the Phonegap barcode scanner plugin in your mobile application. Most of the time we use the Phonegap Build environment provided by Adobe to build our mobile Phonegap applications for different platforms, mostly being iOS and Android. The Phonegap Build environment makes it very easy to build your applications for the platforms. It is just a matter of uploading your Javascript, CSS and HTML to the build server and Phonegap Build compiles and wraps your code in a platform specific build.

Phonegap Build

So… this all sounds very nice. Are there no drawbacks to Phonegap Build? Of course there are. For example, it is not possible yet to use your own Phonegap plugins. PhoneGap Build offers a limited set of plugins that can be used. The plugins that are available are listed here. One of the plugins that has recently been added is the BarcodeScanner plugin, which we have used in our mobile apps quite extensively.

Phonegap Barcode Scanner

The Phonegap barcode scanner plugin provides functionality to scan a barcode using the camera of your mobile phone. We have used the scanner to implement our KaartSaldo app, which can be used to determine how much money you have left on an electronic gift card that you’ve received (check out www.giveacard.nl for some nice gift cards). These gift cards have a barcode on the back which can be scanned.

So, how to implement the barcode scanner plugin in your application? The first step is to include the BarcodeScanner plugin in your config.xml. This file is used by Phonegap Build to determine what to include in your native wrapper app and how to configure it (i.e. what is the name of the app, what are the splash screens, etc.).

<gap:plugin name="BarcodeScanner"/>

The second step is to include the javascript in your HTML file.

<script src="barcodescanner.js"></script>

After including the javascript you are ready to implement your nice scanning feature. This can be done fairly easy. See the code snippet below for the scan function we have implemented.

function scan(successFunction) {
    var scanner = cordova.require("cordova/plugin/BarcodeScanner");
    scanner.scan(function (result) {
          if (!result.cancelled) {
            // Successfully scanned a bar code
            if (result.format == "CODE_128") {
              loadCardData(result.text, successFunction);
            } else {
              $('#typeInPopup #hint').html("Sorry, invalid format");
              $('#typeInPopup').popup('open', { transition: 'pop'});
            }
          }
        }, function (error) {
          alert("Scanning failed: " + error);
        }
    );
}

In the function scan you can see how to call the BarcodeScanner plugin from your custom javascript function. You provide a success callback function to handle a successful scan and an error callback function to handle errors while scanning. This is all you have to do. Check the documentation of the plugin here for the different barcode formats that are supported.

PhoneGap pull to refresh implementation

We all know the very nice pull to refresh functionality that was introduced in the Twitter app for iOS. Though patented by Twitter, it has been implemented in many apps since. I was working on a PhoneGap app with a page containing a list of news items and was wondering how difficult it would be to implement the pull to refresh functionality on that page. This blog describes how to make your PhoneGap pull to refresh implementation.

PhoneGap pull to refresh

Google led me to the iScrollView JQuery Mobile plugin to use the iScroll scroller. Using this plugin it was fairly easy to implement pull to refresh. A few steps had to be taken. First, include the plugin stylesheets and javascript files in your html file.

<link rel="stylesheet" href="css/jquery.mobile.iscrollview.css" type="text/css"/>
<link rel="stylesheet" href="css/jquery.mobile.iscrollview-pull.css" type="text/css"/>
<script src="js/lib/iscroll.js"></script>
<script src="js/lib/jquery.mobile.iscrollview.js"></script>

Next, add the attribute data-iscroll to the container you want to add the functionality to. In my case, this was the content container of the page. See the first line in the code snippet below.

<div id="scroller" data-role="content" data-iscroll="">
 <div class="iscroll-pulldown">
   <span class="iscroll-pull-icon"></span>
   <span class="iscroll-pull-label"
         data-iscroll-loading-text="News is being refreshed"
         data-iscroll-pulled-text="Release to refresh the news">
     Refresh the news
   </span>
 </div>
 <div id="newsList"></div>
</div>

The <div> with class iscroll-pulldown contains the definition of the pulldown content that will be displayed when the user pulls down the container. Different data tags are available for the different states the pull down dialog can be in. data-iscroll-loading-text for the text to be displayed when the update action is executed and data-iscroll-pulled-text for the text to be displayed when the user has pulled down the container.

So, how do we implement the code to actually update the news items? We need some Javascript for that ofcourse! On the pageinit event of the page we need to bind javascript functions to the different events that have been defined by the plugin. See the code below how the javascript function onPullDown is defined for the iscroll-onpulldown event.

$('#newsPage').live("pageinit", function(event) {
  $(".iscroll-wrapper").bind( {
    iscroll_onpulldown : onPullDown
  });
});
function onPullDown(event, data) {
  //do your stuff here...
}

This is all that is needed to implement the pull to refresh functionality in your JQuery Mobile PhoneGap application. Enjoy!

Game TV

I’ve been wanting to create a mobile videogame-focused app for a looooooooong time. During the Christmas break I finally has some spare time and created…: Game TV  😛 😮 🙂   sorry, can’t stop smiling

Game TV.. wut?

So what is it? By installing Game TV the user will always know which channel (game related websites or youtube channels, to be precise) has added new content. By clicking the channel, the user will see a list of recently added video’s and is able to play the video and share it with friends (email) or the world (twitter). Game TV doesn’t bother you with registration or advertisements, just pick and play!

Game TV at a glance

Technique

Well, we’re all techies here, right? So let’s highlight some technical bits.

Client

 PhoneGap / Cordova wrapped JQuery Mobile app (css3, html5, js). Kindly built by PhoneGap build. Notable stuff:

– Responsive design with CSS3 is cool. See the upper left screenshot in the pic above. This is how I position the video (block a) next to the description (block b)  when in landscape, or above the description when in portrait orientation (default JQM width of these blocks is 50%):

@media all and (orientation:portrait) {
  #videoplayer .ui-block-a, #videoplayer .ui-block-b {
    width: 100%;
  }
}

– As the app will *cough* obviously hit 100.000+ users shortly, clientside caching is very important. We cache the channels and videos in sessionstorage. But to guarantee a quick startup, we also leverage localstorage. When the app is started, the content is immediately retrieved from localstorage and asynchronously updated from the server, showing the diff to the user when done (red  count bubbles, we all know them).

– Since I want my app to be present in all appstores, I had to localise some bits of text. Keith Wood has created a simple yet very effective jquery localisation library.

Server

Play! Framework Java app, doing two things:

– Harvesting new content for all channels. 1 Job per channel.

– Serving the harvested content as JSON to the client.

What I’ve learned

– Android and iOS have great native videoplayers, as long as you invoke them correctly.

– Android animations are still not as smooth as on iOS. Fortunately, JQuery Mobile allows you to easily configure them per platform. I used this snippet:

// override some defaults, before jqm.js is loaded
$(document).bind("mobileinit", function(){
  $.mobile.defaultPageTransition = isAndroid() ? "fade" : "slide";
});

– Adding a Tweet button with a count bubble (see the upper left screenshot in the image above) is not as trivial as you’d think when you don’t want users to leave your app while tweeting. A combination of clickjacking, Twitter web intents and the PhoneGap Childbrowser plugin did the job.

– Some sites make life for a screenscraper really hard. Try to find the URL of the videos being played on this site for example. Horror!

– .. but YouTube rocks, thank you for providing easily parseable RSS feeds like this one (Gamespot channel).

– JQuery Mobile is great, but has some nasty caveats (stacking click handlers, document ready, reloading a page, etc). We’ll definitely blog about some high and lows of JQM in the future, but for now: download the Android app please please please 🙂There will probably be no iOS version because of the strict Apple review guidelines regarding streaming ‘protected’ content.

Dynamically load phonegap.js per mobile platform

Recently I was wondering how to dynamically load phonegap.js per mobile platform. I mean, when using PhoneGap Build, you could just add

<script src="phonegap.js"></script>

to the <head/> of your page, but what about running your app outside PhoneGap Build in a Simulator, on your device, or even as a website locally on your laptop?

Dynamically load phonegap.js per mobile platform

Ofcourse there are more ways to solve the problem, but what we did was really easy and working extremely well: we load our own phonegap/cordova.js file based on the useragent while loading the page and don’t include it in the head at all. Your app supports all deployment scenario’s, even on PhoneGap Build.

The code: an easy bit of JavaScript

Add this to any .js file every page of your webapp needs Cordova functionality for. We’ve included it in a core.js file, which is included in the head of every page. Note that this app doesn’t use jQuery, but Vanilla.js, the fastest JS framework on the planet.

(function loadCordova() {
  var CORDOVA_VERSION = "2.1.0";

  var CORDOVA_EDITION = null;
  if (isAndroid()) {
    CORDOVA_EDITION = "android"
  } else if (isIOS()) {
    CORDOVA_EDITION = "ios"
  }

  if (CORDOVA_EDITION != null) {
    document.write('<script type="text/javascript" src="' + 'js/lib/cordova-' + CORDOVA_VERSION + '-' + CORDOVA_EDITION + '.js"></script>');
    // now add plugins
    if (isIOS()) {
      document.write('<script type="text/javascript" src="js/lib/keychain.plugin-ios.js"></script>');
      document.write('<script type="text/javascript" src="js/lib/certificatepinner.plugin-ios.js"></script>');
    }
  }
})();

Let me explain the highlighted lines:

Lines 5 & 7: Determine the platform by querying the useragent, nothing fancy, so didn’t include details.

Line 12: The correct version for your platform is loaded. By using document.write the library gets evaluated immediately and that’s what we want!

Line 19: Don’t wait for ‘document ready’ or similar events, we want the js evaluated right away.