Monday, February 4, 2013

PhoneGap and jQuery Mobile: Work Around for Camera Crash

PhoneGap is a great program to create apps for mobile phones. If you haven't heard of it, read about it here. For the most part, PhoneGap works great, but I ran into an issue where the camera plugin on Android crashes (the camera does not have this problem on iOS). Turns out a lot of people have this problem:

https://issues.apache.org/jira/browse/CB-193
https://issues.apache.org/jira/browse/CB-205
https://groups.google.com/forum/?fromgroups=#!topic/phonegap/xjf8TKVC6YA

After doing some research, it turns out that it is a problem with Android itself and not just PhoneGap. What happens is that Android will close apps when the device runs low on memory, particularly when launching other apps through intents. When you call the camera in PhoneGap, Android will pause the PhoneGap activity and load a camera app (the default camera app or one that the user chooses if they have more than one). If your phone does not have a lot of memory, Android will have to close the original PhoneGap activity so the camera has enough memory to function. When the camera is done, it will close and Android will automatically open the PhoneGap app again, but the PhoneGap app will just open to the first activity and it will have no idea what picture the camera just took.

Android does provide a way for your app to deal with being closed automatically, the onPause() and onResume() Activity events. If you are developing an Android app from scratch, you can use these events to save your app settings before it closes and load the settings again when your app restarts. PhoneGap also hooks into these events with "pause" and "resume" event listeners, but we still need a way to persist the data in the meantime.

Enter HTML5 local storage. The idea to overcome the camera closing issue is to store a flag using local storage before opening the camera. Local storage is persisted between browser sessions so if Android closes the PhoneGap app before it can get the result from the camera, the PhoneGap app will know that it was supposed to get a picture back. The reason the PhoneGap team can't implement this in the PhoneGap code itself is because users may want to do something different with the result from the camera. I have the PhoneGap app load the last picture taken with the camera and then I use jQuery mobile to go to the page where the camera was loaded. Some sample code:

initPagePhoto: function() {
$('.send-image').click(function () {
localStorage.camera = "true";
                        ...other camera stuff here...
                }
       };

When loading the app, check to see if the local storage flag is set:

if (localStorage.camera == "true") {
...do whatever you needed to do with the camera picture...
}

I've found that local storage can solve a lot of small problems like this using PhoneGap.