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.
The problems we encountered
- 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.
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!
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!
- 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.