Friday, September 14, 2012

How we sidestepped an App Store catastrophe

UPDATE: The app has been approved since I originally wrote this post. The app review delay had nothing to do with technology choices, and Apple has been fairly quick to approve updates since.

I submitted Outbox's iPad app for review on July 10. It went into "In Review" status on July 24, where it has remained ever since. Actually, it was rejected once on August 22 because the demo account credentials I gave didn't work, despite server logs showing 2 logins on the demo account from Cupertino. I resubmitted, saw 4 logins the following day, and have heard nothing since. My expedited review request was denied. The request status update feature in iTunes Connect is a joke because it takes a week to get a response that the app is still in review, which of course I can see in iTunes Connect. Apple Developer Relations can't help because they can only contact the review team through the same channels I can. One of Outbox's founders even contacted a handful of friendly VPs at Apple for help, and still nothing.

So here we are 2 months later (and counting), still in review.

For a while we continued to plan our launch for "after we get approval" thinking that the app was bound to be approved soon since it had already been so much longer than the average review time, but the weeks kept slipping by and we were forced to delay our launch week after week. Finally, we came to terms with the fact that Apple will get around to approving (or rejecting) the app whenever they damn well feel like it. It could be tomorrow or it could be a year from now. The important lesson I learned is if your product lives in the iOS App Store you are forfeiting control over your release schedule. Have a backup plan.

Fortunately the Outbox iPad app is built with Javascript, HTML, and CSS. The app calls into native extensions for functionality like contacts and notifications as needed through PhoneGap, and makes heavy use of hardware accelerated transforms to get a native look and feel. So after a short discussion, we decided to launch a web app with support for iPad only (we haven't optimized for different aspect ratios or mouse interaction yet). This required almost zero additional effort because this is how we test the app most of the time anyway. The native bits that the app depends on degrade gracefully in a browser when they are not available. The only thing that needed to change was the email confirmation at the end of the signup process which now says "go to this URL on your iPad" instead of "download the app from the App Store". Our designer whipped up a screen with some instructions for the user to pin the app to the home screen when they follow the link from the confirmation email:

In some ways the web app experience is actually better than the app store version of the app. Nitro is available in chromeless web apps, but not in UIWebView, so Javascript execution gets about a 5X speed boost. At any rate, launching the web app beats the hell out of sitting around waiting when we could be making money and iterating on the product. Had we built a fully native application to begin with, turning around to build a web app would likely have taken weeks, if not longer. And if nothing else, it feels good to own our release schedule again.

We just launched in Austin, so if you live in Austin, try us out!

Monday, September 3, 2012

My first "Hacker News Effect" experience

I recently ended a long quiet period on my blog. It had been 9 months since my last post, which incidentally, is about how old my daughter is... I'm sure there's correlation there somewhere. Anyway, as I sat around feeling like a bad citizen of the internet, I decided to dust off a post about mobile web performance I had been working on for a while and finally publish it. I also figured I might as well try submitting the post to Hacker News. I checked the pickup rate and saw that it was a "good time" to submit, so I did, fully expecting to get just a handful of extra views before the submission quickly and quietly dropped off the newest submissions list.

About 10 minutes later I checked my traffic statistics and saw I had almost 200 views. I checked Hacker News and saw my submission was in the #5 spot on the front page. My wife and I spent the next 2 hours watching the submission rise to the top spot while racking up a little over 3,000 views. I actually had trouble sleeping that night! But not the bad, anxious kind of sleeplessness, it was lack of sleep due to excitement!

By the time my submission dropped off the front page my post had received about 15,000 views. I never promoted my own writing before so my blog received a steady trickle of organic search traffic. Hacker News made my previous traffic graph look like a flat line.

The initial spike has long since ended, but the post is still getting around 100 views per hour, which is head and shoulders above what my blog used to get!

My biggest surprise throughout the whole experience was how overwhelmingly positive the feedback was in both the discussion on Hacker News and in the comments on the post. Here was my favorite:
I already feel like you saved me 2 weeks in testing.
Thank you Hacker News, and thank you to everyone who stopped by to read!

Saturday, September 1, 2012

10 tips for getting that native iOS feel with PhoneGap

At Outbox we have been hard at work building our iPad application with PhoneGap. I wanted to share some of the lessons my team has learned so far. All of the following tips have been tested on iOS 4, 5, and 6 with PhoneGap 1.8. Also note that these tips apply just as well to web applications running on mobile Safari.

Want more information about developing high quality PhoneGap applications, with in-depth explanations and working code examples? Check out

Tip #1 - Test on old hardware

Your app looks and feels great on that shiny new iPad 3 or iPhone 4S, right? Unfortunately, not everyone runs out to drop $500 whenever Apple releases a new toy. Get your hands on a first generation iPad or third generation iPhone. Always test on them first. If your app performs acceptably on on old hardware it is going to be blazing fast on the newer hardware.

Tip #2 - Use pre-emptive 3D transforms

If an element is going to be transformed in response to user interaction put an identity 3D transform on the element before any user interaction happens, for example:
-webkit-transform: translate3d(0px,0px,0px);
When the user first interacts with the element the initial movement will be much smoother.

Tip #3 - Show or hide elements with 3D transforms when possible

Invariably you will have some elements that need to be shown or hidden based on user interaction. For example, a modal dialog or menu of some sort. The easiest way to do this is usually display:none or visibility:hidden, however, you can achieve a significant speed increase by using a 3D transform to position the element offscreen. In my experience, using this technique to show or hide menus resulted in a 3-5X speed increase over display:none.

Tip #4 - Preload images

Even though your images are already stored on the iOS device there will still be a noticeable "pop-in" when the images are first displayed. I found CSS3 caching to be the best method for dealing with this issue. If you are not keen on enumerating and maintaining a list of every background image you use in your app, here is a jQuery plugin that will preload any background image referenced in your CSS.

Tip #5 - Phark image replacement does not play nice with 3D transforms

Image replacement by setting a large, negative text-indent is great for accessibility since screen readers will find the text and browsers will only display the image. However, the text-indent will make for unbearably choppy 3D transitions in mobile Safari (this is actually related to tip #7). Fortunately, there are alternatives to Phark that perform much better.

Tip #6 - Velocity scrolling!

Velocity scrolling is a super easy way to get a native feel in the scrollable portions of your app. It is simple to enable it on any scrollable area with a CSS rule:
-webkit-overflow-scrolling: touch;
That's it! However, be warned, Apple's current implementation is a little bit buggy.

Tip #7 - Respect maximum texture sizes

Each iOS device has a maximum texture size. If you try to smoothly transform an element larger than the maximum texture size, the element will be broken into smaller tiles before the transform is applied, and this a very slow and ugly process.

Tip #8 - Hide large, off-screen images

If your app displays many large images, hide the images that are off-screen. Otherwise, it doesn't take many large images to unceremoniously crash your app. Both display:none and visibility:hidden work just fine, but tip #3 will not cut it here.

Tip #9 - Eliminate tap event delays

It takes mobile Safari about a third of a second (300 milliseconds) to decide that a touch start event followed by a touch end event should be synthesized into a click event. Plenty of frameworks, such as jQuery Mobile, have "tap" handling code that can eliminate this delay for you.

Tip #10 - Disable tap highlighting

Have you ever noticed that translucent gray highlight mobile Safari puts on links and buttons when they are clicked? It is a dead giveaway that your app is not native, but you can get rid of it by making the highlight color completely transparent:
Overall we're loving PhoneGap at Outbox. Hopefully these tips will help make a few more happy PhoneGappers!

This post got picked up by Hacker News. See the discussion here.