spacer

Labs.byHook

Scripts, Tools & Methods Developed at Hook

spacer spacer
spacer

This blog is created and maintained by the technical team at Hook in an effort to preserve and share the insights and experience gained during the research and testing phases of our development process. Often, much of this information is lost or hidden once a project is completed. These articles aim to revisit, expand and/or review the concepts that seem worth exploring further. The site also serves as a platform for releasing tools developed internally to help streamline ad development.

spacer
spacer

Hook is a digital production company that develops interactive content for industry leading agencies and their brands. For more information visit www.byhook.com.

spacer

Facebook “Like” Button in Flash

spacer
Posted on August 3rd, 2010 by Jake
spacer

Facebook Like Button in Flash: A Tale of Broken Dreams and Tortured Souls

It all started so innocently, “Hey, can we implement The Like Button in flash?”. Seemed like a very average and reasonable request. I mean really, how hard could it be? Its all just http requests right? Shouldn’t be an issue… Turns out its like agreeing to step into a ring with Kimbo Slice, assuming that anyone with a name like “Kimbo Slice” couldn’t possibly put up much of a fight.

Consequently, this post has two parts. The first part that explains what we ended up with, and the second part which is a recount of what essentially turned out to be a twisted trail littered with the shards of broken dreams… I highly suggest reading part two first. However the TL;DR effect will probably kick in on this post. So we are putting the working bits up front.

Part 1 – Mostly Successful
So, the original goal was to create a duplicate of the Facebook “Like Button”. Which means that we wanted to make a component of sorts that folks could drop into their project, and feed it a URL to be “liked”, just like the Javascript and br versions of the Like Button. This was not to be. I’m not saying its impossible, but its far from trivial. Please see Part 2 below to find out why its so difficult. However, we still wanted to have some semblance of a Like button for people to be able to use. So we worked out the next best thing. The answer is within Facebook Connect.

We have a working solution but there are some disadvantages when compared to Facebook’s Like Button. In order to use the Facebook API to “Like” something, you will actually need to have a post to like already set up. Which means you will need a page with posts on it that you can “Like”. This is a stark difference to how the “real” Like Button works, with which you can like any URL passed to it, and Facebook itself manages the creation of the objects within the Facebook system for the URL automatically. The other inconvenience is that in order to “Like” a post on a Facebook page, the user must also “Like” the page itself. This cannot be done through the Facebook API, which means we need to find a way to interface with the Facebook LikeBox or FanBox components.

So in order for our solution to work for you, you will need:

  • A registered Facebook Connect app
  • A company Facebook Page
  • A post on that page

While they are inconvenient requirements, the process will help drive traffic to places where you have a presence, and anyone that clicks the new Like Button, will have a standard “Like” notification posted in their Recent Activity section on their wall. So not all is lost. The trick here is to make the process the least annoying as possible for the user. So here is an in-depth look at our solution.

Our working example that we will be building during this post can be found here:
labs.byhook.com/hookconnect/HookConnect.html

And the source here:
HookLikeButtonExample.zip

First Things First
To get started, you will need set up a Facebook Connect application by going here:
www.facebook.com/developers/createapp.php

If you do not already have the “Developer” application installed you will be greeted with a window that looks similar to this:
spacer

Once you click “Allow”, you will be redirected to the “Facebook Developers” home page. Here at the bottom right you will see a “Status” section. Keep an eye on this as often as possible, because this seems to be one of the only places to get a bit of a heads up on changes and bug fixes to the api.

As a quick note, to get back to the developers page without creating a new app, just go here:
www.facebook.com/developers/

If you are now not sitting at the “Create Application” screen, click the “+ Set Up New Application” button in the upper right hand corner of the Developer page. It should look like this:
spacer

Type in the name you want to give your application, select “Agree” (after reading the Facebook Terms of course), and click “Create Application”.

This will bring you to your application settings:
spacer

Thankfully for a “Connect” app, there are very few things we need to set up. Go the the “Authentication” section and uncheck “Users” and “Facebook Pages”, since this app won’t be installed for people to use it on Facebook.

Next go to the “Connect” tab and fill in the Connect URL. This is basically the URL from where the api calls will be made. In this example’s case it will be from “labs.byhook.com/hookconnecttest/”

You will also need to fill in the “Base Domain”, which is simply the domain from which the API calls will be made. In our case its “byhook.com” (without the quotes).

In the Advanced tab, make sure your application type is set to “Web”.

That is pretty much it. Easy right?

Facebook Connect
So Facebook Connect apps work like this. Your client app is launched by the user. Then your app pops open a browser window, and makes the standard Facebook Auth call:

"https://graph.facebook.com/oauth/authorize?client_id=_appID&redirect_uri=redirectURL&type=user_agent&scope=appScope&display=popup"

