Saturday, October 22, 2011

Facebook Single Sign-On for AIR iOS Apps

With AIR 3 on the door many developers are willing to build their Mobile Applications with Adobe AIR Runtime. I need not mention separately that Social Networking remains one the biggest use cases for mobile applications which means nothing but integration with Facebook.So, today we have a great library(SWC) build for Facebook API that can be used with any Actionscript based application it can be a Web app running in browser or a desktop application built with AIR or A mobile application on Android/iOS/Playbook. One swc serves all. This can be found here.
But this article addresses a very specific problem. Facebook has provided a feature for Mobile Devices called "Single Sign-On".
A quote from Facebook developer page which best describes what this feature is all about.
One of the most compelling features of the iOS SDK is Single-Sign-On (SSO). SSO lets users sign into your app using their Facebook identity. If they are already signed into the Facebook iOS app on their device they do not have to even type a username and password. Further, because they are signing to your app with their Facebook identity, you can get permission from the user to access to their profile information and social graph.
Just to explain better. If I have 10 Facebook applications on my iPhone I will need to enter my credential in each app as and when I use them. SSO solves this problem for once and for all. You need to provide your credentials only once in the "Facebook" application (Facebook app by Facebook) and all other applications will come to Facebook app for authorizations.It also has a fallback mechanism, if the end user doesn't have "Facebook" app installed we can use Safari browser to serve the same purpose.
Ok. So lets start coding!! but before we actually start lets summarize the 5 easy steps involved and we will walk through each step.
  1. Define Custom URL for your application
  2. Set-up and use a simple native extension, which can tell us if a particular URI can be opened.
  3. Implement the Authorize method in Actionscript
  4. Handle the INVOKE EVENT of the application and Pass on the access_token and expiry_date to the Actionscript API for Facebook.
  5. Make Facebook API Calls with Actionscript API.
