Uw betrouwbare partner voor (mobiele) web applicaties
TwitterEmailRSS

Phonegap camera implementation

We are currently working on the implementation of a new App for a customer using the Phonegap framework to simplify development for multiple platforms. One of the requirements the customer came up with is the possiblity for a user of the App to upload photo’s that he made with the camera of his mobile device. Is this possible using the Phonegap framework? Of course it is, and this blog will show you how.

Photo upload using the Phonegap camera object

Several steps are needed to implement the photo upload functionality:

  1. Make sure your App has access to the mobile device’s camera functionality.
  2. Get you App to open the device’s native camera dialog.
  3. Get the photo from the native camera dialog.
  4. Upload the photo to your server.

1. Access to the device’s camera functionality

It is necessary to configure in your Apps’s Phonegap configuration that you’ll be using the Phonegap camera plugin.We are using Phonegap Build, which means that a single configuration file (config.xml) can be used for both Android and iOS.

The following lines have to be added to the config.xml:

<feature name="http://api.phonegap.com/1.0/camera"/>
<feature name="http://api.phonegap.com/1.0/file"/>

Note that the second line is needed because on Android you need to configure the user permission WRITE_EXTERNAL_STORAGE, see the Phonegap API documentation. This is needed to store the picture taken with the camera on the local file system.

When you are not using Phonegap Build, this needs to be done differently for Android and iOS.

Android:

Config.xml:
<plugin name="Camera" value="org.apache.cordova.CameraLauncher" />
AndroidManifest:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

iOS:

Config.xml:
<plugin name="Camera" value="CDVCamera" />

2. Open the device’s native camera dialog

First, you want to tell the user that it is possible to upload a photo in the App. We added a camera icon to the page and added an onclick event to that icon. This onclick event opens a confirm dialog asking the user if he wants to 1) Make a photo and upload it or 2) Select a photo from the device’s gallery and upload it. After that, the Javascript method listed below is executed.

function onConfirm(buttonIndex) {
  if(buttonIndex == 1) { 
    // User wants to make a photo using the camera
    sourceType = Camera.PictureSourceType.CAMERA;
    captureImage();
  } else if (buttonIndex == 2) {
    // User wants to select a photo from the gallery
    sourceType = Camera.PictureSourceType.PHOTOLIBRARY;
  } else {
    // cancelled
  }
}

As you can see, this method does nothing more than setting the correct sourceType, which is a global var in the Javascript file and executing the method captureImage, which contains the magic. captureImage is listed below.

function captureImage() {
  navigator.camera.getPicture(
    onSuccess, 
    onFail,
    { quality:60,
      allowEdit:true, // ignored by Android
      destinationType:Camera.DestinationType.DATA_URL, //base64
      encodingType:Camera.EncodingType.JPEG,
      sourceType:sourceType,
      targetWidth:160,
      targetHeight:160
    }
  );
}

The captureImage method calls the Phonegap navigator.camera.getPicture method, which is the bridge to the native camera functionality of your mobile device. Some configuration settings are provided, i.e. the destinationType that tells Phonegap we want a base64 encoded image String, the encodingType to configure the image encoding type and the sourceType to tell the device that we want to make a new picture or select an existing image from the gallery. See the Phonegap API documentation for the complete list of configuration properties.

3. Get the photo from the native camera dialog

In order to obtain the photo from the native camera dialog, the onSuccess callback function listed in the captureImage method above needs to be implemented. Our implementation of the onSuccess method is listed below.

function onSuccess(imageData) {
  var theImage = "data:image/jpeg;base64,"+imageData;

  // immediately change the image in the view 
  clickedImage.src = theImage;

  // And now upload the photo to the server
}

4. Upload the photo to your server

To actually upload the photo to the server, we have extended the onSuccess callback function with an Ajax call to our server, which is shown in the listing below.

function onSuccess(imageData) {
  var theImage = "data:image/jpeg;base64,"+imageData;

  // immediately change the image in the view 
  clickedImage.src = theImage;

  $.mobile.loading('show'); // Show the spinner
  doPost(
    '/user/uploadphoto',
    {
       'personid': getUser().personID,
       'photo': imageData
    },
    function(data) {
      if (data.success) {
        alert('Saving photo succeeded');
      } else {
        alert('Saving photo failed');
      }
      $.mobile.loading('hide'); // Hide the spinner
    }
  );
}

On our server we store the base64 encoded JPEG file in our database for the user that uploaded it. The server side code is not included here.

Phonegap camera

As we described above, it is very easy to implement a photo upload mechanism in your Phonegap application using the Phonegap camera object. A few simple lines of Javascript code in your App is enough. Enjoy!