Basically, that is the only reason we need to create a connect app at all. Its simply get access to the authentication system. The Facebook app portion isn’t used for any other reason really.

At this point the browser window popup is on Facebook. If the user is already logged into Facebook, the pop up is redirected to whatever was put in the redirect_uri with the addition of the access_token hash appended:

"#access_token=142459119113770|2.EEdhWucXWlnNxaUX3o608A__.3600.1280768400-100001308505549|55r0b4qYjCI-SOMEMORESTUFF.&expires_in=4419"

If you remember from our previous Facebook post, the access token is passed along with most of the API calls made from your app. So your app will store that token, and use it with the Facebook web requests.

If the user is not already logged in, the pop up will be redirected to Facebooks Login pop up. Once they login, or cancel, the pop up will, like in the other situation, be redirected to the URI you passed in. If the login was a success you will get the access token, but if the user canceled you will get:

"&error_reason=user_denied"

appended to your URI.

The trouble with the pop up, is that we still need that access token passed back into our flash app which resides in the original browser window. The first thought was to use the window.opener reference in the browser and call a JS method that would then pass that token into the flash app in the original browser window. However we discovered that Chrome will block the function call if its not called from the window that contains that function.

Here is a quick example demonstrating the issue:
labs.byhook.com/likebutton/ChromeFunctionExample.zip

So we needed another way to get the token back to our flash app. We ended up passing that information through a LocalConnection, which we will talk about in more depth later in the post.

With a basic understanding of how a Facebook Connect app is set up, and flows, lets get this all into Flash, shall we?

Setting Up The Example
I first want to point you to Yoz’s blog post about Facebook Connect with Flex:
blog.yoz.sk/2010/05/facebook-graph-api-and-oauth-2-and-flash/

During the creation of this Flash Like Button, that post was referenced for the overall Connect flow. He also had the great idea of storing the current access token into a Local Shared Object for an attempt at a seamless (behind the scenes) user authentication. Our Connect implementation ended up being somewhat different, but we certainly store the access token for later use, thanks to his post. Thanks Yoz!

In order to get our example running, you need to set up a Facebook Connect app as stated above. Then download our example here:
HookLikeButtonExample.zip

Lastly you will need to download ShadowBox from:
www.shadowbox-js.com/

We will be using ShadowBox to display the Facebook LikeBox for the situation where the user has not yet liked our company page, but wants to Like a post.

On your web host in the directory where you set your Connect url, make a /js folder and extract the shadowbox code into a folder called “shadowbox”. So the whole path looks like /js/shadowbox/shadowbox.js (and the other files).

Also in the /js folder put the jaclib.js, shadowboxEnabler.js and swfobject.js file from our example.

In the root directory (just above the /js folder) put the AuthConnector.swf, ConnectCallback.html, expressInstall.swf, HookConnect.html, and HookConnect.swf files from our example.

Now update the APP_ID (to your new Facebook app id), PAGE_ID (company page) and _postID (a post id from the company page) vars at the top of HookConnectMain.as. Recompile the HookConnect.fla, and reupload the HookConnect.swf file to your host.

Pop open a browser and hit the HookConnect.html page from your host. You should now be able to like the hell out of your post spacer

I know, I know.. “bbbbut where do I get the PAGE and POST IDs!?”

The page ID can be found in the link to the company page. For instance the Hook page link:
www.facebook.com/home.php?#!/pages/Hook/106749192712698

That number at the end is the Page ID.

To get the Post IDs you can use the example app from our other Facebook Post:
Hook Facebook Loader Example

In the “Item ID” field put your PageID, and then in the GRAPH API Call field, put “posts” (without the quotes). Now click “Get Info” and you will get the info you need on the right. You will see an “id”: just before the “from”: line. That ID looks like PAGEID_POSTID… you just need the number after the underscore. So the first post on the Hook page has an ID of 122857984426987.

From here you should just be able to new up a LikeButtonControl wherever you like in your project (as seen in HookConnectMain.as in the handeAddedToStage() method) and get your Facebook on!

Flash Like Button
By now, hopefully you have messed with the example a bit and got yourself a working Flash Like Button. Here is a bit of a rundown of how it all works. With Flowcharts! spacer

Oh stop your whining, its way easier to look at these charts than to read a million lines of my blathering to get the gist of whats happening with our Like Button spacer .

This is the flow of the initial Like Button Load
spacer
Click to enlarge.

The is the flow for when the Like Button is Clicked
spacer
Click to enlarge.

A quick note on pop up blockers
Not surprisingly, each browser handles pop up blocking differently. This makes it difficult to make an OAuth app that doesn’t annoy the user by requiring extra clicks. What we would have liked to do is when the user clicks the Like Button, make a request using the saved token, and see if that was successful. If it comes back and is not successful then pop open the Facebook OAuth page. The issue with that is the pop up comes as the second request after the initial click. The browser tracks the click and seems to allow one request before it starts blocking things. (this is the case with most browsers… Opera differs here however)
So the blocking seems to work like this for the different browsers (as far as our quick tests have shown):
Opera:

  • Blocks pop up even if its right after the click
  • Blocks second request pop ups (after a click)
  • Blocks non-click pop ups
  • Blocks Pop ups called from within flash.

