Home >
If you have had an opportunity to look at the Adobe Flash Collaboration Service (AFCS) you could see that there is a huge opportunity to do interesting multi-user applications without needing to write all of the server side code.
However there is the challenge of how do you control who comes into your application and what they are allowed to do. In addition, keeping your application credentials safe in case your SWF file was decompiled.
So as the title suggests you can use a service like Facebook to take care of the users authentication and Flash Remoting for the application authentication.
You will need the Facebook Actionscript API, the AFCS SDK and a web server that is set up for Flash Remoting. In this example the remoting code will be done with ColdFusion but any Language that supports remoting should be fine.
Setup
We are going to break this down into three parts. The first will be the AFCS room, next we will add the Facebook features, finally add the remoting code.
The reason why are are breaking it up like this is because you as the developer need to have the room set up first. Meaning that whatever components that need to be in the room (for example, a roster and webcam) need to be there first. Guest can not add components into room.
If you have not yet created an account head over to cocomo.acrobat.com and sign up. After sign-up click "Download the SDK". The SDK will be contained inside an AIR application. After installation you should have a new application called "AFCS SDK Navigator".
The SDK Navigator contains everything you need to get started. All the documentation for both Flex and Flash. In addition there are video tutorials, SWC and source code files for Flex and Flash, and other developer tools to help you put your AFCS project together.
Create a new project in Flex Builder, this will be an AIR project. Launch the SDK Navigator if you have not all ready and unzip the SDK. After, go to the Libraries section. For our project we will choose the Player 10 SWC from the Flex libraries section. By clicking on the button it should launch a browser window and direct you to the location of the SWC file on your machine. Once you located the file you can then add it to the lib folder created for your project.
You can see here that the SWC file is now referenced in your project by going to: Project > Properties > Library Path. Click on the libs folder and you can see the SWC file.
Now that we have our basic set up we are going to quickly get the room up and running
Create your AFCS room
In your WindowedApplication tag add the reference to your AFCS code.
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml"
width="1024" height="768" layout="absolute" xmlns:rtc="AfcsNameSpace">
Now we can quickly set up our room and test it out. Between the WindowedApplication tags add the AdobeHSAuthenticator tag and the ConnectSessionContainer tag. This is going to handle logging into the room. For this to work you will add a few attributes to the tag.
<rtc:AdobeHSAuthenticator
id="HSAuthenticator" />
<rtc:ConnectSession
id="sessionContainer"
authenticator="{HSAuthenticator}"/>
Then we will create all the components for the room
<mx:ViewStack width="100%" height="100%" id="vStack">
<mx:Canvas>
<mx:HBox height="100%" width="100%">
<mx:VBox width="100%" height="100%" verticalAlign="middle" horizontalAlign="center">
<rtc:Roster id="roster" width="100%" height="100%" showMenuButtons="false" />
<rtc:SimpleChat id="chatPod" width="100%" height="100%"/>
</mx:VBox>
<mx:VBox height="100%" width="100%">
<mx:HTML id="userInfo" width="100%" height="100%"/>
<mx:LinkButton id="profileButton"/>
<rtc:WebCamera width="100%" height="100%"/>
<rtc:FileShare height="100%" width="100%"/>
</mx:VBox>
</mx:HBox>
</mx:Canvas>
</mx:ViewStack>
This will finish your room. We just need some Actionscript to tie everything together and log you into the server.
<mx:Script>
<![CDATA[
private function init():void
{
HSAuthenticator.userName = "acrobat.com email";
HSAuthenticator.password = "acrobat.com password";
sessionContainer.roomURL = "http://connectnow.acrobat.com/userName/roomName";
sessionContainer.login();
}
]]>
</mx:Script>
Make sure to add this function call to the "creationComplete" event inside the WindowedApplication tag. Then compile the project.
This is an important step because as the owner of the room you are the only one that can place components or pods in the room. So you do need to make sure that its set up. All the Facebooks users will be logged in as guests without the power to make any adjustments to the room.
In the code you see that the room components are inside a ViewStack component. After we add some of the Facebook funcitons we will add one more canvas to our viewstack to that people can get into the room.
Add the Facebook API
Now that your room is set up we can add the Facebook functions.
A good reference for getting started with Flash and Facebook is Create your first Facebook application with Flex on the Adobe Developer Connection. Otherwise you can download the Facebook AS3 API SWC file add that to your lib folder.
There are a few Facebook and AFCS classes in order to get this to work. Here is some of the code
<mx:Script>
<![CDATA[
import com.facebook.Facebook;
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 com.facebook.commands.users.GetInfo;
import com.facebook.utils.FacebookSessionUtil;
import com.adobe.rtc.events.SessionEvent;
import com.adobe.rtc.events.AuthenticationEvent;
import com.adobe.rtc.messaging.UserRoles;
import com.adobe.rtc.sharedManagers.descriptors.UserDescriptor;
import mx.events.ListEvent;
import mx.events.MenuEvent;
private var _fbookObj:Facebook;
private var _session:FacebookSessionUtil;
private var _fbookUsersObj:FacebookUser;
private var _userId:String;
In the above code some of the classes we import gives us access to Facebook user information, the ability to get information about our user, and any Facebook events. In addition we import AFCS classes giving us access to session and authentication events in addition to the ability assign roles to a user.
Finlay we create some variables to hold on to information like the Facebook session and the user id that we will use when we log into the service.
In our next block of code brings us back to the init function. Are are going to take ConnectSessionContainer and add an event listener to it. This way we will know when the session is established and synchronized with the application.
<mx:Script>
<![CDATA[
private function init():void
{
HSAuthenticator.userName = "acrobat.com email";
HSAuthenticator.password = "acrobat.com password";
sessionContainer.roomURL = "http://connectnow.acrobat.com/userName/roomName";
sessionContainer.addEventListener(SessionEvent.SYNCHRONIZATION_CHANGE, synchUp);
sessionContainer.login();
}
]]>
</mx:Script>
When it is, it will call a function called "syncUp". Using the registerCustomUserField method we can gather all the results that come back from Facebook and save them as part of our application.
In our next code block we will create syncUp and first check to see if custom fields were added. If not add them to our room. Only room owners can add fields. However publishers and update them, so when Facebooks users start to enter the room it will be their information that will update the fields we are about to create.
The registerCustomUserField method is part of the Usermanager class. We get access to it from the ConnectSession tag that was added earlier. That tag gives you access to not only user information but Room, Stream and File information as well.
private function syncUp (event:SessionEvent):void
{
userId = sessionContainer.userManager.myUserID;
if(!sessionContainer.userManager.isCustomFieldDefined("UserName"))
{
sessionContainer.userManager.registerCustomUserField("UserName");
sessionContainer.userManager.registerCustomUserField("Location");
sessionContainer.userManager.registerCustomUserField("Networks");
sessionContainer.userManager.registerCustomUserField("Birthday");
sessionContainer.userManager.registerCustomUserField("Avatar");
sessionContainer.userManager.registerCustomUserField("ProfileURL");
sessionContainer.userManager.registerCustomUserField("Status");
sessionContainer.userManager.registerCustomUserField("StatusTime");
}else
{
trace("custom fields defined");
}
What we will do next is add a button to our application. This will let users launch a browser and login to Facebook. Once logged in they will be able to use the AIR application and give you access to the information you want to display in the application.
Lets revisit the MXML code and add as new canvas tag to the ViewStack. Add this code above the current canvas.
<mx:Canvas>
<mx:VBox width="100%" height="100%"
verticalAlign="middle" horizontalAlign="center">
<mx:Button id="loginButton"
label="Use your Facebook account to enter"/>
</mx:VBox>
</mx:Canvas>
We next need to add a few new variables. This will hold information from your Facebook developer account and help keep track of if the login window was launched.
private var isWindowLaunched:Boolean = false;
private var API_KEY:String;
private var SecretKey:String;
Next we will add an event listener that will launch a browser window and let users login. In addition we will add the API key and Secret key from Facebook.
<mx:Script>
<![CDATA[
private function init():void
{
HSAuthenticator.userName = "acrobat.com email";
HSAuthenticator.password = "acrobat.com password";
sessionContainer.roomURL = "http://connectnow.acrobat.com/userName/roomName";
sessionContainer.addEventListener(SessionEvent.SYNCHRONIZATION_CHANGE, synchUp);
sessionContainer.login();
//add this eventListener
loginButton.addEventListener(MouseEvent.CLICK, launchLoginWindow);
API_KEY = "API KEY";
SecretKey = "SERETKEY";
}
]]>
</mx:Script>
This next function will start to use part of the Facebook API
private function launchLoginWindow(evt:MouseEvent):void
{
if(isWindowLaunched != true){
_fbookObj = new Facebook();
_session = new FacebookSessionUtil(API_KEY, SecretKey,this.loaderInfo);
_fbookObj = _session.facebook;
_fbookObj.login(false);
evt.target.label = "Click again to enter the site";
isWindowLaunched = true;
}else{
_session.validateLogin();
_session.addEventListener(FacebookEvent.CONNECT,getFBData);
vStack.selectedIndex = 1;
}
}
This code creates a Facebook session by passing over information gathered from your Facebook developer account. Once the session has been created it will launch a browser window so that users can login. You don't need to store passwords or any user information. Next the button label changes to inform the user that they need to click again to enter into the application.
The second time the button is clicked is when the users information gets added to thhe AFCS application by calling the getFBdata function,.
The next block of code will make a call to the server and retrieve data about our user.
private function getFBData(evt:FacebookEvent):void
{
//trace(evt.success);
var _fbCall:FacebookCall = _fbookObj.post(new GetInfo([_fbookObj.uid],[GetInfoFieldValues.ALL_VALUES]));
_fbCall.addEventListener(FacebookEvent.COMPLETE,onComplete);
}
Now that we made our server call using the post method. We can add that information to the application using the onComplete function. Here is were we get to use the custom fields that were created before.
public function onComplete(event:FacebookEvent):void
{
_fbookUsersObj = (event.data as GetInfoData).userCollection.getItemAt(0) as FacebookUser;
sessionContainer.userManager.setUserRole(userId,UserRoles.PUBLISHER);
var userName:String = _fbookUsersObj.first_name + " " + _fbookUsersObj.last_name;
sessionContainer.userManager.setUserDisplayName(userId,userName);
sessionContainer.userManager.setUserUsericonURL(userId,_fbookUsersObj.pic_small);
sessionContainer.userManager.setCustomUserField(userId,"Name",userName);
sessionContainer.userManager.setCustomUserField(userId,"Location",_fbookUsersObj.current_location.city);
sessionContainer.userManager.setCustomUserField(userId,"Networks",_fbookUsersObj.networkAffiliations);
sessionContainer.userManager.setCustomUserField(userId,"Birthday",_fbookUsersObj.birthday);
sessionContainer.userManager.setCustomUserField(userId,"Avatar",_fbookUsersObj.pic_small);
sessionContainer.userManager.setCustomUserField(userId,"ProfileURL",_fbookUsersObj.profile_url);
sessionContainer.userManager.setCustomUserField(userId,"Status",_fbookUsersObj.status.message);
sessionContainer.userManager.setCustomUserField(userId,"StatusTime",_fbookUsersObj.status.time.getMonth() +"/"+ _fbookUsersObj.status.time.getDay()+"/"+ _fbookUsersObj.status.time.getFullYear());
roster.addEventListener(MenuEvent.ITEM_CLICK, handleItemClick);
trace(_fbookUsersObj.current_location.city);
trace(_fbookUsersObj.networkAffiliations);
trace(_fbookUsersObj.birthday);
trace(_fbookUsersObj.status.message);
trace(_fbookUsersObj.profile_url);
}
You can see in the code above that the roster component has an event listener. The goal here is to be able to click on people in the room and see information from their profile. The event listened for is similar to clicking on an item from the data grid.
Below we have to code that will handle the click on the roster. We take the data available and start to use the UserDescriptor class that we referred to before. That class has all the data from the custom fields that were created.
private function handleItemClick(evt:ListEvent):void
{
var userName:String = (evt.itemRenderer.data as UserDescriptor).displayName;
trace("userInfo = " + userName);
trace("Birthday = " + (evt.itemRenderer.data as UserDescriptor).customFields.Birthday);
var birthDay:String = (evt.itemRenderer.data as UserDescriptor).customFields.Birthday;
var avatarURL:String = (evt.itemRenderer.data as UserDescriptor).customFields.Avatar;
var ProfileURL:String = (evt.itemRenderer.data as UserDescriptor).customFields.ProfileURL;
var status:String = (evt.itemRenderer.data as UserDescriptor).customFields.Status;
var statusTime:String = (evt.itemRenderer.data as UserDescriptor).customFields.StatusTime;
userInfo.htmlText = "Icon: <img src='"+avatarURL+"'>" + "<br/> Name: " + userName + "<br/> Birthday: " +birthDay + "<br/> Status: " + status + "<br/> Status Time: " + statusTime;
profileButton.label = "View " + userName + "'s profile";
profileButton.addEventListener(MouseEvent.CLICK, function():void
{makeWindow(ProfileURL)});
}
Once clicked on we create a series of local variables, then apply our new data to an HTML component called "userInfo".
Under the HTML component there is a button that will bring you to that users profile page on Facebook. Next we will add the function for that:
private function makeWindow(theURL:String):void
{
trace("make popup");
trace("theURL = " + theURL);
popUpWindow = new PopUp();
popUpWindow.open(true);
popUpWindow.theURL = theURL;
}
Our latest function creates a popup window and has the variable "theURL" passed over to it. That variable was created from gathering the user information in the previous function.
If you are using Flex Builder, you should see a few warning icons on the left side of the screen. The reason for this is that there is no built in definition for PopUp. We will fix this by creating a Flex component that will handle this for us.
In order to get this to work we need to create a separate file. In Flex Builder go over to File > New >MXML Component . This new component will be called PopUp and its base class will not be Canvas, in this instance it will be Window.
This will be a simple MXML file that will have an HTML component, and a function that will get the URL passed over to it and assign it to the HTML component.
<?xml version="1.0" encoding="utf-8"?>
<mx:Window xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" width="800" height="600">
<mx:Script>
<![CDATA[
private var profileURL:String;
public function set theURL(userURL:String):void
{
this.profileURL = userURL;
trace("profileURL = " + profileURL);
htmlComponent.location = this.profileURL.toString();
}
]]>
</mx:Script>
<mx:HTML id="htmlComponent" width="100%" height="100%"/>
</mx:Window>
Here you can see that there is a setter function that is being used by the previous code block. By receiving a URL the function will then assign a location to the HTML component.
Now that you have all the code set up go back to the main MXML file and add both an import statement and a variable so Flex can find this new component.
import PopUp;
private var popUpWindow:PopUp;
That should make the warning marks go away. Now everything should be working.
If you run the application, you can click on the button and launch the browser window. Use your Facebook credentials to login, when finished you can go back to the application and enter the room.
You should see your self in the roster on the top left side. Click on your name and the right side should be filled with your user information from Facebook. Finally if you click the link from the right side, the application will open a new window and bring you to your profile page.
At this moment all if the user information is embedded in the file. What we will do next is separate this and put the login information on the server. The AIR application will then make a call to the server using the RemoteObject tag and get the information at runtime.
Set up your CFC
For this example we will set up a ColdFusion component that will hold both the Facebook and AFCS information.
In any text editor you can create a CFC file. This one will be called "AFCSConnect.cfc". I'm placing this file inside a CFC folder on my ColdFusion server. Inside the CFC file we will create a CFFunction called "facebookID" and set the access type as "remote" and the returnType as "array".
<cfcomponent>
<cffunction name="facebookID" access="remote" returntype="array">
<cfset username = "AFCS Email Address">
<cfset password = "AFCS password">
<cfset accounturl="Your account URL">
<cfset apiKey = "Facebook API Key">
<cfset secretKey = "Facebook Secret Key">
<cfset facebookArray = ArrayNew(1)>
<cfset facebookArray[1] = username>
<cfset facebookArray[2] = password>
<cfset facebookArray[3] = accounturl>
<cfset facebookArray[4] = apiKey>
<cfset facebookArray[5] = secretKey>
<cfreturn facebookArray>
</cffunction>
</cfcomponent>
With this component created, you now have the ability to separate the all of your login information form the application and only request it when needed.
Now the AIR application needs to be updated to call this file and retrieve the information.
The first thing we will add a set of RemoteObject tags and point it to the ColdFusion server.
<mx:RemoteObject destination="ColdFusion" id="AFCS_AUTH" endpoint="http://localhost/flex2gateway/" source="cfc.AFCSConnect">
<mx:method name="facebookID"/>
</mx:RemoteObject>
In the above code the RemoteObject is pointing to my local ColdFusion server and the source is the directory on the server my CFC lives in. Inside the RemoteObject tag lives the Method tag that refers to the function inside the CFC that was made before.
The next step is to update our Init function so that when the application is launched it will make a call to the server and gather all the information needed. Once the information has been collected we will call a new function named "getFacebookKey", the application will then be ready to make any connections to either FaceBook or the AFCS service.
private function init():void
{
AFCS_AUTH.facebookID();
AFCS_AUTH.addEventListener(ResultEvent.RESULT, getFacebookKey);
loginButton.addEventListener(MouseEvent.CLICK, launchLoginWindow);
}
private function getFacebookKey(evt:ResultEvent):void
{
HSAuthenticator.userName = evt.token.result[0];
HSAuthenticator.password = evt.token.result[1];
sessionContainer.roomURL = evt.token.result[2];
API_KEY = evt.token.result[3];
SecretKey = evt.token.result[4];
sessionContainer.addEventListener(SessionEvent.SYNCHRONIZATION_CHANGE,synchUp);
sessionContainer.login();
}
With this new code, we need to add one more import statement. Import the ResultEvent package:
import mx.rpc.events.ResultEvent;
When the project gets tested it now will call your remoting server, gather all the information needed to login to both the AFCS and FaceBook. All of the functionality should be the same as before.
As noted before the remoting can be done with any server side language that supports remoting.
You now have an application that can pull information from Facebook and share it with everyone else in the room, in addition to being able to share files and video using the webcam component.
For more information about the Flash Collaboration Service go over to Adobe Labs or check out the AFCS Forums.
For information on Facebook integration with Flash take a look at the Adobe Developer Connection
Here is the Flex 3 project.




Facebook Application Development
Great article Russ, more articles on AFCS are most welcome. Cheers
@rob thanks.
I have a few ideas in the works.
The new social API that was just released on labs, should make this a lot easier to do.
Thanks for the input.
...russ
Interesting article!
Do you perhaps have any idea about what adobe is going to charge for using AFCS? It's free now but I heard they are planning to charge for it in the near future.
@Jochen you can see how pricing works on the official blog for what is now LiveCycle Collaboration Service.
http://blogs.adobe.com/collabmethods/