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.

31 Responses to How to Use CameraUI in a Cross-platform Way

  1. Pingback: Tweets that mention How to Use CameraUI in a Cross-platform Way « Christian Cantrell -- Topsy.com

  2. Pingback: How to Use CameraUI in a Cross-platform Way

  3. Seth says:

    Hi Christian,

    Are you using a private version of the iOS packager/API? The current iphone packager doesn’t allow the use of CameraUI since it’s locked to AIR 2.0 (not 2.5). How are you testing this on AIR 2.5 for iphone?

  4. Mikhailov says:

    Hi =)
    I have the same question.
    Please let us know the truth =)

  5. I’m actually wondering something. I’d like to know if the sources for the PFI.jar are open source, or at least partially. The license says that we can request permission to decompile the jar, where do I do that? I don’t even care about using it for the iphone at all, all I want out of the jar is the LLVMEmitter code and associated classes so I can build a pure actionscript to SWF compiler using LLVM. I really don’t want to have to sit here and code GlobalOptimizer to emit LLVM IR when you guys have already done it, but will if I have to. Please email me with any nfo, even if it’s just someone I can contact and make a formal request to decompile the jar in accordance with the PFI license.

  6. Pingback: Cool Stuff with the Flash Platform – 2/10/11 | Finding Out About

  7. Pingback: Everything New in Adobe AIR 2.6 « Christian Cantrell

  8. Pingback: 火柴工作坊 » Adobe AIR 2.6的新特性

  9. erik says:

    Can iOS applications created with adt playback videos? Or do we still need to use navigateToURL( )?

  10. Pingback: Adobe AIR 2.6的新特性 | AdobeShowCenter

  11. Pingback: Adobe AIR 2.6 | ChinemitBlog

  12. Axel says:

    Hey Christian,

    Thanks for posting this, it was much needed to figure out the iOS stuff for me… my problem is… in my view i have something like.

    and i’m using some model view controller presentation model type code. everything works fine in android, and when it comes back i can just store the url in my local db… and then it recalls fine when i load the object from the db again, because the image_url = “file:///….”

    but if I use this method, how would i store the path for iOS so that it recalls correctly from the db? is there a path?

    also was a little confused on the debugging of iOS… compiling takes a while with the pre release, which im sure your aware, so i was just wondering any tips or tricks you know of to help debug what you get back on iOS?

    thanks again man.

    Axel

    • nona says:

      hi mr axel , i have the same problem that you have , and i would like to know if found some solution for that problem :

      to find the name of the captured image and the path in the device IOS (Ipad)

      thanks for ur help

  13. Pingback: AIR Mobile – Utilisation de CameraUI (Appareil photo) sous Android, iOS et BlackBerry Tablet OS - Adobe Flex Tutorial - Tutoriaux Flex Builder, MXML, ActionScript, AS3

  14. Hi Christian,
    Thanks for this post, really nice.
    I’ve been trying a bit and it works just great, at least with images.
    I’ve tried with video in both ways (cross platform and not, and none of them work).
    Using the Loader creates an Unsupported filetype error.
    Using just the MediaPromise data and a VideoDisplay component seems to work, but I don’t see nor hear anything.
    When debugging, it seems like the VideoDisplay has been able to decode some of the information of the video, like the duration, resolution and so on, but it doesn’t play it.
    The video shown in the data.file.url is a .MOV, so I believe that it should be able to play it.
    Any hints?
    Thanks!

  15. Pingback: Promotie proDEV – iDraw - Portfolio Arnor D'Haenens

  16. Pingback: What is new in Adobe AIR 2.6 ? « PriyeshSheth (M)+91 909 979 5049

  17. Heiko Voigt says:

    Hi Christian,

    excellent article – thanks for that. One question in addition – I got it working for iOS and Android and am now going to test on the bb playbook (latest OS, Air 2.7, …) should this work on the PlayBook as well ?

    Kind regards, Heiko

  18. Max Stonebraker says:

    Instead of assigning the loader to an image, how can I write it to a file so I can upload it to my server?

  19. Shilpi Vohra says:

    Hi

    Can someone guide me – how to publish a stream with the cameraUI class (using the cameraUI class fro android front camera)?

    Thanks in advance
    Shilpi

  20. Saar says:

    hey Christian

    do you know of the bug using AIR on Android that using the cameraUI creates TWO duplicates of the picture – one automatically stores by the Android OS and another by the AIR app?
    this happens on Samsung Galaxy S and many other models.
    any known solution?

    also, any news on how to determine if a pic was taken in landscape or portrait mode on iOS? retrieving exif info isn’t supported….

    thanks
    Saar

  21. Joe Ward says:

    Max, I just wrote an article on how to upload: http://www.adobe.com/devnet/air/articles/uploading-images-media-promise.html

    Shilpi, I believe it is up to the user which camera to use with CameraUI. The built-in camera app has a switch. You can’t give the system a hint.

    Saar, yes that is a known bug. Also, you can read the exif data on iOS. The problem is that the JFIF format used by the CameraRoll on iOS isn’t supported by the most popular ActionScript exif library. The fix is easy, though. I am thinking of writing another article on that topic next month. If you can’t wait, post a message on the Adobe AIR forum and I will see it.

  22. Pingback: Slides, Links, and Questions From my MAX 2011 Presentation « Christian Cantrell

  23. nona says:

    Hi Christian,
    thnx for this post
    i have problem with ios i cant find the name and the path of image
    can u help me
    i try it for ipad
    thnx

  24. Pingback: Parsing Exif Data From Images on Mobile Devices « Christian Cantrell

  25. Hamid says:

    Hi Nona,
    I was wondering if you fix your issue, I also have the same dificulty to get the creationdate of the image.
    thanks

  26. Greg says:

    Hi,

    Saar referenced this duplicate images bug, I am seeing this also on the Samsung Galaxy Tab. I tried searching the web, Adobe bug dbase… nothing. Do you know the bug number or any other reference to it or a workaround?

    Thanks,

    Greg

  27. Pulkit Gupta says:

    Hi,

    When capturing Image using CameraUI and retrieving it, the pic has the EXIF information with ut and can be read. However, doing a CameraRoll.addBitmapData after loading the promise, doesn’t put the EXIF information in the file added. Any way to get over it?

    Or any other way to identify the image loaded via accessing camera roll so that we can manually store data and use it when the image loads?

    Please help.

    Regards
    Pulkit

    Regards
    Pulkit

  28. Paul says:

    Hi Christian.

    Thanks for this post – REALLY useful ! The camera interface is perfect.

    Is it possible to somehow add a time delay so that when the user clicks the take pic button on the CameraUI there is a delay of say 3 secs before the picture is captured ? If we dont use the cameraUI but build our own camera we can build a timer into the take pic function but do we have any control in the cameraUI ?

    Thanks

    Paul