IE:

  • Allows pop up just after click
  • Blocks second request pop ups (after a click)
  • Blocks non-click pop ups.
  • Blocks pop ups called from within flash, unless its right after a click.

Chrome:

  • Allows pop up just after click
  • Blocks second request pop ups (after a click)
  • Blocks non-click pop ups
  • Allows all pop ups from within flash (no click required)

FireFox:

  • Allows pop up just after click
  • Allows Second request pop ups (after a click)
  • Blocks non-click pop ups
  • Allows pop ups from within flash (no click required)

This means if there is any chance that we will need the Facebook login pop up, we have to force a pop up on the click. In most cases this is fine, however there is a slight annoyance to the user in these two specific cases:

1) If the user is logged into Facebook, but has never been to our page.
In this case, we don’t have a saved access token. In order to get this, we will need to force a pop up on click. Since the user is logged in, the pop up will come up, and then immediately disappear. Not a huge deal, but not completely seamless either.

2) If the user is logged into Facebook, when they come to our page, then logs out of Facebook in another tab, while they are still on our page, then clicks the like button on our page.
At this point, we make the request and find out that our token is no longer valid. Unfortunately we cannot pop open the log in box now because our 1 request per click has been used up. So we have to inform the user to click the like button again, or log back into Facebook…

So the browsers traded convenience for security… I’m cool with that.

The Nitty Gritty
There are 3 major parts to this whole deal. The FacebookConnectManager, LikeButtonControl, and the AuthConnector.

The FacebookConnectManager deals with all of the mess of getting an access token from Facebook. This has two main starting methods, connect() and quickConnectCheck().

The quickConnectCheck() method will connect to facebook as far as possible without any user intervention. As soon as user intervention is needed, the process stops. This means if there is a saved access token, it will attempt to verify if its good or not. If it is still good, it sets “isConnected” to true, and saves off the user’s Facebook ID for later use. If there is no saved token, or the token is not valid, it stops. In either case, when its done it will dispatch a FacebookEvent.QUICK_CHECK_COMPLETE event.

The connect() method will attempt to verify with whatever information it has, and if user intervention is needed, it pops open the appropriate Facebook Authentication window. If a pop up is required it also sets up a LocalConnection so that when the user is finished with the Facebook authentication pop up, the AuthConnector can send back the new access token. The name of the LocalConnection is generated based on the time elapsed since the app was started. This LocalConnection ID is passed to the pop up in the Redirect URI parameter for the Facebook Authentication Pop up. Please refer to the openFacebookPopUp() method.

protected function openFacebookPopUp(localConnectionID:String):void
       {//openFacebookPopUp
           //Update redirection link with new local connection ID
           var lcParams:String = localConnectionID;
           var fullRedirect:String = (_redirectURI + "?lcid=" + lcParams);
           var url:String = buildAuthURL(fullRedirect);
 
           if (ExternalInterface.available)
           {//handle through js
               var id:String = ExternalInterface.call("getSwfID"); //ADDED by addSWFFinder()
               var name:String = jsWindowName;
               var props:String = ",";
               var js:String = 'window.open("' + url + '", "' + name + '", "' + props + '");'
               ExternalInterface.call("function(){" + js + "}");
           }//handle through js
           else
           {//flash
               Log.log("Opening Facebook Webpage");
               navigateToURL(new URLRequest(url), "_blank");
           }//flash
       }//openFacebookPopUp

Once the access token is passed back from the AuthConnector, the FacebookConnectManager dispatches a FacebookEvent.AUTHORIZED event. If the user cancels the login process, the FacebookConnect Manager dispatces a FacebookEvent.AUTH_FAILED event.

The Facebook Authentication window is only the first half of the Login/Auth process. The second half is the callback after the login has been completed. This is where the AuthConnector comes into play.

The Facebook Authentication window redirects to whatever you passed in with the “&redirect_uri” parameter. In this case we pass in a URL to our ConnectCallback.html file with a “&lcid” parameter like so:

"labs.byhook.com/hookconnect/ConnectCallback.html?lcid=_AuthConnectorLC_12005392"

If you open the ConnectCallback.html file, you will see that it is basically loading a swf, our AuthConnector swf. When the AuthConnector is added to the stage, it calls on a bit of Javascript from the ConnectCallback.html to retrieve the passed in local connection name and another piece of JS to grab the passed in token hash:

