Sunday, 9 February 2014

Review of building mobile apps with Cordova / PhoneGap and a bit about Xamarin and Appcelerator Titanium

A few years ago we were asked by a client to create a small iPhone app.  We decided to explore the possibility of creating a HTML5-based app using PhoneGap.  Using this technology, you essentially create a single page website, which utilises JavaScript and CSS and then embed that inside a pre-assembled native app.  The only bit of the app that's native is the web view control that hosts the web page.  We created a prototype and deployed it to the iPhone 3; it was functional but the app just didn't "feel right". The controls weren't responsive enough and it just wasn't an acceptable experience, so we decided to abandon PhoneGap and go fully native with Obj-C.  After that I didn't really thought about building another app with HTML for quite some time...

However, last year, I had another SME client approach me about a new app for Windows Phone, Android and iPhone.  It's a relatively simple app in that it's just a UI layer over a Web JSON API.  They did not have the budget to create 3 different native apps, so again, I set about trying to find a solution.  I revisited PhoneGap which has since been renamed Cordova and now PhoneGap is a distribution of Cordova with some cloud services attached and is a few versions behind the bleeding edge Cordova builds.

Having built a prototype, we were quite satisfied with the performance and UX on Android and iPhone... on Windows Phone, it's abysmal, but hey, given that WP is only a 10% marketshare we were OK with that (although really I'd have liked it to rock on WP).

We then proceeded to develop the app with Cordova and using Sencha Touch as the UI framework.

If you don't know Sencha Touch, it's basically set of tools which allow you to create app-like JavaScript applications that render with HTML/CSS.  You "build" Sencha Touch apps which minify all the web assets and create a bundle of files which can be deployed onto a web server, or into an app framework like Cordova.

The problems we encountered
  •  The Sencha-"compiled" code operates differently to the development code.  That is, you sometimes end up with bugs that you have to debug via the JavaScript console because the JS code is minified and the error messages are cryptic.  This is akin to spending 3 hours writing C# code and then finding when you deploy it, it doesn't work and you have to debug the MSIL (intermediate code / byte code).  To be fair we didn't get too many issues like this, but this was an unquantifiable overhead and an unknowable apriori.
  • You have to build and deploy Sencha Touch apps into the separate Cordova file structure.  Sencha can integrate with Cordova, so in theory, you could type sencha app build native and it will compile (minify & bundle) the Sencha app, deploy those assets into Cordova's file structure and then command Cordova to compile the app across all the target platforms.  However, if you're building iPhone, Android and Windows Phone apps, this command will always fail because you can't compile iPhone apps on Windows and you cannot compile Windows Phone apps on Mac.  You then have to command Cordova directly to compile against which ever platform you wish to test.  The problem is that this chain of process is very time consuming.  You have to very regularly test the app on real devices because Sencha apps operate differently when compiled and Cordova apps can only really be tested inside an emulator or device.  So suddenly your process for actually testing this stuff is unweildy.  It's an important point, because we developers have become so accustomed to writing code, immediately testing it, playing around, iterating... Going from code to testing on a device and becoming confident that this code will work across all platforms is cumbersome.
  •  We wanted to utilise Push notifications within the app so used Ext.Azure, which is a Sencha component written in collaboration with Microsoft.  Between Microsoft, Sencha and Cordova someone has seriously dropped the ball here.  You have Ext.Azure as a Sencha component, which normalises the intricasies of implementing Push across WP, Android and iPhone.  They seem to say in the documentation that you just download the PhoneGap PushPlugin, put Ext.Azure into your Sencha app and away you go.  The fact is, as of the time of writing, the PushPlugin does not support Windows Phone.  You actually have to integrate a branch of the PushPlugin by darkphantum, rather than the one by PhoneGap.  However, you cannot just utilise DarkPhantum's plugin instead of PhoneGap's, you have to merge the two branches manually, as the PhoneGap plugin is compatible only with the PhoneGap distribution of Cordova - which in itself Cordova from a few versions ago.  So if you're using the current version of Cordova and you implement the PhoneGap plugin, you'll get native compilation errors.  Merging the branches is quite easy, you just copy the PushPlugin.cs into the Windows Phone native project and declare the Plugin in the config.xml file.  The only remaining problem is that config.xml gets automatically rewritten by Cordova and because you've effectively hacked the PushPlugin into Cordova, then Cordova doesn't "know" about the Windows Phone support and you'll constantly find the Push notification doesn't work because of a permission denied issue.  There are probably ways around this by hacking it, but we never got around to that.
  • We wanted to implement Splash screens, however, following the documentation doesn't help.  The Splashscreen plugin didn't seem to do what it's meant to do.  I'm sure there are ways to fix this, however, you can't end up in a situation where a Splash screen takes development time - this is one of those things that should be easy.
  • We found that on iOS 7, the status bar would overlap the UI and prevent users from interacting with controls so we tried using the Cordova status bar plugin which did work.... until we spotted that if you put focus in a textbox, then the UI shifts up... fine... but then when the textbox loses focus, the UI shifts down, however, not the whole way.  The status bar plugin shifts the UI down by 20px, but after a textbox focus event, the UI resets back to being at 0px, so goes underneath the status bar.
  • We also found some configuration options in Cordova's config.xml just don't work. 
