Polyvore released its second iOS app recently. Pure native iOS. Yes, the second. Most people don't remember the first version. We launched a PhoneGap based app earlier in the year but removed it from the app store less than a week later. So why the complete change between v1 and v2?
Before I continue, a disclaimer: I love HTML5. I created the Yahoo! Pipes editor back in early 2007 which surprised many when they realized it wasn't flash but HTML+canvas. I love CSS3 hardware accelerated animation (check out the accordion in the Polyvore mobile HTML web site). Local storage is so useful. HTML5 features just make the user experience faster, better.
So why did we want to create an app when we already had a mobile friendly HTML version for webkit-based browsers (iOS and Android)? Engagement. We really wanted to offer up a more compelling user experience, complete with all the things people expect from apps like push notifications. From a business perspective having an installed presence on the device that could keep bringing users back for new content, and potentially shopping through the app, would be ideal.
An HTML5 based approach
So we opted for wrapping and modifying our JS/CSS with PhoneGap (now Cordova). And off we went. We tried mobile jQuery, Sencha and a few other JS frameworks while we were at it. We spent a lot of time trying to make our PhoneGap app feel native using CSS 3D transitions and various other well known tricks. And indeed, working with Webkit as your operating system gives you a great head start - and from a pure familiarity and comfort perspective, it’s just great. Few cross browser woes either (Android webkit, sigh).
But then you start running into stuff thats really hard to control. For example, Polyvore is a graphics heavy site and putting lots of images into a -webkit-overflow-scrolling: touch; accelerated scrolling experience will cause webkit to crash. Sometimes. Occasionally. Memory related? Probably. De-referencing images as they scroll off helps - but you don't get the scroll events delivered when you really need them when you're running in the smoother scroll. These types of issues just kept cropping up. And we kept building more and more special stuff to make it more and more app like. More plugins for PhoneGap, more Objective-C stubs, more special cases. What you end up doing is attempting to rebuild UIKit on the iPhone and view animations for Android (or using a framework that’s doing the same).
It felt like hammering nails into in a wonky floorboard. We fixed one problem and another would pop up. We probably spent over 80% of our time fixing weird side-effect glitches and making our code work within PhoneGap correctly. But eventually we felt it was much better than our HTML mobile version of our site with transitions and notifications and so we launched it.
Lessons learned and relearned
Some of these reasons may sound very familiar and the Facebook blog post came out mid-way through our development of the second app. We couldn’t have agreed more when we read it.
Unfortunately we’d needed to re-learn an important lesson. It’s all about great products. Not average “ok” stuff, but truly great. It’s something we focus on here at Polyvore and this time we’d missed the mark. We’d spent so much time and effort re-creating UIKit-like functionality in JS/CSS that worked “just like a native app”, we’d lost sight of our goal. Creating something great.
An obvious caveat. Building an app this way is clearly going to take you longer, possibly a lot longer. You’re re-writing your entire client side interface in a language and environment you are unfamiliar with, and if, like us, your web-oriented engineering team has no iOS experience to build upon, the learning curve is going to be pretty steep.
Reassuringly there were a lot of abstractions and code we could leverage from our JS. We moved our data model over almost directly into Objective-C and re-used our Ajax APIs for fetching and updating data. And while the entire DOM-based UI and JS eventing system had to be thrown out, KVO and NSNotifications coupled with UIKits built-in widgets translated very well.
Even after a few weeks of learning Objective-C and fighting Xcode we knew it was the right choice to deliver the app we wish we'd created the first time. Things that took forever getting working well in HTML5 just work. View transitions, UI Thread prioritization, background threads, view re-use and memory management are all built in. Not added on, but core to the framework.
Quick, fast, snappy. Objective-C is certainly no panacea - it has its own issues and weirdness. It wasn’t a quick and simple “port” and without being able to leverage any other Objective-C knowledge in our organization we did a lot of things wrong before getting them right.
Do you really need an app?
So before you start coding your app ask yourself if you really need one. An HTML5 version of your site in the web browser can behave however you want it to without confounding users’ expectations. If you want to create the best user experience possible for the iPhone don’t try to fake the iOS look and feel, you’ll spend too much time on the things you get for free from a native iOS app and not enough delivering the meat of your experience. So bite the bullet, learn Objective-C, and produce that awesome app that will bring joy to your users.