private function handleAddedToStage(e:Event):void
       {//handleAddedToStage
           removeEventListener(Event.ADDED_TO_STAGE, handleAddedToStage);
 
           if (ExternalInterface.available)
           {//get params
               //Get access token
               _token = getToken();
 
               //Get LocalConnection ID
               _lcID = ExternalInterface.call("getLCID");
 
               if (_lcID && _lcID != "")
               {//send token
                   _lc = new LocalConnection();
                   _lc.addEventListener(StatusEvent.STATUS, handleStatus, false, 0, true);
                   _lc.addEventListener(AsyncErrorEvent.ASYNC_ERROR, handleAsyncError, false, 0, true);
                   _lc.addEventListener(SecurityErrorEvent.SECURITY_ERROR, handleSecurityError, false, 0, true);
 
                   //Send token
                   Log.log("ID: " + _lcID);
                   _lc.send(_lcID, "confirmAuthentication", _token);
               }//send token
           }//get params
 
 
       }//handleAddedToStage
 
       private function getToken():String
       {//getToken
           if (ExternalInterface.available)
           {//get hash
               var hash:String = ExternalInterface.call("getHash");
               var token:String = FBUtils.hashToToken(hash);
               return token;
           }//get hash
 
           return null;
       }//getToken

Now that we have the local connection name and the access token, we can send that info to our FacebookConnectManagerin the other browser window.

If the send is good, we call another bit of JS to close the pop up.

private function handleStatus(e:StatusEvent):void
       {//handleStatus
           switch(e.level)
           {//switch
               case "status":
                   if (ExternalInterface.available)
                   {//close window
                       ExternalInterface.call("closeWindow");
                   }//close window
               break;
 
               case "error":
                   Log.logError("Send Failed: " + e.code);
               break;
 
           }//switch
       }//handleStatus

If we have a good token, confirmAuthentication() is called via LocalConnection on the FacebookConnectManager. This starts the token verifcation process, which will save the token locally.

The last piece is the LikeButtonControl itself. It essentially waits around on events from the FacebookConnectManager, and updates the visuals of the button as needed. When the control is first added to the stage, it executes the quickConnectCheck() method on the FacebookConnectManager. Once the QUICK_CHECK_COMPLETE event is received, it makes a “Likes” request on the post to see how many people have liked that post. Once that request comes back, it checks to see if the FacebookConnectManager is connected. If it is, it then grabs the UserID from the FCM and checks to see if that is in the list of userIDs returned from previous the “Likes” request. If the current user is in the list, it sets the button to the “Selected” state and updates the accompanying text. If the FacebookConnectManager is not connected, then it just updates the button text with the number of people that like the post already.

The last scenario is if the user is logged into Facebook, but they have not yet “Liked” the company page. In order to prompt the user to “Like” the company page first (which is the only way the API will let you Like a post) we open an overlay in javascript. In our case, we are using ShadowBox. We could also do this in a pop up, but we are trying to prevent popup blockers from ruining our day.

Begin Tangent:
So I’m sure you are already thinking… Oh OH!! we could show the Facebook Auth pop up in the same type of overlay! That way we don’t have to worry about the pop up blockers!! We thought that too. Hover when you try and embed the result of the request to the Auth Page, Facebook puts a grey overlay above that, and anywhere you click, redirects the browser to their login page. So unfortunately we still need to use a real pop up for that.
End Tangent

Once that overlay opens, the FacebookConnectManager polls Facebook over and over to see if the user has “Liked” the page yet. If they have, we close the overlay automatically. If the user closes the overlay and doesn’t like the page, we stop the polling. There is another possible way to do this through Facebook’s Event Subscription system, but I believe I’ve read that will not be supported in the future. So we went with this route, which is more future safe, but less elegant.

That pretty much wraps it up. If you want to suffer along with us, you can read Part 2 below, for all of the other things we tried before coming to this conclusion. Its good times if you are in to that sort of thing spacer

Our working example:
labs.byhook.com/hookconnect/HookConnect.html

All of the example code can be downloaded here:
labs.byhook.com/likebutton/HookLikeButtonExample.zip

This example is built on top of the library we started with the other Facebook Post as well as with our Logging Library which can be found here on the labs site. There are a few improvements that we have made to the FacebookManager class (not the FacebookConnectManager), that are not in this package yet, but they should be updated soon. The code will be replaced in this example (which won’t effect anything in this post) and in the previous Facebook Post. So check back soon!

Lastly there are some Like Button features that are not yet implemented. We figured we should list them to clear up any confusion:

  • The Facebook “processing” blue bars (could be shown during requests)
  • Be the first of your friends text
  • Faces on big Like Button
  • Comment overlay

These may or may not be implemented in the future. If someone out there implements them, let us know and we will post the update here for everyone.

As always if you have any stories to share or questions to ask, please do so

gipoco.com is neither affiliated with the authors of this page nor responsible for its contents. This is a safe-cache copy of the original web site.