Desktop and Browser Facebook Apps with AIR and Flex
Last week I was presenting at AUG Poznań and today remotely via Adobe Connect at AUG Trójmiasto, where I showed how to build applications usign AS3 API for Facebook that is available at Google Code. My goal was not only to show how to use Facebook API but also how you can build desktop and browser versions of the same app using conditional compilation in Flex. I took the approach of two Flash Builder projects one with minimum set of Flex (browser) code and AIR (desktop) project with common sources for both. Flex project actually links to AIR project src-common folder in Flash Builder. The structure of both projects looks like this:

Below you can also find example of MainView.mxml code that is common for both projects. Within that example you can see sections that will be compiled based on specified options for each project. I actually defined two compiler options CONFIG::AIR and CONFIG::FLEX. You can find more info about defining compiler options and conditional compilation here. Another very good approach especially in more complex cases is described here on Adobe Developer Connection.
Here is the link to my Demo of AS3 API on Facebook and also below is the badge with desktop version.
You can look at the source code of each example by right-clicking and choosing View Source option. Also you can download Flash Builder project archives from here and here, one with Flex and the other with AIR code.
<?xml version="1.0" encoding="utf-8"?> <s:Group xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:mx="library://ns.adobe.com/flex/halo" width="100%" height="100%" currentState="CONNECTING"> <fx:Script> <![CDATA[ import com.facebook.Facebook; import com.facebook.commands.batch.BatchRun; import com.facebook.commands.friends.GetFriends; import com.facebook.commands.users.GetInfo; import com.facebook.data.batch.BatchCollection; import com.facebook.data.batch.BatchResult; import com.facebook.data.friends.GetFriendsData; import com.facebook.data.users.FacebookUser; import com.facebook.data.users.GetInfoData; import com.facebook.data.users.GetInfoFieldValues; import com.facebook.events.FacebookEvent; import com.facebook.net.FacebookCall; import flash.net.URLRequest; import flash.net.navigateToURL; import mx.collections.ArrayCollection; import mx.controls.Alert; CONFIG::AIR { // DesktopSessionHelper import required for AIR and Facebook Connect import com.facebook.utils.DesktopSessionHelper; import com.facebook.session.DesktopSession; // Session variable when running as AIR app protected var session:DesktopSessionHelper; } CONFIG::FLEX { // FacebookSessionUtil import required for Flex (browser) app import com.facebook.utils.FacebookSessionUtil; // Session variable when running as Flex (browser) app protected var session:FacebookSessionUtil; } /** * Facebook class used to access FB remote API's */ protected var fbook:Facebook; /** * Logged-in FB user */ [Bindable] protected var user:FacebookUser; /** * Collection of logged-in user friends */ [Bindable] protected var userFriends:ArrayCollection; /** * AIR init function */ CONFIG::AIR public function init():void { // Creating session based on API key session = new DesktopSessionHelper("795c0879607643aa3c5a363d09ce5384"); // Registering handler when connected session.addEventListener(FacebookEvent.CONNECT, onConnect); } /** * Flex init function */ CONFIG::FLEX public function init():void { // When running in iFrame API key and secret values are not necessary // these are passed with flashVars from GET parameters session = new FacebookSessionUtil(null, null, loaderInfo); // Registering handler when connected session.addEventListener(FacebookEvent.CONNECT, onConnect); // Setting fbook from session properties fbook = session.facebook; // Checking if fb_sig_session_key was set from IFrame GET params if(loaderInfo.parameters.fb_sig_session_key) { // Verifying FB session session.verifySession(); } else { // This application cannot run as external FB app Alert.show("You cannot run this application outside Facebook!"); } } protected function onConnect(event:FacebookEvent):void { var uid:String; // Checking if connection was successful if (event.success) { // Conditional block that sets fbook variable after connection CONFIG::AIR { // Creating instance of Facebook class fbook = new Facebook(); // Starting new FB session with apiKey and session secret // received after connection in session variable fbook.startSession(new DesktopSession( session.apiKey, session.sessionData.secret, session.sessionData.session_key)); uid = session.sessionData.uid; } CONFIG::FLEX { uid = fbook.uid; } // Creating batch to make two data request at one FB call var batchRun:BatchRun; var batch:BatchCollection = new BatchCollection(); // Batch item GetInfo returning info about current user batch.addItem(new GetInfo([uid], [GetInfoFieldValues.ALL_VALUES])); // Batch item GetFriends returning friends list of current user batch.addItem(new GetFriends(null, uid)); // Posting batch to FB batchRun = fbook.post(new BatchRun(batch)) as BatchRun; // Registering batch run results handler batchRun.addEventListener(FacebookEvent.COMPLETE, onBatchRunResult); } else { // In case of not successful connection Alert.show(event.error.errorMsg); } } /** * Handler for batch run results */ protected function onBatchRunResult(event:FacebookEvent):void { // Setting results variable from event object var batchResult:BatchResult = event.data as BatchResult; // Getting data from first batch result item var userInfo:GetInfoData = batchResult.results[0] as GetInfoData; // Setting current user object user = userInfo.userCollection.source[0] as FacebookUser; // Getting data from second batch result item var friendsInfo:GetFriendsData = batchResult.results[1] as GetFriendsData; // Building array of returned friends ID's var friendsUids:Array = new Array(); for each(var friend:FacebookUser in friendsInfo.friends.source) { friendsUids.push(friend.uid); } // Doing another call to FB to get friends detailed info var call:FacebookCall = fbook.post(new GetInfo(friendsUids, [GetInfoFieldValues.ALL_VALUES])); // Registering handler call.addEventListener(FacebookEvent.COMPLETE, onGetFriendsInfo); // Changing state to connected currentState = "CONNECTED"; } /** * Friends details request handler */ protected function onGetFriendsInfo(event:FacebookEvent):void { userFriends = new ArrayCollection((event.data as GetInfoData) .userCollection.source); } ]]> </fx:Script> <s:states> <s:State name="CONNECTING"/> <s:State name="CONNECTED" /> </s:states> <mx:ProgressBar includeIn="CONNECTING" label="Connecting..." indeterminate="true" labelPlacement="center" horizontalCenter="0" verticalCenter="0"/> <s:Label text="Hello {user.first_name}!" horizontalCenter="0" verticalCenter="-100" fontSize="29" includeIn="CONNECTED"/> <mx:AdvancedDataGrid id="adgFriends" dataProvider="{userFriends}" designViewDataType="flat" horizontalCenter="0" verticalCenter="19" includeIn="CONNECTED"> <mx:columns> <mx:AdvancedDataGridColumn headerText="Name" dataField="first_name"/> <mx:AdvancedDataGridColumn headerText="Last Name" dataField="last_name"/> </mx:columns> </mx:AdvancedDataGrid> <mx:LinkButton label="Get AIR (desktop) version..." horizontalCenter="0" verticalCenter="150" color="#ABA5A5" fontWeight="bold" textDecoration="underline" fontSize="14" click="navigateToURL(new URLRequest('http://www.riaspace.net/examples/fb-as3demo/air/'))"/> </s:Group>

Hi,
This is really good tutorial. Im starting to use flash builder 4, to create a desktop application and I was searching for something like this. Big thanks.
Also I started to think, that your desktop app dont work, but it just was waiting for long time to get data back from facebook.
Kristaps
Kristaps
30 Mar 10 at 3:42 pm
It’s great and it’s working
Thank you very much for sharing code
DesktopSessionHelper(“795c0879607643aa3c5a363d09ce5384″);
Where this code from?
LOLFlash
19 Apr 10 at 3:29 am
This key you get from Facebook when you create your application there.
p.
Piotr Walczyszyn
19 Apr 10 at 9:19 am