Authorizing Facebook Applications in Android
Hold on, this is going to be fast and smooth! I am playing with an Android Emluator for a few days now. One of the challenges was to mount FacebookOAuthGraph lib into Android. It turned out to be 1 hour task. Thanks to Flash-Core article and sHTiF and StageWebView. Long live AIR for Android! 🙂 Follow the article for codes:
You do not need a callback.html file, as in previous AIR example, you can use non existing redirect_uri targeting correct domain + a simple extending of FacebookOAuthGraph:
package { import flash.display.Stage; import flash.events.LocationChangeEvent; import flash.geom.Rectangle; import flash.media.StageWebView; import onboard.Controller; public class FacebookAndroid extends FacebookOAuthGraph { public var loader:StageWebView; public var stage:Stage; // this is the air application Stage public function FacebookAndroid() { super(); } override public function connect():void { var bounds:Rectangle = new Rectangle(0,0,480,480); loader = new StageWebView(); loader.addEventListener(LocationChangeEvent.LOCATION_CHANGING, onLocationChanging); loader.addEventListener(LocationChangeEvent.LOCATION_CHANGE, onLocationChange); loader.stage = stage; loader.viewPort = bounds; loader.loadURL(authorizationURL); } private function onLocationChanging(event:LocationChangeEvent):void { event.preventDefault(); loader.loadURL(event.location); } private function onLocationChange(event:LocationChangeEvent):void { var hash:String = locationExtractHash(loader.location); var error:String = locationExtractError(loader.location); if(hash) confirmConnection(hash); if(hash || error) destroyLoader(); } protected function locationExtractHash(url:String):String { var index:int = url.indexOf("#"); if(index <= -1) return null; var hash:String = url.substr(index + 1); return hashToToken(hash) ? hash : null; } protected function locationExtractError(url:String):String { var index:int = url.indexOf("?"); if(index <= -1) return null; var query:String = url.substr(index + 1); var variables:URLVariables = new URLVariables(query); return variables.hasOwnProperty("error") ? variables.error : null; } private function destroyLoader():void { loader.removeEventListener(LocationChangeEvent.LOCATION_CHANGING, onLocationChanging); loader.removeEventListener(LocationChangeEvent.LOCATION_CHANGE, onLocationChange); loader.dispose(); loader = null; } } }
How does this works? You do not need any callback.html, just generate some redirect_uri that correctly targets your domain, it can be anything, even 404.html, or asdf-foo-bar.html file that does not exist. Once the Facebook, redirects you back to the redirect_uri, the url contains access_token within url hash
http://domain/whatever-or-404.html#access_token=123
… now, if it does, it is parsed by locationExtractHash(), if it does not, the url contains error (user clicked Cancel button), the url contains error:
http://domain/whatever-or-404.html?error_reason=user_denied&error=access_denied&error_description=The+user+denied+your+request.
In case of error locationExtractError() parses and error. In both cases (error or access_token), the HTMLLoader window is closed and token is handled via confirmConnection(). Yeah, this way you can authorize !ANY! existing facebook application for your AIR app.
sHTiF also did a good job commenting all the functions, follow his the article to understand LocationChangeEvent listeners.