Phonegap: Fixing black bars on iOS7/iPhone5

Last week, we were using Phonegap Build to build an iOS IPA for a project an ran into an odd issue. When we launched the app on an iPhone 5 running iOS7 black bars appeared at the top and bottom of the screen. On top of that, when launching the app we were observing the same issue with the splash screen.

In typical Phonegap fashion, Googling for people suffering from similar issues brought back dozens of results across several versions each with a different root cause and solution. One of the first promising leads we noticed was this comment in the top of the default Phonegap template:

Unfortunately, that comment seems either be invalid or the issue has since been resolved since removing those meta attributes had no effect.

As it turns out, the issue is that the “config.xml” file created by the default Phonegap “Hello world” project is missing an entry for the iPhone5’s screen size. Oddly enough, there’s actually a splash screen image of the correct height in the demo project but its not referenced in the config file. To resolve this issue, you just need to add this line to your config.xml:

Just make sure that you have a file named “res/screen/ios/screen-iphone-portrait-568h-2x.png” where the rest of your splash screens are and you should be good to go.

Javascript: Phonegap with Backbone and Marionette

We’ve worked with our clients to execute a couple of Phonegap apps lately and in doing so used Backbone and Marionette to structure the apps. For some background, Phonegap, now Apache Cordova, is a project that allows developers to build native iOS, Android, and WP apps using HTML, CSS, and of course Javascript. As a developer, you write some HTML and Javascript, pass it to Phonegap, and Phonegap returns a native app that displays your code inside a WebView without any surrounding chrome. On top of this, Phonegap provides a set of Javascript APIs that allow you to leverage some of the device’s native functions, like the accelerometer or camera.

Writing apps with HTML/JS is great, but it presents some issues particularly that triggering a full page reload for navigation appears “non-native” on mobile. On technique to combat this issue is developing single page Javascript apps. In a single page app, the entire page is never reloaded, instead portions of the DOM are dynamically re-rendered using Javascript. Because of the complexity of managing this process with straight Javascript, several libraries, including Backbone, have been developed to simplify this process. Marionette is a companion library to Backbone which provides a set of features to make managing complex applications easier. So, what were the pros and cons of using Backbone with Marionette to build a Phonegap app?

The Good

Structure: Using a library like Backbone guides you to structuring your code in loosely a MVC design pattern. Coupled with a templating framework, this ends up producing code that’s much easier to follow and maintain. Before Phonegap, I’d already started using Backbone in traditional Symfony2 projects just to get the benefit of better structured code.

It’s familiar: This is a personal preference, but compared to declarative frameworks like AngularJS, Backbone/Marionette apps “look” like regular HTML/JS. Primarily because of the regular HTML templates and use of jQuery, the learning curve for Backbone isn’t very steep. A team member without Backbone experience can quickly grok how things work and make changes quickly.

The Not So Good

“There’s more than one way to do it”: Although flexibility is good, having a generally “well recommended” way usually helps decrease confusion and frustration. With Backbone/Marionette, there doesn’t seem to be much consensus on how to do “standard” things like message passing or even structuring the app as a whole. There’s dozens of StackOverflow answers debating the “best” way to approach things, often with outright conflicting viewpoints. In contrast, Symfony2 and Rails typically have “best practices” for approaching common tasks, even if they’re not appropriate in every circumstance.

Documentation: The documentation for Marionette, and to a lesser degree Backbone, is pretty lacking. The Marionette documentation explains how the individual components work but they didn’t provide much insight to the “big picture”. The docs were also missing some explanation into the “why”, which of course lead to StackOverflow answers and then differing viewpoints. Marionette is also short example apps which Backbone does have. The Backbone documentation is thorough, its just a bit hard to navigate and purposefully introduces the “There’s more than one way to do it” mantra.

Anyway, on the whole using Backbone with Marionette to build a Phonegap app was a positive experience. Unfortunately, our clients’ own the code so we can’t release it. That said, we’ll do our best to build something in-house that we can share.

Phonegap: Recording audio with Phonegap

I was working on a Phonegap app recently and one of the goals was to allow the user to record some feedback as an audio file which would later be shared. If you hit Google, there’s plenty of StackOverflow threads which claim to have working sample code. Almost all of the SO code is using the Phonegap Media API with the “startRecording”/”stopRecording” functions. Despite it looking simple, I could never get the Media based code working on iOS. For whatever reason, I kept hitting iOS permission errors trying to create the recording file. On Android, the code works but I kept ending up with an “AMR” file instead of the expected 3gp recording.

So what’s the alternative? Turns out there’s another Phonegap API called Capture which has a captureAudio method which lets you record audio. As opposed to Media, captureAudio uses the device’s native audio recording UI to let you to record audio. Because of this, captureAudio won’t work for all use cases but the implementation is straightforward and consistent across Android and iOS.

Anyway, here’s the code to record some audio and upload it to a server:

Then, on the server you can just grab the file from say the $_FILES[“file”] variable.