The basic mechanism by which this feature works on iOS is using Custom URI. On iOS any application can register a custom URI type that a perticular application wants to handle. For eg. If I have an application called "Image Viewer" I might want to tell iOS to pass any URI that start with img://... should be passed on to my application so that the application can be used to open an Image. Same is the case with facebook. If you want to try out. go to Safari browser on iOS and in address bar type "fbauth://" and say go. You can see that "Facebook" application opens up.
  1. So lets start and define one such URI for our application. It doesn't matter what IDE you are using to develop your app. So according to your directory structure and IDE locate the application descriptor xml of your AIR iOS app. and add the following XML chunk as a direct child of top level Application tag.
    <iPhone>
            <InfoAdditions><![CDATA[
       <key>UIDeviceFamily</key>
       <array>
        <string>1</string>
        <string>2</string>
       </array>
       <key>CFBundleURLTypes</key>
       <array>
        <dict>
         <key>CFBundleURLSchemes</key>
         <array>
          <string>fbYOUR_APP_ID</string>
         </array>
        </dict>
       </array>
      ]]></InfoAdditions>
            <requestedDisplayResolution>high</requestedDisplayResolution>
        </iPhone>
    
    The above chunk will tell iOS that whenever any application on device wants to open a url of the form fbYOUR_APP_ID://... iOS should open your application to handle that URL. Similar to saying that whenever we open url that starts with http:// it is opened with safari. The facebook app will use fbYOUR_APP_ID:// url to open our application back on successful login and pass all the required data along with this URL which our application can use.
    you can test this right away. just create an ipa install it on your device and then in safari try typing fbYOUR_APP_ID:// and hit go. It should launch your application.
  2. Now, lets move to the next problem. What if the user doesn't happen to have the Facebook application installed? To understand the problem in more detail, Just the way our app registers for a custom URI, The facebook app also registers for a custom URI scheme "fbauth://..." essentially this is how we will transfer control to facebook app for authrization, By opening a fbauth:// based URI, but if the end user does not have facebook app installed on his device there will eventually be none who understands the meaning of fbauth://. What do we do then? In such case we fall back to safari browser and use that for authorization. Currently in AIR we do not have in way of knowing if the iOS device has an application which can handle a particular URI scheme hence we need to a write a small native extension which provides a function called canOpenUrl(string) . This tutorial will not focus on how do we write native extensions you can get the one I have written from here and follow the steps to use it in your project.
    • Add the following XML chunk in your application descriptor as a child of top level application tag.
      <extensions>
          <extensionID>com.sbhave.openUrl</extensionID>
      </extensions>
      
      This will tell ADT that your application uses a native extension.Identified by the given extensionID. Note that Native extension is a new feature added in AIR 3. You must use AIR 3 SDK in order to use native extensions.
    • In order to get the Actionscript functions(which actually call the native obj-c code) recognized by your AIR iOS application. You need to externally link to the swc(Provided in zip). To this in Flash Builder go to project properties ->Flex Build path and Add the SWC. Once added double click on linkage type and make it "external" this step is very necessary.If you are using Flash Develop provide the swc path in external-library parameter
    •  Ok, good to go. Now the only thing to keep in mind that the currently released Flash Builder is not aware of packaging an application which uses Native extension and hence you need to package the application from command-line (help) and at the very end provide a new AIR 3 switch -extdir <Path to folder where .ane file is kept.>
    • We will use the functionality provided by this ANE in next steps. For now everything is set-up.
  3. Now we will implement the authorize method which does all the work of authentication. I will first share the code and then try to explain what it actually does.
    protected function authorize(appId:String,extPerm:Array,forceBrowser:Boolean=false)
    {
     var url:String = "fbauth://authorize";
     var isFbAppAvailable:Boolean = URLUtils.instance.canOpenUrl(url);
     var ops:URLVariables = new URLVariables();
     ops["client_id"] = appId;
     ops["type"] = "user_agent";
     ops["redirect_uri"] = "fbconnect://success";
     ops["display"] = "touch";
     ops["sdk"] = "ios";
     if(extPerm != null && extPerm.length > 0)
      ops["scope"] = extPerm.join(",");
     if(!isFbAppAvailable || forceBrowser){
      url = "https://m.facebook.com/dialog/oauth";
      ops["redirect_uri"] = "fb"+appId+"://authorize";
     }
     var req:URLRequest = new URLRequest(url);
     req.data = ops;
     req.method = URLRequestMethod.GET;
     navigateToURL(req);
    }
    
    This is a very simple method which just sets the data and constructs the url. navigateToUrl actually tries to open the Url which indeed opens the application which has registered to handle the particular type of url scheme. This function expects two parameters. first one is the application ID that you get when you first create your application on facebook developer portal. extParams is a string array which enlists the permissions required by you application.The last parameter allows you to force the use of browser and avoid using the native FB app for authentication. We will see its use in next step when we handle the invoke event. an example call is shown below.(Please read step 4 before you actually write the following call in your code. You may want to check the LSO. See the sample code at the end of tutorial.)
    authorize(APP_ID,["read_stream"]);
    
    You can call this whenever you want the user to authenticate and authorize your application.For various permissions that you can specify see this . It is assumed for the sake of simplicity that APP_ID is the global level constant in your application which set to your facebook application ID.
  4. Till this point, If you can test you application, whenever you call the authorize method you will be redirected to the FB app or Safari depending on availability and the user can get himself authenticated there and once done he will be redirected to your app. Now lets see how we can handle the data we get from facebook. We do this with the help of INVOKE event given by AIR. Whenever the application is invoked as a result of custom URL. we get the link that triggered our app in InvokeEvent's arguments array. This is link is where we have all the data that we need. In order to do this. Add a handler for INVOKE event in your application, earlier is better but must be added before calling the authorize() method. Eg. is shown below.
    NativeApplication.nativeApplication.addEventListener(InvokeEvent.INVOKE,onInvoke);
    
    onInvoke is the function where we will process all the data received as a result of authentication.I will again repeat my habit of first scaring the reader with the code and then trying to explain.
    protected function onInvoke(e:InvokeEvent):void{
    
    var str:String = e.arguments[0];
    if(str && str.indexOf("fb"+APP_ID+"://") != -1 )
    {
     var vars:URLVariables = FacebookDataUtils.getURLVariables(e.arguments[0]);
     var accessToken:String = vars.access_token;
     if(!accessToken || accessToken == ""){
      var err:String = vars.error;
          
      if(err && err == "service_disabled_use_browser"){
       authorize(APP_ID,["read_stream"],true);
      }
          
      else if (err && err == "service_disabled"){
       // We cant use SSO at all use the old FacebookMobile.init() and FacebookMobile.login()
      }
       
      var errCode:String = vars.error_code;
      var userDidCancel:Boolean = !errCode && (!err || err == "access_denied"); 
          
      if(userDidCancel){
       // User cancelled the login and authentication
      } 
     }
         
     else{ // Login was successful
      var expiresIn:int = int(vars.expires_in);
          
      if(expiresIn != 0){ // Everything went just well
       var expDate:Date = new Date();
       expDate.seconds += expiresIn;
       FacebookMobile.init(APP_ID,startUsingApi,accessToken);
       
                            // Store FB details in LSO
              var diskCache:SharedObject = SharedObject.getLocal("diskCache");
       diskCache.data["token"] = accessToken;
       diskCache.data["expDate"] = expDate;
       diskCache.flush();
       diskCache.close();
       diskCache = null;
      }
     }
    }
    }
    
    Lets go through the code bit by bit In the first line we store the first argument in a variable. As there can be various other methods of opening(invoking) the app. This can very well be null. That's what we do in the if statement that follows. We also check that the first argument is actually the result of triggering our fbUrl. If you go back and see the step 1. URLSchemes are actually an array and hence your app can register for more than one url scheme. We do absolutely nothing if any of this tests fail
    As our ultimate goal is to hook up this authentication with Actionscript API for facebook.I can safely assume that you have already added a reference to the AS FB API swc file.FacebookDataUtils.getURLVariables is a function in the SWC that decodes the URL and return an object, using which we can access various parameters passed along with URL by making use of normal dor(.) operator.for eg. if I pass to the function a url like abcd.com?a=b&c=d I can access the data as result.a and result.c, and this is exactly how we will use vars.
    The very first this that we do is to try getting an access token this is the key for API. If this access token happens to be null or empty we have hit some problems. which we handle in the if block. Generally, if we dont get the token we get a variable called error which describes the error that may have occurred
    • service_disabled_use_browser: The SSO serve is disabled from FB app and hence we need to try with browser. This is where we use the third parameter of the authorize() which forces the use of browser.
    • service_disabled: SSO service is disabled completely we need to fall back to the old method of using SWC init and login methods.
    • The next few lines decides if user purposely canceled the process of authentication. and
    If we enter the else block we have made it and we have an access token every time we get the access token we also get with it an integer called expires_in these are the number seconds for which the token is valid. If we have a non zero value we have received a valid usable token. In such case we will call the FB API SWC's init method, but with the third parameter as we already have a valid access token now.
    But to make developers and end users' life even easier. We store the access token and expiryDate(Pay attention to how the expiryDate is generated from expiresIn value) to the local object. WHY? Reason being: What if user closes the app soon after authentication, and opens it back in just few ours? though he need not enter his credentials again (This is what SSO is all about), He will get a round trip to FB app(Showing that he has already authorized the application) and then back to your app. Instead what we can do is that in step 3. before we call the authorize method we can check the same local shared object and check if we already have a non-expired and valid access token. In such case we do not need to call authorize at all.
  5. Now the last and most fun part that is to actually use the FB API to make calls and get the real data from facebook. In the earlier step we have passed a callback name called startUsingApi this will be the function that will get called when Facebook API completes the initialization. An example emplementation is shown below.
    protected function startUsingApi(session:Object, error:Object){
     var p:Object = new Object();
     p.limit = 0;
     FacebookMobile.api("/me",function(result:Object, fail:Object):void{
      if(null == fail){
       trace(result.name);
      }
     },p);
    }
    
    
    Just to trace the user's name.
