Uw betrouwbare partner voor (mobiele) web applicaties

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.


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.


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',

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

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',

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',
                   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',
           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");
  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


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

Sign an Android debug-APK for release in Play

“Video’s don’t play and the app is slow”

Game TV
That’s the feedback I got a day after publishing a new version of Game TV to the Google Play store. I thoroughly tested the debug version of the app (built with PhoneGap Build) and it worked fine. After installing the released version myself, I found that indeed the scrolling in the app was terribly sluggish and video’s only played in fullscreen (not as an embedded inline video).

UPDATE: PhoneGap Build has been fixed, so Build users can simply sign the release apk in the cloud.

What to do?

It turned out, I was not alone in this one: it’s a bug in PhoneGap Build where release APK files are incorrectly build (a.o. no hardware acceleration).

I could have waited for the bug to be resolved, but when writing this blog, the problem was already a month old. In the meanwhile I would’ve had a lot of complaints about Game TV. So I tried:

  • Reverting to the previous version of the app in Google Play. This wasn’t possible, because the newer version was already in use, so Play didn’t allow me to activate an older version.
  • Uploading a previously correctly built version. This didn’t work, because again, there was already a distributed version with a higher buildnumber.
  • Build the app offline, instead of using PhoneGap Build. Ofcourse this could have been done, but it would have been a significant effort and lots of testing, while loosing customers.

Then I wondered: “why can’t I release the debug version of the app?

Sign an Android debug-APK for release in Play

Well, it turns out you can. And that’s what solved my problem. Take these steps to use your debug apk and turn it into a release apk yourself (sorry, Mac example only):

  • Get your debug apk. In my case, I downloaded an unsigned build from PhoneGap Build (set the key-dropdown to ‘no key selected’).
  • Fire up a Terminal and cd to the folder where your apk lives. In this case: GameTV-debug.apk
  • Remove the META-INF dir which contains the debug certificate stuff:

    zip -d GameTV-debug.apk META-INF/\*

  • Now we need to sign it for release with our keystore. For PhoneGap Build users: this is what you uploaded when creating a release key for Android. You’ll need to replace alias_name with the correct value. Don’t know it? Running the first command will show all entries in your keystore, look for ‘Alias name’ in the output, then use that value in the second command:

    keytool -list -v -keystore /path/to/your.keystore

    jarsigner -sigalg SHA1withRSA -digestalg SHA1 -keystore /path/to/your.keystore GameTV-debug.apk alias_name

  • This will prompt you for your keystore password and sign it with your release certificate.
  • Now it’s time to zipalign the apk and we’re done:

    zipalign -v 4 GameTV-debug.apk GameTV-zipaligned.apk

Upload your zipaligned apk to Google Play and sleep well 🙂

Promo: Using PhoneGap Build for your apps?

If you do, you may also want to use our nice new app: Buildmeister, a mobile app for easily managing your PhoneGap Build apps.
Android app on Google Play

Buildmeister - X-Services

Bypass AJAX CORS restriction for desktop testing

While developing a mobile app I often need to invoke a webservice which is not under my control. Most times I bump into the fact that I can call a webservice with AJAX from my mobile phone, but not from my desktop browser. This is caused by AJAX CORS.


