Archive for the ‘Examples’ Category
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>
My approach to MVP pattern with Swiz Framework
Recently I noticed that MVP (Model View Presenter) pattern especially using Swiz Framework is becoming very popular. That is why I decided to port one of my old examples to checkout this approach. It is a simple Flex based notes editor, really really trivial one. As an inspiration and some guides I used one of Ben Clinkinbeard blog posts and also Soenke Rohde blog post. With my approach I introduce assumption that all/most PresentationModel classes extend AbstractPresentationModel class that also extends AbstractController from Swiz package. My abstract class adds dispatcher property that returns reference to CentralDispatcher (I guess this could be also a nice addition to Swiz itself). The assumption here is that communication between different PresentationModel classes is done only through events. Of course PresentationModel has direct access to views and model as with standard MVP, additionally I threat service delegates also as part of model. I guess this could be also called MVPS pattern
Working application is here and application source code here.
I’m waiting for your comments, especially about approach to currentState switching in ApplicationPresentationModel.as and assumptions like event based communication between PresentationModel classes.
Here is just an overview diagram of the architecture, it doesn’t represent all dependencies between application components.

Flex Doc Team blog!
Today colleague of mine pointed me to very interesting resource on Adobe Blogs – http://blogs.adobe.com/flexdoc/. Actually this is an Adobe Flex Documentation Team blog where we can find updates, useful information and links to our documentation. Defenetly I will subscribe to it as Gumbo will bring us a lot of new features to study!
I just found there interesting documentation about Spark Containers http://blogs.adobe.com/flexdoc/pdf/sparkContainersAndRenderers.pdf
Adobe AIR in government institutions (e-Deklaracje Desktop)
At the beginning of April (09.04.2009) Polish Ministry of Finance released their first Adobe AIR based application e-Deklaracje Desktop. This application lets its users submit annual tax declarations electronically and monitor their status. In Polish tax legislation every citizen is obliged to settle his income for previous year with tax office by the end of April. Historically e-Deklaracje project was initiated by Ministry of Finance in 2007/2008 but with less success and wide range adoption due to electronic signature requirement. By that time it required special hardware readers for digital signatures that are not commonly adopted in Poland.
This year Ministry of Finance has prepared change in legislation that was later signed by President of Republic of Poland that allowed sending annual declarations without qualified digital signature. Still to ensure proper security level users had to provide their personal information like: first name, last name, date of birth, NIP – tax identification number, PESEL – personal identification number and declared income from previous year. In reality this set of information is more than it was required in traditional paper based declarations (that’s the case with income from last year). I guess all this information gives better identity verification than traditional way where anyone can send his declaration by post or bring it in person to tax office (where no one asks for any id).
After only three weeks of availability over 77000 citizens have sent their declarations electronically (UPDATE 18.05: latest information from MF website states that 89000 declarations were sent, I guess those that forgot to do it till the end of April are still submitting)!!! This is incredible result taking into consideration such a short time, I believe next year we can expect this number to multiply couple times when people will have it available since January.
I’m also proud to say that local Adobe team (Tadeusz Chełkowski, Tomasz Lichota, Bartek Soin and of course myself) supported this project from very beginning with our technical and RIA experties.
Why Adobe AIR?
Ministry of Finance had couple of major requirements that had to be met by that type of application:
- Cross-platform support – solution had to work without any compromises on all major operating systems like: Windows, Mac OS X and Linux.
- Usability – it had to be easy to install and natural to use for inexperienced users. With badge installer on MF website it just couldn’t be made easier.
- Security – give the users confidence that application they are installing was really issued by Ministry of Finance.
- Interoperability – integration with SOAP based backend services.
- PDF forms support – already existing PDF forms developed in previous year could be reused with small adjustments supporting non-qualified signature.
- Desktop integration – required desktop features:
- Reliable local storage for drafts and sent declarations offline persistence;
- PDF forms templates and documentation local caching;
- Notifications mechanism for asynchronous confirmations (declarations receiving and confirmations service works in asynchronous mode with response time up to 24 hours).
As you can see all of above make Adobe AIR perfect fit for that type of applications. In my opinion the most important features in case of any application issued by public sector institutions are: cross-platform support, usability and security.
We had some stories in Poland in the past of applications written only for Windows platform with closed protocol specifications that ended with Linux users taking legal actions against publishing institutions. Adobe AIR built-in cross-platform support resolves this issue, I actually observed very positive feedback especially on Linux forums after e-Deklaracje release. Some comments stated that this is first time Polish government institution has noticed that there are also other OS’s than Windows.
In terms of usability there are two important factors, first of all installation process to make it as smooth as possible, ideally with small footprint, dependent runtime, tools and libraries automatic detection and installation (badge installer was resolving most of these, except Adobe Reader installation). Another factor is availability of experienced UI designers and developers. This is Adobe’s strong field with great community of Flash and UI design experts.
From the security perspective for application that gathers and sends out user personal information is important to give users confidence that the application was distributed by trusted entity and any communication with backed services is done through secure encrypted channels. Application issuer verification is Adobe AIR built-in feature with signed install packages.
You can check it out yourself on MF website: http://www.e-deklaracje.gov.pl/index.php?page=do_pobrania
This is how the application looks:
e-Deklaracje Desktop main window
Declaration fill window
History window
Flex on Google Java App Engine
Yesterday I was presenting at GeeCON (Kraków/Poland) conference where I showed how you can build Flex apps that run and connect to Google Java App Engine. With my first example I did a simple servlet based RESTful service that was returning XML document to my HTTPService on Flex side.
At the end I demonstrated one of my examples that I previously wrote for Zend_Amf but this time I ported it to slightly modified version of BlazeDS that works with GAE. I used instructions from Martin Zoldano blog http://martinzoldano.blogspot.com/2009/04/appengine-adobe-blazeds-fix.html.
You can give it a try, the app is hosted here: http://flexnotes.appspot.com/
Google App Engine is really immazing technology, hopefully it will be able to run BlazeDS without hacking soon
I know GraniteDS and WebORB with their latest builds are already supporting it.
Augmented Reality examples
On couple of my recent events I presented augmented reality examples. Serge Jespers collected some of those and posted it on his blog: http://www.webkitchen.be/2009/04/29/the-power-of-the-flash-platform-part-2-augmented-reality/
Flex with full Zend Framework on Adobe Developer Connection (part 2)
It was actually published last week but I just found some time to write about it on my blog. Its a part 2 of my ADC series about Zend Framework for Flex developers:
Recording is also available directly on Adobe TV website and iTunes.
Flex with full Zend Framework on Adobe Developer Connection
It was just published on ADC, it’s a first recording of two part series. You can find more details on one of my previous blog posts: Zend_Amf with full Zend Framework
Recording is also available directly on Adobe TV website and iTunes.
Zend_Amf with full Zend Framework
There are many examples on the web how to use Zend_Amf as a standalone component but couldn’t find one that actually shows how you can run it with the rest of the Zend Framework. Main benefit of running it in a way I will demonstrate in this post is that requests to AMF service classes are automatically bootstrapped with configuration, database initialization and other Zend components.
Here is how I use Zend_Amf with the full framework. First we have to setup whole environment as it is in ZendFrameworkQuickstart (there is also already preconfigured archive available there).
flinks – new Flex deep linking library
I needed very simple logic to do deep linking based on currentState value. In order not to repeat same logic in couple of my small projects I created flinks library which I just uploaded to google code. Anyone interested in giving it a test drive please let me know how it runs
Believe me it is very very simple, the only thing you actually need to do is include this single line of code:
1 | <riaspace:EnableDeepLinking autoDeepLinkStates="true" /> |
to enable it and to apply it to all your states. You will find other examples on project google code site.
p.