That is all. Actually it doesn't seem so big when you actually do it. You can find the complete implementation here.

64 comments:

  1. Is there any chance of getting an example of this but for the Flash IDE? I'm finding I can't export after I put extensions code in the application descriptor.

    My app is at the stage that it logs in and gets permissions etc. I'm just trying to implement the SSO feature.

    Thanks
    Don

    ReplyDelete
  2. I think the issues you are facing are common to any native extension. I recommend reading http://code.google.com/p/in-app-purchase-air-ios/issues/detail?id=1 . BTW, You cant publish from IDE if you use the Native Extension. You have to package swf/app-xml/assets using the command line.

    ReplyDelete
  3. Thanks, I was wondering if that was the problem.

    ReplyDelete
  4. Hi - do you have any examples of the mobile version working on an iPad? I've got the source code from the Google repository and have had no luck getting FacebookMobile working at all - iPad or not. I have gotten the desktop version working, but that is it. If anyone has an example working on an iPad I'd sure appreciate seeing it.

    ReplyDelete
    Replies
    1. Hi:

      just as a demo you can have a look at "Photos Of You" on iOS App Store.(Its free anyways)

      I too used FacebookMobile (Though I had to make minor changes in the source). Is there any specific issue you are facing? So I might be able to suggest some fix/workaround.

      Delete
  5. Saumitra,

    Could you provide the source for building your .ane file? I'm trying to use yours with the next flash builder 4.6 and I think I might need to update the namespace in the extension.xml descriptor for building the .ane file.

    Thanks,
    Craig

    ReplyDelete
  6. Great article. I'm curious if there's a way to get a new token without having to switch back to the Facebook app and re-authorize. Is that possible?

    ReplyDelete
    Replies
    1. Solved this in case anyone cares...

      In your facebook app settings, you have to be sure to disable offline access or else your token will only last 2 hours.

      Delete
  7. Does this url handling mechanism based SSO work on ANdroid too? What is the best practice to do SSO on the Android?

    ReplyDelete
    Replies
    1. No, I think Android uses Intents to do this communication. I havent used Android SSO yet.

      Delete
  8. In the authorize function in the line: ops["redirect_uri"] = "fb"+appId+"://authorize";
    Does the appId var refer to the ios app id?

    ReplyDelete
  9. I´m trying to use your code in Flash.

    Here I will paste the 3 codes i´m using (in 3 different posts as they are too long)

    The error i get is an "Install error" when i put the IPA con the Ipad.

    On flash it doesn´t throw any errors.

    1- APP-XML
    //**********************************************************************************************



    FlashMobileWeb

    1.0

    FlashMobileWeb




    FlashMobileWeb





    FlashMobileWeb.swf
    standard
    false
    true
    true
    portrait
    auto
    true




    false

    false



    UIDeviceFamily

    1
    2

    CFBundleURLTypes


    CFBundleURLSchemes

    138239306302272



    ]]>
    standard



    com.sbhave.openUrl




    //**********************************************************************************************
    END APP-XML

    ReplyDelete
  10. The second step

    2- AS3 FLASH (OpenURL.swc Externally Linked)
    //**********************************************************************************************
    package
    {
    /**
    * ...
    * @author mec
    */

    import com.facebook.graph.FacebookMobile;
    import com.facebook.graph.utils.FacebookDataUtils;
    import com.sbhave.openUrl.URLUtils;

    import flash.display.*;
    import flash.events.*;
    import flash.net.*;
    import air.net.*;

    import flash.system.*
    import flash.desktop.*;

    public class Main extends Sprite
    {
    public var APP_ID:String = "138239306302272";

    public function Main():void
    {
    if (stage) init();
    else addEventListener(Event.ADDED_TO_STAGE, init);
    /**/label.text = "FIRST STEP"
    }

    private function init(e:Event = null):void
    {
    removeEventListener(Event.ADDED_TO_STAGE, init);
    /**/label.text = "entry point"

    if (Capabilities.cpuArchitecture == "ARM")
    {
    NativeApplication.nativeApplication.addEventListener(InvokeEvent.INVOKE,onInvoke);
    var diskCache:SharedObject = SharedObject.getLocal("diskCache");
    var token:String = diskCache.data["token"];
    var dt:Date = diskCache.data["expDate"];

    if(token && dt && dt.time > (new Date()).time)
    FacebookMobile.init(APP_ID,startUsingApi,token);
    else
    authorize(APP_ID, ["read_stream"]);
    }
    }

    protected function startUsingApi(session:Object, error:Object)
    {
    var p:Object = new Object();
    p.limit = 0;
    FacebookMobile.api("/me", function(result:Object, fail:Object):void
    {
    if (null == fail)
    {
    trace(result.name);
    }
    },p);
    }

    protected function onInvoke(e:*):void
    {
    var str:String = e.arguments[0];
    if(str && str.indexOf("fb"+APP_ID+"://") != -1 )
    {
    var vars:URLVariables = FacebookDataUtils.getURLVariables(e.arguments[0]);
    var accessToken:String = vars.access_token;
    if (!accessToken || accessToken == "")
    {
    var err:String = vars.error;

    if (err && err == "service_disabled_use_browser")
    {
    authorize(APP_ID,["read_stream"],true);
    }

    else if (err && err == "service_disabled")
    {
    /**/label.text = "We cant use SSO at all use the old FacebookMobile.init() and FacebookMobile.login()"
    }

    // CUT THE AS3 script for the blog to work.

    ReplyDelete
    Replies
    1. Hi:

      If you are creating IPA successfully. and iTunes is throwing error I doubt if problem is related to ANE. Can you try following?

      1. Remove ANE from your app. Do you still receive error?
      2. In your project properties make sure that your "Packaging contents" are ONLY the files you want. Some times it automatically packages the dSym or some other resources which make the package invalid.

      Delete
  11. Variable com.sbhave.openUrl::URLUtils is not defined.

    Any idea what can cause that?

    ReplyDelete
    Replies
    1. Are you trying to run the application from flash pro IDE? That is not possible when you use native extension for Flash CS 5.5.

      You will need to package your app from command line.

      Delete
    2. You can actually change the extension of the ane file to swc and it will work in the flash pro ide :)

      Delete
  12. Hi,
    great article. I'm trying to use this code, but I'm getting some errors.
    If the Facebook app is not installed and Safari opens, it doesn't send me back to my app.
    If the Facebook app is installed, then it sends me back to my app, but without any urlVariables. The value for the "str" variable in the onInvoke function is just "fbMY_APP_ID://authorize" and my app crashes when it tries to call "FacebookDataUtils.getURLVariables(e.arguments[0]);".
    I just can't figure out what I did wrong...

    ReplyDelete
  13. Solved my problem.... I had to register my app as a Facebook app....

    ReplyDelete
    Replies
    1. Hi, can you elaborate a little more on your solution? I'm having the same problem.

      Delete
    2. Your app settings on facebook.com (developer.facebook.com/apps) should be correct. Go to your app settings->advanced and make sure that app type is Native/Desktop and not web.

      Delete
  14. many thanks, this will open up a lot of possibilities for client apps. do I still need to package from the command line if I'm using Flash Builder 4.6? Can I specify utils.ane in the Native Extensions tab of AS Build Packaging? seems like it should work, I just did a quick test and I'm getting that "Variable com.sbhave.openUrl::URLUtils is not defined." as well..

    ReplyDelete
    Replies
    1. to clarify I'm seeing that error: ReferenceError: "Error #1065: Variable com.sbhave.openUrl::URLUtils is not defined." when "authorize" is being called..

      Delete
    2. Hi:

      No, If you have FB 4.6, you dont need to package from command line. what steps you mentioned are correct for FB 4.6

      Can you confirm the native extension is being packaged? You can confirm the same in Project Properties -> Build Packaging -> iOS Build Packaging.

      Delete
    3. ah yes that was it, sorry for that! added the ANE but needed to check the checkbox under Package.. works now

      Delete
  15. Hi Saumitra Bhave,

    Thanks for the tutorial, it's very informative.

    I follow your tutorial and then further explore for the communicate for the two AIR applications in IOS.
    1. The first app uses Custom URI "fbMY_APP_ID" as described in your first step, which is alright to be called by Safari.
    2. The second app uses URLRequest with the Custom URI to communicate with first app.

    I get the error: "SecurityError: Error #2193: Security sandbox violation: navigateToURL: app:/secondApp.swf cannot access tfbMY_APP_ID://test".

    Am I missing something? Is there any way to get rid of the problem?

    ReplyDelete
  16. Hi Saumitra Bhave,

    Excellent tutorial! Thanks very much for this.

    There is no sample code in the github repository. Could you pls share your sample code?

    ReplyDelete
  17. Hi Saumitra,

    Great article!!! Thank you for the tutorial and the ANE/SWC download, super helpful. Great post and thank you for sharing... for anyone else out there, if you get the undefined error or canOpenURL, the answer is:

    "Can you confirm the native extension is being packaged? You can confirm the same in Project Properties -> Build Packaging -> iOS Build Packaging."

    PS - If you have any tutorials on actually developing native extensions, I would love to read those as I am looking to develop my own extensions... I have Visual Studio 2010, not sure if I need other IDE's, do you have any suggestions...

    ReplyDelete
    Replies
    1. What platform you intend to write ANEs for? if for windows you need VS. for android you need eclipse. for iOS you need Xcode.

      I am working on some lib/framework that would make it easy to write extensions. I will post the article as soon as I have something usable.

      Delete
  18. Hey, great article! We implemented the single sign-on based on example and it works except...

    Using FacebookMobile.dialog(...) function to share feeds or make apprequests causes the Facebook login dialog to appear again (in the StageWebView). We actually tested this by logging into this dialog with different credentials than in the native Facebook application and our application then had two users logged in. Direct calls to graph api return data from user A (logged in native Facebook app) and FacebookMobile.dialog(...) calls cause a window appear with user B logged in.

    I think this might be because StageWebView doesn't share cookies with system browser on iOS (http://helpx.adobe.com/air/kb/stagewebview-differences-platforms-air-sdk.html), but it does say there that URLLoader and StageWebView should share cookies... :/

    I'll keep looking for solution but thought to ask if your app is using FacebookMobile.dialog(...) and if it's working for you. I could not find the "Photos of you" app from appstore,so couldn't check myself. Maybe it's regional thing?

    ReplyDelete
  19. Hello Saumitra

    Great work!
    I want your advice on what I am doing wrong. I follow your code to the letter (I belive I did) and this is what happens. I open my app (testing on my iphone) and try to authorize my app. It redirects me to safari where I accept the application and allow all permissions. So far all good. When I am done and press "Okey" that should redirect me back to my app a safari window pop ups that says "Cannot Open Page Safari cannot open the page because the address is invalid". Any idea what I am doing wrong.

    Thank you very much in advance.
    C

    ReplyDelete
    Replies
    1. hmmm...
      1. Make sure your info.plist is modified properly and that it contains your APP_ID as it is mentioned on Facebook app settings.

      2. Make sure the App Type is Native/Desktop in facebook settings.

      Delete
  20. Thank you very much Saumitra for your answer.
    I fixed my problem with your advice but I dont know if it did it by accident or by design. I changed in the application descriptor xml file the app id! Previously I had the apple app id and I put the facebook app id instead and it worked. I dont know were to find the info.plist file (are those two the same?). I am working in flash cs6 compiling to .ipa and testing on my iphone if that makes any difrence. Thansk for your time and advise.

    ReplyDelete
    Replies
    1. Hi Sorry for confusion. I meant to see app descriptor only.

      There are two different things in step 1 of article where you set


      CFBundleURLSchemes

      fbYOUR_APP_ID



      Here YOUR_APP_ID should be your Facebook APP ID.

      2. there is another tag in app xml which should be you Apple app id (One registered with your provisioning profile.)

      Delete
    2. Thank you very much :) For the advice and the tutorial!
      My best regards
      C

      Delete
  21. Hey dude - please share sorce code of URLUtils ane

    ReplyDelete
    Replies
    1. Hi:

      I dont have the sources now. But you can use any hello world ane. to call following two APIs of iOS [UIApplication sharedApplication]

      - (BOOL)canOpenURL:(NSURL *)url
      - (BOOL)openURL:(NSURL *)url

      Delete
  22. Excellent work Saumitra. Works like a charm!

    ReplyDelete
  23. This was working great until just today, did Facebook make a change that broke it? Now Facebook no longer returns to my app after login.

    ReplyDelete
  24. Hi Saumitra,

    A somewhat unrelated question but I feel you can help. I have an Android extension, which launches a native Android activity... Now when I go to home screen, go to the applications menu and again click on the app icon, the android activity gets killed and the AIR's activity is back in focus. Have you faced this before? I think it's got something to do with InvokeEvent's native implementation. I've noticed that this behavior replicates just before the onInvoke event is fired.

    Pulkit

    ReplyDelete
    Replies
    1. Apologies for late reply...Can you share the code? or you have it solved already?

      Delete
  25. hi,

    When i want to do SSO with Facebook apps, it show me an error page.
    An Error Occured with APP_NAME, Please try again later.

    What is the possible reason for this error?
    Thank you!

    ReplyDelete
    Replies
    1. Hi, Have you configured your application at Facebook Developers Portal?

      Delete
  26. hi,
    when i click cancel its not move back to the app...
    did i miss anything???

    Thanks

    ReplyDelete
  27. 1) my app is redirected to facebook app, but never return from facebook. On facebook developer I checked the native app radio button.
    2)FlashBuilder 4.6 premium is unable to see the native extension you provide. All is correct in app.xml and the completion works, but an error raises at runtime, it does not know what is URLUtils.

    I use AIR 3.1

    Any clues?

    Thanks.

    ReplyDelete
    Replies
    1. 1. Can you check if the step 1 is followed correctly? go to safari andi hit fbYOUR_APP_ID:// and it should open your ipa.

      2. In project properties you get a checkbox somewhere which tell FB whether to package that extension or not. Please confirm the checkbox has a tick.

      Delete
  28. Great. Thank you!

    It was the checkbox.

    So now, if I am already connected with the Facebook app, when i launch my app, it goes to FB app then come back. But if I'm not already connected, my app goes to FB app, then I log in, but the FB app doesn't return back to my app.

    With Safari, it's almost the same, if I'm not already connected and then log, I have to click on an ok button on top right on a facebook page on safari.

    Thanx.

    ReplyDelete
  29. HI, i am developing ios app with adobe air, thx for your great article, but when i try, it says

    "No libraries were linked as Runtime Shared Libraries (RSLs) because of your publish settings: AIR 3.2 for iOS"

    how can i solve this?

    thx

    ReplyDelete
    Replies
    1. Where are you using RSLs? RSLs dont work on iOS. If you are using old version of Flash Professional or Flash builder See http://code.google.com/p/in-app-purchase-air-ios/issues/detail?id=1#c5 (Comment no. 5 ) on how to link and use ANE in your application.

      BTW, More info about libs your using their linkage types etc would help

      Delete
  30. This comment has been removed by the author.

    ReplyDelete
  31. Cracking tutorial - I've one quick question if I may?

    Does the openURL ANE work on Android?

    Many thanks,

    Wayne

    ReplyDelete
    Replies
    1. I havent implemented it for android, as the tutorial was intended for iOS only.

      Delete
    2. For those looking for an Android version of this plugin, you can buy one here:
      http://www.adobe.com/devnet/air/articles/goviral-ane-ios.html

      It also works for iOS, definitely worth buying it if you need both iOS and Android support. I bought it and it works great, it has a bunch of other features too (no I dont work for them).

      Delete
  32. Hi all,
    Is there any way to get 'email' address of the user?

    I am passing 'email' param along with 'read_stream' to authorize() method.

    protected var permissions:Array = ["read_stream", "email"];

    authorize(APP_ID, permissions);

    bUT in onInvoke() method I am getting only 'access_token' but not email. How can we get email address of the user in iOS application. I am using 'GraphAPI_Web_1_8_1.swc'.

    PS: I am running app on IPAD

    ReplyDelete
    Replies
    1. If I use FacebookMobile.init(APP_ID,startUsingApi,accessToken);I am getting email,id,username ... information in the 'startUsingApi()' method.

      But if I use Facebook.init(APP_ID,startUsingApi,accessToken); control is not at all coming back to 'startUsingApi()' method.

      Am I doing anything wrong here?

      Delete
  33. Hey Saumitra,
    thanks a lot for your extension/solution, we are successfully using it. We also needed one for Android, so I had to write one myself (couldn't find anything), here is the link for anyone who is interested. Its free.

    http://afterisk.wordpress.com/2013/02/26/first-free-facebook-single-sign-on-sso-adobe-air-native-extension-for-android/

    ReplyDelete
    Replies
    1. Thanks for sharing I will add the link at the top of the article. So people wont miss.

      Delete
  34. Hi Saumitra Bhave ,

    Is it possible to do the same for Air desktop application ?

    Thanks

    ReplyDelete
  35. Hi, I've been experiencing an error lately. a sudden new error. it was fine until a month ago.

    I get IO_ERROR #2032 trying to access fbauth://authorize. basically, the app was calling the FB app, which after opening called back my app, right away, without asking any permission.

    right now, the Apple devs website is a bit messed up, but I don't think it's related. or maybe Facebook is not "talking" to my app because of the Apple issue, so my provisioning is "not valid" somehow?

    any idea of what's going on.

    thanks

    ReplyDelete
  36. This comment has been removed by the author.

    ReplyDelete
  37. It looks like if you try to run your app with the OpenURL ANE on AIR simulator it crashes as there is no implementation for Desktop platform in that ANE.
    I've used your ANE to create one with non-operative (does nothing) desktop extension:

    https://copy.com/sTPNEydDuFUI

    Using this one your simulator won't crash on startup but WILL if you try to access the extension. It's useful when you want to check the rest of your app without Facebook access.

    ReplyDelete
  38. Knowing how to identify the best commercial hvac repair lewisboro contractors is very important. It ensures that your heating unit is always functioning properly all the time.

    ReplyDelete