Archive for February, 2011

How to Use CameraUI in a Cross-platform Way

If you use, or plan to use, the CameraUI API, this post will explain how to do it in a cross-platform way so your code will work on both iOS and Android.

The AIR mobile profile supports an API called CameraUI which can be used to launch a device’s native camera application for taking both still photos and video. AIR applications can then access the photo or video and do whatever they want with it. I prefer this method to the Camera ActionScript API because it gives the user the native camera experience he or she is accustomed to along with all the camera features and functionality available on the device.

The problem with the API is that there’s an easy way to use it, and a slighter harder way, and the easy way is not cross-platform. I discovered this when writing AIRBench — an AIR application that demonstrates and tests all the mobile profile specific APIs in AIR. I wrote AIRBench before the CameraUI APIs were available on iOS, so I was only able to test them on Android. Naturally, being a programmer who prefers simplicity to complexity, I used the easy CameraUI APIs only to discover, when running AIRBench on iOS, that the CameraUI test didn’t work.

The easy (and non cross-platform) way to use the CameraUI API is to do something like this:

private function onLaunchCameraUI(e:Event):void
{
    var cameraUI:CameraUI = new CameraUI();
    cameraUI.addEventListener(MediaEvent.COMPLETE, onCameraUIComplete);
    cameraUI.launch(MediaType.IMAGE);
}

private function onCameraUIComplete(e:MediaEvent):void
{
    var picture:File = e.data.file;
}

The data property of the MediaEvent is a MediaPromise object which has a file property which, in some cases, points to the photograph that was just taken. In some cases, but not all. On Android, when the CameraUI is used to take a picture, the photo is stored in the camera roll so the file property of the MediaPromise can reference it. On iOS, however, the image isn’t stored in the camera roll (unless you choose to do so yourself) which means that the file reference is null.

The better (more cross-platform) way to write this code is to load the image asynchronously from the MediaPromise itself. Here’s the refactored code from AIRBench:

private function onLaunchCameraUI(e:Event):void
{
    var cameraUI:CameraUI = new CameraUI();
    cameraUI.addEventListener(MediaEvent.COMPLETE, onCameraUIComplete);
    cameraUI.addEventListener(Event.CANCEL, onCameraUICanceled);
    cameraUI.addEventListener(ErrorEvent.ERROR, onCameraError);
    cameraUI.launch(MediaType.IMAGE);
}

private function onCameraUIComplete(e:MediaEvent):void
{
    var cameraUI:CameraUI = e.target as CameraUI;
    cameraUI.removeEventListener(MediaEvent.COMPLETE, onCameraUIComplete);
    cameraUI.removeEventListener(Event.CANCEL, onCameraUICanceled);
    cameraUI.removeEventListener(ErrorEvent.ERROR, onCameraError);

    var mediaPromise:MediaPromise = e.data;
  
    this.mpLoader = new Loader();
    this.mpLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, onMediaPromiseLoaded);
    this.mpLoader.addEventListener(IOErrorEvent.IO_ERROR, onMediaPromiseLoadError);
    this.mpLoader.loadFilePromise(mediaPromise);
}
  
private function onMediaPromiseLoaded(e:Event):void
{
    var mpLoaderInfo:LoaderInfo = e.target as LoaderInfo;
    mpLoaderInfo.removeEventListener(Event.COMPLETE, onMediaPromiseLoaded);
    mpLoaderInfo.loader.removeEventListener(IOErrorEvent.IO_ERROR, onMediaPromiseLoadError);
    this.imageDisplay.source = mpLoaderInfo.loader;
}

It’s a few more lines of code, but it works perfectly on Android and on iOS, and it will also work on any mobile profile platforms that AIR supports in the future.

If you’re using the CameraUI API now on Android, I strongly encourage you to use the technique described above to ensure that your code is as portable and cross-platform as possible.

How to Discover Your AIR Runtime Version

This morning, someone asked me how to figure out what version of the SDK and/or AIR runtime you’re using. Rather than just respond to the email, I figured I would blog it for everyone to see.

Here are two easy ways to see the AIR runtime version you’re using:

  1. Check the "AIR SDK Readme.txt" file in your SDK directory (the version is at the top).
  2. Trace out NativeApplication.nativeApplication.runtimeVersion.

Remember that you don’t want to check the runtime version to see if certain capabilities, features, or APIs exist — rather, you want to use an individual feature’s’ "isSupported" flag. But for debugging purposes, knowing your runtime version programmatically can sometimes be useful.