Fundamentally, we chose Cordova because we wanted to write one app, that would work across all platforms.  We wanted Cordova to abstract-out platform-specific concerns. It's the same with any engineered thing; you want to know it's interfaces and that is all.  If you have to get bogged down with how it works, then, well, what's the point (given the goal is to have that abstracted).  Put another way, a mechanic can fit a new battery in your car, but he doesn't not have to know battery chemistry and if the battery doesn't work, he sets about to find a new battery, rather than getting a chemistry degree.  Sure, in our situation, Cordova is software and the app is software, however, they are two distinct domains - specialisms.  Going massively on a tangeant here, but you could have had a virtual car with a virtual battery - all done in software and the semantics are the same.

I think the goals of Sencha and Cordova are great and maybe one day it'll be a great experience, but for now, we have to leave it.  The amount of friction means the app takes so much longer to develop, you may as well have just gone native and enjoyed being able to debug code on the device, have fast compilations and deployment, and have predictable results between dev and production builds (i.e., doesn't break just because you compiled it).

Xamarin.  I looked into this, however, if you wanted to create a WP, Anrdoid and Windows Phone app, you'd still effectively have to write 3 apps.  Xamarin allows you to share C# across all the platforms, but this cannot be UI code, so if you're writing an app, like us, where it's just a thin UI layer over a Web API, then the only advantage of Xamarin is that you can write iPhone, Android and WP apps in C#.  I say, "only" not in a derogatory way, it's just I quite like writing software in Obj-C, C# and Java.  If you're proficient in all those languages, then it's probably not worth the added layer of abstraction and complexity of Xamarin.  However if you're doing an app with a complex backend component or you don't have the time/resources for Obj-C/Java, then Xamarin could be the way to go!

Appcelerator Titanium.  This is an interesting option.  You can write an app using JavaScript and platform-agnostic and platform-specific APIs.  In a Titanium app, the UI is native, which means you get excellent performance and a fluid UX - users can hardly notice the difference. The way it work is that your JavaScript code and a JavaScript engine is shipped with the app.  The JS engine interprets your code and maps the JS API calls onto the native counterparts.  It is possible to write an app in JS using only the platform-agnostic APIs.  These APIs represent things like table views which Android and iOS have in common.  You occasionally have to use platform-specific APIs in order to create a UX which is inline with the way the underlying platform works.  For instance, you may use a Popover API which will only work on iOS, so you'd have to use another component on Android.

The downsides of Titanium are:
  • The deployed apps are a bit bigger as they contain a JS engine
  • The platform-agnostic APIs may result in UI working correctly on one platform, but not on another, so you end up iterating between the platforms until they both work
  • Whilst the UI performance is great, there is a performance hit with using JS, especially if you have any complex back-end code.
  • Debugging is quite difficult compared to native dev
  • You will most likely have to use platform specific APIs for a medium-to-large app, which means you have a learning overhead, if you don't know some stuff about iOS / Android development
  • You cannot use it for Windows Phone... hopefully one day!
The upsides are:
  • You can write an app using one code base
  • The UI is native, meaning users largely do not notice any different when it comes to UX
  • It's free!
  • You don't need to learn Java or Objective-C
  • It's technically possible to write an app in such a way that you never need to be concerned with platform-specific stuff.  However, is that wise?  Users on Android and iPhone are accustomed with specific UX-patterns that, if you ignore, you may end up alienating them. 

The main motivation for using any of these abstraction layers is to save time and money.  Clients want to target Windows Phone, Windows 8, iPhone, iPad and Android in one fell swoop with one app.  In my opinion, the reason for using an abstraction layer should be to totally abstract the details of the underlying platforms.  Also, you should never ever have to delve into the details of abstraction layers (such as re-compiling Cordova plugins); as these defeats the point in using them. 

Personally I love doing dev in C#, Java and Objective-C, so the only gain for me in using these frameworks is to save time.  I have spent a number of weeks utilising Titanium and Cordova, only to find that it's actually a false ecomony.  I spent a lot of time dealing with bugs in Cordova and weird anomalies in Titanium.  I found my productivity and time was thwarted by stuff that wouldn't have come up had I gone native.

I'll probably review these frameworks again in a year or two, but for now, I'll be advising clients to go native.  It's just vastly better from a user experience point of view and from the developer point of view.

There is no objective black and white answer though.  You may find for your projects an abstraction layer works well for you. 
Kris Dyson