Using PhoneGap Build? You should.. if possible

Unless you need to add your own native code to your PhoneGap project, you can use the excellent PhoneGap Build service. If you do, you may also want to use our nice new app: Buildmeister, a mobile app for easily managing your PhoneGap Build apps.

Download Buildmeister for these platforms:

Android app on Google Play

Buildmeister - X-Services

Phonegap barcode scanner implementation

This article describes how to implement the Phonegap barcode scanner plugin in your mobile application. Most of the time we use the Phonegap Build environment provided by Adobe to build our mobile Phonegap applications for different platforms, mostly being iOS and Android. The Phonegap Build environment makes it very easy to build your applications for the platforms. It is just a matter of uploading your Javascript, CSS and HTML to the build server and Phonegap Build compiles and wraps your code in a platform specific build.

Phonegap Build

So… this all sounds very nice. Are there no drawbacks to Phonegap Build? Of course there are. For example, it is not possible yet to use your own Phonegap plugins. PhoneGap Build offers a limited set of plugins that can be used. The plugins that are available are listed here. One of the plugins that has recently been added is the BarcodeScanner plugin, which we have used in our mobile apps quite extensively.

Phonegap Barcode Scanner

The Phonegap barcode scanner plugin provides functionality to scan a barcode using the camera of your mobile phone. We have used the scanner to implement our KaartSaldo app, which can be used to determine how much money you have left on an electronic gift card that you’ve received (check out www.giveacard.nl for some nice gift cards). These gift cards have a barcode on the back which can be scanned.

So, how to implement the barcode scanner plugin in your application? The first step is to include the BarcodeScanner plugin in your config.xml. This file is used by Phonegap Build to determine what to include in your native wrapper app and how to configure it (i.e. what is the name of the app, what are the splash screens, etc.).

<gap:plugin name="BarcodeScanner"/>

The second step is to include the javascript in your HTML file.

<script src="barcodescanner.js"></script>

After including the javascript you are ready to implement your nice scanning feature. This can be done fairly easy. See the code snippet below for the scan function we have implemented.

function scan(successFunction) {
    var scanner = cordova.require("cordova/plugin/BarcodeScanner");
    scanner.scan(function (result) {
          if (!result.cancelled) {
            // Successfully scanned a bar code
            if (result.format == "CODE_128") {
              loadCardData(result.text, successFunction);
            } else {
              $('#typeInPopup #hint').html("Sorry, invalid format");
              $('#typeInPopup').popup('open', { transition: 'pop'});
            }
          }
        }, function (error) {
          alert("Scanning failed: " + error);
        }
    );
}

In the function scan you can see how to call the BarcodeScanner plugin from your custom javascript function. You provide a success callback function to handle a successful scan and an error callback function to handle errors while scanning. This is all you have to do. Check the documentation of the plugin here for the different barcode formats that are supported.

Implementing JQuery Mobile buttons without unexpected side effects

Recently we started the implementation of a new mobile application. We are using the Phonegap / Apache Cordova framework to have a single code base for multiple target platforms. The code base exists of HTML, CSS and Javascript. We use JQuery Mobile to implement the HTML pages.

JQuery Mobile offers different templates, the single page template and the multi page template. We are using the multi page template, which of course means that there are multiple pages in our application. These pages are defined in a single HTML file using the following JQuery Mobile code:

<div id="pageOne" data-role="page">
  Page code here
</div>
<div id="pageTwo" data-role="page">
  Page code here
</div>

Adding behaviour to your buttons

After creating the pages, we added some buttons to these pages. To add behavior to these buttons, we used the JQuery “pagebeforeshow” event of the page.

$('#pageOne').live('pagebeforeshow', function(e, data) {
  $('#myButton').bind('click', function() {
    $.mobile.changePage("#pageTwo", {transition: 'slideup'});
  });
});

After creating several pages and buttons we were ready to run our application to see if the navigation between the pages worked correctly. At first, we were very happy because all buttons seemed to work correctly. However, clicking around for a bit resulted in some very strange unexpected behavior. It turned out that each time the page was shown, the event handler was added to the page. Multiple event handlers to buttons result in ‘clickthroughs’, which basically means that page navigation is messed up.

How to fix this?

Finding the root cause proved to be more difficult than fixing the issue. Just unbind the click behavior of buttons when hiding the page, see the code snippet below. This will prevent multiple event handlers being added to your buttons.

$('#personPage').live('pagebeforehide', function(e, data) {
  $('#previousPerson').unbind('click');
  $('#nextPerson').unbind('click');
});