Cross-Origin Resource Sharing prevents AJAX calls from one domain to the other. A PhoneGap app uses the file prototcol (file:///), which isn’t a domain at all, so no CORS restriction is in effect. However, when testing on your desktop (http://localhost/app), you’re using the http protocol with a domain, so the request fails.

Chrome to the rescue

Google Chrome can be started with a switch to disable the CORS restriction 🙂


To easily start Chrome with disabled websecurity in effect and immediately opening the app I want to test, I added a shortcut to my Mac desktop. You need to name it <yourapp>.command and add this to the file:

open -a Google\ Chrome --args --disable-web-security localhost:8080

One more thing

The command above opens a Terminal shell and then opens Chrome. If you want to terminate the Terminal shell when it’s done opening Chrome, start a Terminal > open Preferences > Settings > Shell > When the Shell exits > ‘Close if the shell exited cleanly’. Apple should have made that the default anyway.

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


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


 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.


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()) {

  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.

Cordova LocalStorage cleared after first App launch on iOS 6

“OMG WTF ! ? “

That’s what we thought today when we were hunting a bug in a PhoneGap / Cordova iOS app.


Upon first launch of the app (in the simulator, from PhoneGap build, or the AppStore) the app saves registration info in LocalStorage. Next time the app launches, it checks LS and recognizes you as a known user.

However, upon the second launch, we had to register again and found out that the LS was empty!

The Problem: Cordova LocalStorage cleared

Googling around, we found it’s actually a known issue on iOS 6 in Cordova 2.1.0: Upon first launch, Cordova tells iOS to remember anything the app stores in LS. This is done with a flag. However, the flag is set too late, so anything put in LS on the first run is not saved to the correct location.

The next time the app is started (and any consecutive time for that matter), the flag has already been set and the LS will behave as you’d expect (surviving app restarts, crashes, app upgrades, etc).

The solution

With this blog we hope to save some fellow coders a few hours of bug hunting. The suggestion done by Christian Hemker in the issue mentioned previously is the right thing to do. We had to roll out a quick fix, so there was no time to upgrade to a newer version of Cordova; we had to patch Cordova 2.1.0 (this bugfix was released with Cordova 2.2.0).

Don’t forget to do a Product > Clean in XCode, so the Cordova files get recompiled along with your project upon the next build.

Using PhoneGap Build?

Unfortunately, it’s not currently possible to add your custom Java code to apps built with PhoneGap Build. But if you do use that great Adobe cloudservice, check out this nice new app we created: Buildmeister, a mobile app for managing your PhoneGap Build apps.

Download Buildmeister for these platforms:

Android app on Google Play

Buildmeister - X-Services


Hide iOS keyboard Form navigation buttons in PhoneGap / Cordova

iOS HTML keyboard with navigation bar

The default keyboard

You have probably seen this keyboard before: the default iOS keyboard that pops up for <input type=”tel”> form fields.

I don’t want those buttons!

The numeric keys are just fine, but the Previous/Next/Done buttons are not what I want when showing a page with only one input field. So… I wondered if the navigational buttons could be removed in my PhoneGap / Cordova HTML5 app.
iOS HTML keyboard without navigation bar

A solution 🙂

Fortunately, the internet is full of people who have similar problems, so a quick look around the globe revealed this great post.

UPDATE July 2013: simply adding this to your config.xml may get the trick done as well. BEWARE: it’s an app-wide setting, so if you need more fine grain control, read on. <preference name=”HideKeyboardFormAccessoryBar” value=”true”/>

But wait, there’s more!

This blog entry wouldn’t have existed if that was it. What I actually wanted, was an on demand solution; for one page show the buttonbar, and hide it on other pages.

Conditionally show or hide the navbar

What I wanted was controlling the appearance of the navigation bar based on a tag in the HTML. A custom class for the body tag seemed right, so I added this to the page for which the navigation bar should be hidden:

<body class="hideKeyboardNavBar">

So all I had to do was adjusting the piece of obj-c I added to my PhoneGap wrapper by checking for existence of the aforementioned classname:

NSString *hideForClass = @"hideKeyboardNavBar";

- (void)keyboardWillShow:(NSNotification*) notification {
  NSString *formClassName = [self.webView stringByEvaluatingJavaScriptFromString:@"document.body.className"];

  if ([formClassName isEqualToString:hideForClass]) {
    // remove the bar in the next runloop (not actually created at this point)
    [self performSelector:@selector(removeBar) withObject:nil afterDelay:0];

The added code is on the highlighted lines: simply check whether or not the className of the body is equal to the className we hide the navigation bar for.

Question for the reader

I’m afraid the trick in the blogpost is as far as we can stretch the boundaries of the HTML keyboard on iOS devices. But… if anyone knows how to add a comma in the empty field below the 7, you’d be king.