Building Client / Cloud Apps with Flash Builder for Force.com

I have a theory. The majority of people who use enterprise software today use old school Client / Server apps. We’ve been trying to move these apps to the web for more than ten years. The ease of deployment of web apps is a clear motivator. Yet the client capabilities of the plain old web browser have not been sufficient for many apps to make the leap. This is why I love Flex and the Flash Platform. It provides a way to use web technologies and the web deployment model but adds many of the critical things needed for mission critical apps that people use all day long.

But no one wants to go back to the Client / Server architecture. We want to embrace Cloud Computing architectures but not lose the client capabilities. What we really need is the Client / Cloud architecture. We need a web deployment model that provides ease of deployment but also the ability to install applications on our desktops and mobile devices.

This is why I’m so excited about the new Adobe Flash Builder for Force.com. In a nutshell this is a tool that Adobe and Salesforce.com built together to enable developers to build great software using Flex for the UI and Force.com for the Cloud back-end. It’s a wonderful combination of technologies that will help many Client / Server apps make the switch to Client / Cloud.

Applications created with Flash Builder for Force.com can be run in the browser, on the desktop, and on mobile devices. These applications can be assembled from the hundreds of Flex components that are out there (check out many of them in Tour de Flex).

Check out this video to see how to use Flash Builder for Force.com to build a simple app:

As you can see, it’s very easy to get started. But I wanted to go a step further and try to build something real–something that shows a genuine use case for extending beyond the out-of-the-box Salesforce.com UI. I wanted to keep it really simple so that I could post the code here. What I came up with is this (in user story form):

  • As a Salesforce.com user I want to take a photo, using my phone, of one of my contacts so that the photo can be saved to their contact record for future reference.
  • As a Salesforce.com user I want to see photos I’ve taken of my contacts so that I can be reminded of what they look like.

Simple enough. So here is what I came up with:

To build these two apps I first downloaded and installed Flash Builder for Force.com. I used the Adobe AIR for Android prerelease to build the mobile app. Here is how I created these apps.

First I added a new field to Contact to store the photo. Salesforce.com doesn’t have a binary field so I used a large text field (32k limit). I’ll store the photo Base64 encoded.

Then in Salesforce.com I saved my enterprise.wsdl file. Check out a great video from Dave Carroll to see how to do this.

Now in Flash Builder for Force.com I created a new Force.com Flex Project for the mobile app. If you do this on your own and want to run on a mobile device then you will need to overlay the AIR for Android SDK on top of a Flex 4.1 SDK. Select Desktop Application as the app type. Replace WindowedApplication with just Application. And replace the F3DesktopApplication with F3WebApplication since F3DesktopApplication uses APIs that are not available on AIR for Android. (BTW: Flash Builder, Flex, and Force.com Flex Projects do not officially support mobile deployment yet. It works but there is no support and no guarantees.) If you are building a standard Web Application or Desktop Application then you can just leave the generated code as is.

Using the Data/Services wizard I connected to Salesforce.com using my enterprise.wsdl file. After the services and value objects have been generated I modified the Contact object and added a Bindable account property. The generated application already included the F3DesktopApplication Declaration used to connect to Salesforce. Due to an incompatibility with that API and AIR for Android I switched it to use F3WebApplication. In F3WebApplication’s loginComplete event handler I query Salesforce.com for Accounts and then Contacts, associate contacts with their account, and then store the contacts:

app.wrapper.query("select Id, Name from Account", new AsyncResponder(function(data:ArrayCollection, token:Object):void {
    accounts = data;
    app.wrapper.query("select Id, AccountId, FirstName, LastName, Phone, MobilePhone, Email, Title, Department, MailingCity, photoData__c from Contact", new AsyncResponder(function(data:ArrayCollection, token:Object):void {
        for each (var contact:Contact in data)
        {
            for each (var account:Account in accounts)
            {
                if (account.Id == contact.AccountId)
                {
                    contact.account = account;						
                }
            }
        }
        contacts = data;
    }, handleError));
}, handleError));

Notice in the query that I’m fetching photoData__c, which is the custom field I created on Contact to store the photo.

In the renderer for a contact I need to either display the photo if there is one or let the user add one. Here is the simple UI code to handle that:

<s:Group width="92" height="92" top="8" right="8">
    <s:Rect width="92" height="92">
        <s:fill>
            <s:SolidColor color="#cccccc"/>
        </s:fill>
    </s:Rect>
    <s:Label id="addPhoto" text="Add a photo" width="92" height="92" verticalAlign="middle" textAlign="center"/>
    <s:BitmapImage id="photo" width="92" height="92"/>
