Facebook Connect ActionScript 3 ImageViewer Example

I finally had the time to write something about the facebook-actionscript-api we used in one of our last projects. It’s a very interesting API when you want to add Facebook support (user management) to your site/project. There are different things you can do with this API: i.e. access user information, post on the user’s wall, get user’s photos and much much more.

For the litte demo application I decided to use the feature to access the user’s photos to create an ImageViewer in pure ActionScript. It’s just a small example of what you can do with the facebook-actionscript-api but I think it’s a good starting point for someone who hadn’t had the chance to take a look at this whole Facebook Connect stuff.

Facebook introduced a new API some weeks ago – the Graph API – but the facebook-actionscript-api is still based on the “Old REST API”. You can find a in-depth documentation of the old API here: http://developers.facebook.com/docs/reference/rest/

Here are the methods we called to get all the info we needed for the ImageViewer demo:

  • users.getInfo
    Returns a wide array of user-specific information for each user identifier passed, limited by the view of the current user.
  • photos.get
    Returns all visible photos according to the filters specified.
  • photos.getAlbums
    Returns metadata about all of the photo albums uploaded by the specified user.

But you don’t have to worry about the exact name or URL of the methods because the facebook-actionscript-api provides Call-classes for every method there is (i.e. GetAlbums.as).

Before you can send out any calls you have to get a Facebook session and of course log into your Facebook account. Session and login are handled via Facebook’s own JavaScript library (http://static.ak.facebook.com/js/api_lib/v0.4/FeatureLoader.js.php).
Here’s the JS part in our index.html:

// ...
<script type="text/javascript">

    function fbLogin(api_key)
    {
        FB.init(api_key, 'xd_receiver.htm', {"ifUserConnected":permissions});

        FB.ensureInit(function()
        {
            FB.Connect.get_status().waitUntilReady(function(status)
            {
                switch (status)
                {
                    case FB.ConnectState.connected:
                        loggedIn = true;
                        break;

                    case FB.ConnectState.appNotAuthorized:
                    case FB.ConnectState.userNotLoggedIn:
                        FB.Connect.requireSession();
                        loggedIn = false;
                        break;
                }
            });
        });
    }

    function permissions()
    {
        FB.Connect.showPermissionDialog('user_photos', onLoginHandler);
    }

    function onLoginHandler()
    {
        var session = FB.Facebook.apiClient.get_session();
        flashcontent.onLogin(session);
    }

</script>
// ...

We use the ExternalInterface to call the fbLogin() function from our ActionScript class passing the API_KEY as a parameter.

To get your own API key to meddle with, you have to have a Facebook account
and install the Developers application here: 
http://www.facebook.com/developers/
You can create your own app after you've installed the developer stuff.
// ...
ExternalInterface.call("fbLogin", FacebookConnectTest.API_KEY);
// ...

Here is where the “Facebook magic” happens¬†… the fbLogin() function connects to the Facebook page and checks the login status of the user. It either logs you in straightaway or displays the “connect screen” in an iFrame.

After confirming the connection the login form pops up in a new window.

After logging in, the user has to allow the application to access the information it needs (see permissions() function). Because we just want to display the user’s photos, we only need to get the “user_photos” permission.
First allow access to the general user info.

And then allow us to grab your photos. This again happens in an iFrame overlay in the same window our app is running.

After settings all relevant permissions the onLoginHandler() JS-function is called. This function collects the creates session data and passes it to our flash-application (using an ExternalInterface-Callback).

// ...

ExternalInterface.addCallback("onLogin", onLogin);

// ...

/**
 * JS callback - called when user logged into facebook account.
 */
private function onLogin(session:Object):void
{
    if(session == null)
    {
        return;
    }

    _session = session;

    // save session data in shared object for later use ...
    var my_so:SharedObject = SharedObject.getLocal(FacebookConnectTest.SO_NAME);
    my_so.data.session = session;

    // start a WebSession with the session secret and key passed in from Javascript
    var webSession:WebSession = new WebSession(FacebookConnectTest.API_KEY, session.secret, session.session_key);
    _facebook.startSession(webSession);

    webSession.addEventListener(FacebookEvent.CONNECT, onSessionConnect);
    webSession.addEventListener(FacebookEvent.ERROR, onSessionError);
    webSession.verifySession();
}

We just take the supplied data and create a WebSession object and afterwards verify the session.
In addition we are saving the session in a shared object so we can access it at a later time when the user returns to our application – if the session is still valid, we log the user in.

If the sessions is valid, the onSessionConnect() handler is called and we submit the first API call to retrieve the user’s first- and lastname.

// ...
var call:FacebookCall = _facebook.post(new GetInfo([_session.uid], ['first_name', 'last_name']));
call.addEventListener(FacebookEvent.COMPLETE, handleGetInfoResponse);
// ...

The facebook-actionscript-api handles the results automatically and converts the returned XML into value objects we can use within our result handler:

// ...
var infoData:GetInfoData = event.data as GetInfoData;
if(infoData != null)
{
    if(infoData.userCollection == null || infoData.userCollection.getItemAt(0) == null)
    {
        return;
    }

    var firstName:String = infoData.userCollection.getItemAt(0).first_name;
    var lastName:String = infoData.userCollection.getItemAt(0).last_name;

    _loginTxt.htmlText = "Hello " + firstName + " " + lastName + "! <a href='event:logout'>Logout</a>";

    // ...
}
// ...

Because the API is meant to be used with Flex we have to get used to the extra level of “collections” that are added to the data (i.e. infoData.userCollection). But we can access the ArrayCollection kinda like a normal Array – just use getItemAt(index:int) instead of the [].

Now we want to get the user’s photo albums – so create another call and submit it:

// get albums
var call:FacebookCall = _facebook.post(new GetAlbums(_session.uid));
call.addEventListener(FacebookEvent.COMPLETE, handleGetAlbumsResponse);
// ...

The result handler should look familiar:

// ...
private function handleGetAlbumsResponse(event:FacebookEvent):void
{
    var albumsResponseData:GetAlbumsData = event.data as GetAlbumsData;
    if(albumsResponseData != null)
    {
        var tempCovers:Array = [];

        for(var i:int = 0; i < albumsResponseData.albumCollection.length; i++)
        {
            var album:AlbumData = albumsResponseData.albumCollection.getItemAt(i) as AlbumData;
            if(album != null)
            {
                _albums.push(album);
                tempCovers.push(album.cover_pid);
            }
        }

        // ...
    }
}
// ...

By now you should be comfortable working with the returned results …

If you want to know how the others call look like, download the sourcecode and open the FacebookConnectTest class.

To display the album thumbnails we used the TileList flash component – here is a good article how the component works: http://www.adobe.com/devnet/flash/quickstart/tilelist_component_as3/

If you still have questions, don’t hesitate to ask.

You can download the sourcecode here: /examples/fbconnect/source.zip
You can find the online demo here: /examples/fbconnect/

Don’t forget to download the SWC from Google code: http://code.google.com/p/facebook-actionscript-api/downloads/list (it isn’t included in our sources).

The ImageViewer code is by no means bug-free but – as i said before – should give you a good insight of the API.¬†I put everything into one class … but don’t worry, I also added some short comments so hopefully you won’t get lost :)

Cheers
Phil

Comments