</s:Group>

When the contact is set I check to see if there is a photo and if so display it:

if (contact.photoData__c == null)
{
    photo.visible = false;
    return;
}
 
var decoder:Base64Decoder = new Base64Decoder();
decoder.decode(contact.photoData__c);
 
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, function(event:Event):void {
    photo.source = event.target.content;
    photo.visible = true;
});
loader.loadBytes(decoder.toByteArray());

The data from the photoData__c field is Base64 decoded and then displayed using the Flex BitmapImage component.

Now when the user clicks on the photo or empty photo box I use the AIR for Android CameraUI to grab a photo, resize it, covert it to a PNG, Base64 encode it, set it on the contact, and then save the contact to Salesforce.com:

if (CameraUI.isSupported)
{
    cameraUI = new CameraUI();
    cameraUI.addEventListener(MediaEvent.COMPLETE, function(event:MediaEvent):void {
        var loader:Loader = new Loader();
        loader.load(new URLRequest(event.data.file.url));
        loader.contentLoaderInfo.addEventListener(Event.COMPLETE, function(event:Event):void {
            var bitmap:Bitmap = event.target.content as Bitmap;
 
            var result:BitmapData = new BitmapData(46, 46, false);
            var matrix:Matrix = new Matrix();
            matrix.scale(46 / bitmap.width, 46 / bitmap.height);
            result.draw(bitmap, matrix);
 
            var pngEncoder:PNGEncoder = new PNGEncoder();
            var pngBytes:ByteArray = pngEncoder.encode(result);
 
            var base64Encoder:Base64Encoder = new Base64Encoder();
            base64Encoder.encodeBytes(pngBytes);
            var encodedImage:String = base64Encoder.flush();
 
            contact.photoData__c = encodedImage;
 
            displayPhoto();
 
            F3WebApplication.getInstance().wrapper.save(contact, new AsyncResponder(function(data:Object, token:Object=null):void {
            }, FlexGlobals.topLevelApplication.handleError));
        });
    });
    cameraUI.addEventListener(ErrorEvent.ERROR, function(event:ErrorEvent):void {
        FlexGlobals.topLevelApplication.handleError(event);
    });
    cameraUI.launch(MediaType.IMAGE);
}

That’s it for the mobile app! I compiled it, exported it to an Android app, and then copied it to my phone. Pretty simple and as you can see it works! One limitation with my approach is the 32k limit of the photoData__c field. However, I think I could easily get around that by striping the Base64 encoded data across multiple fields. It’s not ideal but it would work.

To display the photo when I view a contact on Salesforce.com I created a very simple Flex app using another Force.com Flex Project. I could have also added photo upload to this application but chose to keep it simple. All it does is display the selected contact’s photo. Here is the complete code (after generating the required services in Flash Builder):

<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
    xmlns:s="library://ns.adobe.com/flex/spark"
    xmlns:mx="library://ns.adobe.com/flex/mx"
    xmlns:flexforforce="http://flexforforce.salesforce.com">
 
    <fx:Script>		
    import mx.rpc.AsyncResponder;
    import mx.utils.Base64Decoder;
    </fx:Script>
 
    <fx:Declarations>
        <flexforforce:F3WebApplication id="app" requiredTypes="Contact">
            <flexforforce:loginComplete>
                app.wrapper.query("select photoData__c from Contact where Id = '" + this.parameters.contactId + "'", new AsyncResponder(function(data:Object, token:Object):void {
                    if (data.length == 1)
                    {
                        if (data[0].photoData__c == null)
                        {
                            photo.visible = false;
                            noPhoto.visible = true;
                            return;
                        }
 
                        var decoder:Base64Decoder = new Base64Decoder();
                        decoder.decode(data[0].photoData__c);
 
                        var loader:Loader = new Loader();
                        loader.contentLoaderInfo.addEventListener(Event.COMPLETE, function(event:Event):void {
                            photo.source = event.target.content;
                            photo.visible = true;
                        });
                        loader.loadBytes(decoder.toByteArray());
                    }
                }, function(fault:Object):void {
                    // ignored
                }));
            </flexforforce:loginComplete>
        </flexforforce:F3WebApplication>
    </fx:Declarations>
 
    <s:applicationComplete>
        app.serverUrl = this.parameters.serverUrl;
        app.loginBySessionId(this.parameters.sessionId);
    </s:applicationComplete>
 
    <s:Rect width="92" height="92">
        <s:fill>
            <s:SolidColor color="#cccccc"/>
        </s:fill>
    </s:Rect>
 
    <s:Label id="noPhoto" text="No Photo" width="92" height="92" textAlign="center" verticalAlign="middle" visible="false"/>
 
    <s:BitmapImage id="photo" width="92" height="92"/>
 
</s:Application>

Finally I created a custom S-Control to run the Flex app:

<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" id="ContactPhoto" width="92" height="92" 
codebase="https://fpdownload.macromedia.com/get/flashplayer/current/swflash.cab"> 
    <param name="movie" value="{!Scontrol.JavaArchive}" /> 
    <param name="flashvars" value="sessionId={!API.Session_ID}&serverUrl={!API.Partner_Server_URL_90}&contactId={!Contact.Id}" /> 
    <embed src="{!Scontrol.JavaArchive}" width="92" height="92" name="ContactPhoto" 
flashvars="sessionId={!API.Session_ID}&serverUrl={!API.Partner_Server_URL_90}&contactId={!Contact.Id}" 
type="application/x-shockwave-flash" 
pluginspage="http://www.adobe.com/go/getflashplayer"> 
    </embed> 
</object>

I uploaded the compiled Flex app to the S-Control and added it to the Contact page. And that’s it! In just a few hours I extended Force.com and built a cool mobile app. I could also have easily created a desktop widget for browsing contacts and adding photos. If you are looking for a fun project to use as a way to learn this stuff that would be a good one! :)

Here are some resources to help you get started with Flash Builder for Force.com:

Have fun building the next generation of software! Let me know how it goes.

This entry was posted in Adobe AIR, Cloud, Flex, Mobile, Salesforce.com. Bookmark the permalink. Post a comment or leave a trackback: Trackback URL.
  • Vitally Tezhe

    Hi James,

    Can you please explain how did you manage to run mxml code under AIR for Android? I was trying to do so for a few times but did not succeed.

    Thanks.

    • http://www.jamesward.com James Ward

      It’s not recommended until Flex Hero. But you can do it today with Flex 4. Just use s:Application in an Flex Desktop (AIR) project. Then use the normal instructions to create the apk file.

  • http://blog.jeffdouglas.com Jeff Douglas

    Kudos James! Nicely done. I expect more Flash apps to pop up shortly due to the fact there is not AXIS support for Android and no REST API for Salesforce.com. This should fit the bill nicely.

  • Jonathan

    Very cool demo James, but if I already have Flash Builder (Mac OSX) installed can I just run the installer for ‘Flash Builder for Force.com’ or will I need to uninstall my current Flash Builder and then install ‘Flash Builder for Force.com’?

    Thank you

  • Dave

    Dude! You rock!

  • Pingback: Bay Area Event: Building RIAs using the Flash Builder for Force.com

  • John

    Great article. I have a quick question related to Salesforce. How would you recommend uploading and resizing a photo in one step. Ideally, the photo exists on PC, chose the file ( a 10MB jpeg ), upload and resize so that the final photo is a 320×240 jpeg.

    Thanks for the article and any suggestion.

    • http://www.jamesward.com James Ward

      On the client-side in Flex you can resize the photo. It must be Base64 encoded to save it into a Salesforce table. Once that is done it can be sent in an update statement. My code above does exactly this.

      • John

        I have finally gotten to the point in my project where this is relevant. I have enjoyed reading your articles in the process. My challenge is this, the custom field I am trying to update is Rich Text Area. I would like to view the picture in the Salesforce UI after the upload. If I just send the Base64 data, that is what I see in the Salesforce UI. Any help would be greatly appreciated.

  • Krishnan

    Hi James,

    Do you know if there is any force.com tool kit optimized for flash builder burrito?

    Krishnan

    • http://www.jamesward.com James Ward

      Not yet. Sorry.

  • Pingback: Flash Builder for Force.com and Adobe AIR for Android

  • Pingback: Flash Builder for Force.com and Adobe AIR for Android

  • Jensen Axel

    James, fellow salesforce, I work real close with MM in chicago, you know if there is any way to get progress back from salesforce on file uploads? were not using the rest api for file uploaded, just the standard soap stuff, is there anything for that? i wouldn’t guess so but figured you would be the guy to ask.

    • http://www.jamesward.com James Ward

      Hi Jensen.  Good question.  I’m not aware of any way to do this.  Sorry.

      -James

      • Axel Jensen

        Thanks for the reply!

        Im axel (first name) btw, sorry for the cloudy email, not sure if you picked up what i was saying about MM ( model metrics ) think you know jason and john pretty well… anyway, i’ve been one of the 2 main devs with doing their 2go platform… dont think we’ve ever formally met… anyway, nice to meet you.Axel



  • View James Ward's profile on LinkedIn