iPhone, Facebook, oAuth 2.0 and the Graph API. A Tutorial, Part 2.

June 29, 2010

NOTE: I’ve moved the source code for this project to Git Hub, please get it here:  http://github.com/reallylongaddress/iPhone-Facebook-Graph-API

Preface

In part 1 of this tutorial we walked through obtaining an oAuth 2.0 access token from Facebook via an iPhone (or any iTouch device).  If you wish to go back and review the oAuth 2.0 process in some detail HERE.

iPhone oAuth Facebook login and extended permissions images

Facebook Login and Extended Permission Dialogs

In the second part of this tutorial I’ll show you how to leverage my pseudo-API to:

  • Login to Facebook using oAuth 2.0
  • Request extended permissions for your mobile application (photos, videos, publish stream and offline access)
  • Get your profile data
  • Get your friend list
  • Get your feed
  • Post to your feed
  • Post a photo (via a local image (UIImage) not a url)
  • Get metadata
  • Delete a feed post (via a Post)
  • Get search results
  • Get (and display) the author’s avatar

Convention

There are 2 APIs being talked about in this tutorial. To avoid confusion, I’m going to refer to them consistently as Facebook’s  ‘Graph API’ and my ‘pseudo-API’*.  Facebook’s Graph API is the stuff we’re interacting with via HTTP Get and Post calls.  The pseudo-API is the Objective-C/iPhone code that’s facilitating the interaction.

* I call it a pseudo-API if for no other reason I haven’t proven to myself it supports 100% of the Facebook Graph API functions.

An aside about my API design philosophy:  I could have written the pseudo-API to be much more robust and feature rich, with exceptions, logging, auto-magical json parsing, full featured functions like ‘getMyWallFeed’, etc.  However with robustness and features comes complexity and dependencies.  I kept everything aside from the absolute core functionality required to read/write data from/to the Facebook Graph API out of this implementation.  In short, I’ve left it primitive enough that anybody should be able to extend/wrap it easily, if they see fit.

The pseudo-API has only 3 classes.  The core functionality lies in the FbGraph.m file.  The other two classes support this core class.  FbGraphFile is used when uploading a file to Facebook.  FbGraphResponse is, I would hope, self-explanatory.

We’re going to skip over the steps required to create a Facebook application.  I covered that in Part 1:  iPhone, Facebook, oAuth 2.0 and the Graph API.  A Tutorial.  If you completed part 1 of the tutorial, you can use the same Facebook application without modification here.

Sample Code:

http://github.com/reallylongaddress/iPhone-Facebook-Graph-API

Creating the FbGraph Object

Before we can interact with the Graph API, we need to make a connection to it. And before we make a connection to it, we need a FbGraph object instance.  We do so like:

self.fbGraph = [[FbGraph alloc]initWithFbClientID:client_id];

Where:

FbGraph *fbGraph;

And

NSString *client_id = @"123145257717248";

The client_id should be YOUR Facebook application id.  I’ve left my application ID in here for no other reason than the tutorial code will work ‘out of the box’.

The login process

Now we have our fbGraph object instance, we’ll want to ask Facebook for a login screen.  Additionally we’ll need to let Facebook know the extended permissions we’re requesting for our app.  Here’s the code to do that:

[fbGraph authenticateUserWithCallbackObject:self andSelector:@selector(fbGraphCallback:) andExtendedPermissions:@"user_photos,user_videos,publish_stream,offline_access"];

There are 3 major things to note in this line (found in oAuth2TestViewController).

1)  We’re asking the fbGraph object to initialize the authentication process by calling the function: authenticateUserWithCallbackObject

2)  We’re setting a callback object (self) and a callback function (fbGraphCallback).   This object and function will be called upon completion of the oAuth authentication process.

3)  We’re requesting extended permissions:@”user_photos,user_videos,publish_stream,offline_access”

When this function is called, the pseudo-API will find the root application window**, stick in a UIWebView, and ask Facebook for a login screen (passing along your client_id and requested extended permissions):

NSString *url_string = [NSString stringWithFormat:@"https://graph.facebook.com/oauth/authorize?client_id=%@&redirect_uri=%@&scope=%@&type=user_agent&display=touch", facebookClientID, redirectUri, extended_permissions];

**-There’s a second authenticateUserWithCallbackObject function that allows you to specify a specific view you wish the login screen to be anchored/rendered in, if you don’t want it to render within the root view of your application.  Look at the FbGraph class for further details.

Note the ‘display=touch’ parameter.  It tells Facebook we’d like a login screen optimized for an iPhone/iPod touch screen.

Now that the process is started the UIWebView will render the login window that Facebook has returned to us.

After you’ve successfully authenticated to Facebook, you will be presented with a second screen with an extended permissions request dialog.  2 things to note here:  First, all permissions are unified into a single step.  Second, after you’ve approved the permissions, you won’t have to complete this step or see this screen again (so long as you don’t revoke the permissions).

Under the Hood of the Authentication Process

There’s some http redirects involved with the oAuth 2.0 (User-Agent flow) login process.  The FbGraph object is a UIWebViewDelegate, one of the functions associated with this delegate class is: webViewDidFinishLoad.  This function is called several times during the authentication process.  When the URL contains “access_token=” we’re golden.  We’ve successfully logged into Facebook.  When the pseudo-API sees this string, it parses out our oAuth access token, stores it to a class level variable, removes the UIWebView we inserted and finally calls the callback function we defined, returning control to your application.

The Rest of the Pseudo-API

The core of the pseudo-API is about 250 lines of code (including whitespace and comments), which is very little indeed.  This is possible because the Facebook Graph API does everything via simple HTTP Gets and Posts.  In fact, once you’ve figured out how to do Get and Post with the Graph API, you’ve pretty much figured out everything.

If you’re familiar with the current Facebook Connect implementation, you’ll immediately notice Graph API is immeasurably less complex and more consistent.

So, I could go through and explain how everything works in painful (and highly repetitive) detail…but I’m going to peace out, let you read over the code, dissect it, add some breakpoints and get your hands dirty.

FYI:  There is very intentionally very little UI in the app. Rather than having you, the reader, have to figure out my UI conventions as well as Interface Builder, I’ve kept it simple and dumped most all output to the debugger console.  The code is simple, the pseudo-API is simple, the Graph API is simple……

I hope you take a look at my pseudo-API and agree, it’ simple…that’s the idea.

If you find this post useful, if you include this code or the concepts you learned here in an app, if you extend this into a more full featured API….I’d love to know!

Happy hacking.

Dominic

ddimarco@room214.com

@dominicdimarco

Sample Code:

http://github.com/reallylongaddress/iPhone-Facebook-Graph-API

About Room 214

Room 214 is a social media agency focused on social media and digital marketing solutions for iconic brands. Our services include business intelligence, social strategy, application development and video production.

30 Comments

  • Minar says:

    Posting am image file in the feed fails.

    The request is: [variables setObject:@"test" forKey:@"message"];
    //[variables setObject:@"http://bit.ly/bFTnqd" forKey:@"link"];
    UIImage *picture = [UIImage imageNamed:@"75x75.png"];
    FbGraphFile *graph_file = [[FbGraphFile alloc] initWithImage:picture];
    [variables setObject:graph_file forKey:@"file"];
    [variables setObject:@"image" forKey:@"name"];
    [variables setObject:@"boy." forKey:@"description"];

    This request fails. Posting an image via the “link” works

  • Dominic Dimarco says:

    Hi Minar,

    Take a look at the ‘postPictureButtonPressed’ function. I just tested it and it’s working. If you continue to have problems, post an error message or other relevant data to help find the problem.

    Dominic

  • Minar says:

    The method ‘postPictureButtonPressed’ works fine and as expected. The documentation for publishing to the ‘me/feed’ mentions that besides the ‘message’ and ‘link’, one can also post ‘picture’.

    I tried posting an image in the method ‘postMeFeedButtonPressed’. I commented the line that posts the ‘link’ and instead added lines that will post a ‘picture’ in the feed.

    ***********************
    Posting am image file in the feed fails.

    The request is: [variables setObject:@"test" forKey:@"message"];
    //[variables setObject:@"http://bit.ly/bFTnqd" forKey:@"link"];
    UIImage *picture = [UIImage imageNamed:@"75x75.png"];
    FbGraphFile *graph_file = [[FbGraphFile alloc] initWithImage:picture];
    [variables setObject:graph_file forKey:@"file"];
    [variables setObject:@"image" forKey:@"name"];
    [variables setObject:@"boy." forKey:@"description"];

    This request fails. Posting an image via the “link” works
    ***********************

  • Minar says:

    The method ‘postPictureButtonPressed’ works fine and as expected. The documentation for publishing to the ‘me/feed’ mentions that besides the ‘message’ and ‘link’, one can also post ‘picture’.

    I tried posting an image in the method ‘postMeFeedButtonPressed’. I commented the line that posts the ‘link’ and instead added lines that will post a ‘picture’ in the feed.

  • Dominic Dimarco says:

    The documentation is minimal at best. My experience is that ‘picture’ element is a URL, not an actual file (wouldn’t it be nice if the documentation let us know)

    Perhaps you could try uploading a photo to an album (via POST /ALBUM_ID/photos), then figure out the URL and post to wall? Although when you post a photo to an album it appears in a user’s news stream already.

    Dominic

  • Minar says:

    I have tried all possible ways to post a ‘picture’ (not a URL but a UIImage) on the feed and have been working on this for 2 weeks now.

    If you go to facebook.com you can upload a picture from your computer on to the wall. I am using ASIHTTPRequest to work on facebook graph API. (You can do the same since it easier to code with ASIHTTPRequest than NSURLRequest.)

    This is the nearest I have gone to posting a picture on the feed.
    So if I have a ASIHTTPRequest *request.

    Now to post a picture I do the following:

    [request setPostValue:@"My Message" forKey:@"message"];
    [request setPostValue:@"somepic.png" forKey:@"picture"];
    [request setPostValue:@"Some Name" forKey:@"name"];
    [request setPostValue:@"Some description" forKey:@"description];

    [request startAsynchronous];

    If you try this then everything works fine other than the picture being posted. A blank placeholder for the picture is though show on the feed.

  • Minar says:

    *Some problems with comments here

    I have tried all possible ways to post a ‘picture’ (not a URL but a UIImage) on the feed and have been working on this for 2 weeks now.

    If you go to facebook.com you can upload a picture from your computer on to the wall. I am using ASIHTTPRequest to work on facebook graph API. (You can do the same since it easier to code with ASIHTTPRequest than NSURLRequest.)

    This is the nearest I have gone to posting a picture on the feed.
    So if I have a ASIHTTPRequest *request.

    Now to post a picture I do the following:

    [request setPostValue:@"My Message" forKey:@"message"];
    [request setPostValue:@"somepic.png" forKey:@"picture"];
    [request setPostValue:@"Some Name" forKey:@"name"];
    [request setPostValue:@"Some description" forKey:@"description];

    [request startAsynchronous];

    If you try this then everything works fine other than the picture being posted. A blank placeholder for the picture is though show on the feed.

  • Minar says:

    Instead of ASIHTTPRequest *request it should be

    ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];

  • Dominic Dimarco says:

    I haven’t researched exhaustively enough to call it a bug, yet. However I believe it’s either a bug, or it’s not well enough documented that ‘picture’ must be a URL reference, not an actual file upload.

    ASIHTTPRequest – I took a long look at it and liked what I saw. I would use it within a project that required HTTP Post file uploads, BUT I didn’t use it within pseudo-API because I wanted to avoid ANY/ALL dependencies.

    Dominic

  • Minar says:

    I found out this documentation on facebook: http://developers.facebook.com/docs/reference/api/post

    According to this documentation we can not post an image residing on our machine using the api. Instead we have to upload the pic and then provide the link for posting to the feed.

    But uploading an image on to the wall is allowed if you logon to facebook.com. I believe this functionality is not provided in the graph api.

  • Minar says:

    This is a bit off the discussion.

    Since it is not possible to upload a UIImage directly to the feed, I think I will have to upload the image to some website and then give out the ‘link’ in the request.

    Do you know of some wesbite where I can upload my images and get the link back?

  • David Peterson says:

    All I get is a white screen when I compile the xcode source code. Anyone else getting this? If so what did you do to resolve it?

    Thanks,

    David

  • Dominic Dimarco says:

    Hi David,

    My first guess would be that Facebook’s oAuth servers aren’t responding in a timely fashion (I just re-tested the code again and it’s working for me). Do you see abnormal anything in the Debugger Console? Is there a break point being hit?

    Dominic

  • David Peterson says:

    Hello Dominic,

    I think you were right about the timeout issues. I just re-downloaded the code and ran it in the simulator. Works!

    Thanks for your reply and for the code!

    Cheers,

    David Peterson

  • Kiran says:

    Thanks again for a great example project.

    Do you know how to allow a user to “unlink” their FB account for an app? I’m looking for the equivalent of the “Logout” button, but all the samples I have seen so far assume a strict web page.

    I’m assuming there is a way to do something like: graph.facebook.com/me/logout?

  • orlando seo says:

    Would it be ok if I used a bit of your CSS design for my own blog? I always ask first! Thank you!

  • Dominic Dimarco says:

    Hey thanks for your support! The community has been very receptive to this pet project of mine. I’m going to be moving it to Git Hub over the next few days!

    About your question….it’s a bit ambiguous so I’m going to (kinda) answer it two ways:

    1) Are you looking to logout a user from your application? If that’s the case simply delete the access_token. Without the token the user has been logged out. Deleting the access_token is essentially the same as deleting their cookie to use a web analogy. So if you were to create a logout button that simply wipes away the access_token…you’re all set.

    2) Are you looking to revoke the mobile application’s extended permissions?….That I’m not sure how to do via the Graph API…..

  • Dominic Dimarco says:

    Nice….

    FYI: I’m going to be moving this project to Git Hub over the next few days so the community can get further involved…..

    Dominic

    UPDATE (7/15/2010): The full sample code as well as the Facebook iPhone API can be found on Git Hub: http://github.com/reallylongaddress/iPhone-Facebook-Graph-API

  • Kiran says:

    (I can’t seem to reply to your post, but this is RE: “logging a user out”)

    Ok, I feel stupid now. Delete the access_token. Of course!

    Thanks again.

  • Jason says:

    Not sure if its the new SDK but I’m getting a short white screen then login. I can login but never see the extended permissions screen. Have you tried it recently?

    Thanks.

  • Dominic Dimarco says:

    Hi,

    I just downloaded the code that lives on GitHub and tested it….I get both the login and the extended permissions screen.

    My guess would be that Facebook’s server had a glitch, which isn’t all that uncommon….

    Dominic

  • Garmin 60CSX says:

    Exactly where might I buy this particular software?

  • Rahul says:

    Hi:
    Thanks for the tutorial. It is a great help. I am looking to get the email id, birthday and phone numbers from the facebook friends and load them in UITableView. Can you please help me with this? I see you are getting friends name but trying to understand how do I get rest of the other information.
    Thanks for your time.
    Regards

  • Viral Narshana says:

    Hi,
    I have a question. I am using this method “getMeButtonPressed” to get facebook user profile but i couldn’t provide profile picture and birthdate.Any idea to get this detail ?

  • shivaganeshgupta sunkari says:

    hi sir, this is usefull but small problem when user logged in facebook its coming white screen how can i remove white screen or how can i put its activity indicator while displaying white screen please help me.

  • Thank you so much! but i have a question.

    How to post a feed to my friends?
    Thank again!

  • sallam says:

    SECURITY WARNNING:PLEAse treat the URL above as you would your password and don’t share it with any one

  • prakash says:

    when i press long in button then it shows Security warning please treat the URL above as you would your password and do not share it with anyone. i tried some other tutorial too i am getting same error in graph api. how to resolve this problem?

  • Nitin Tyagi says:

    HI i am not getting any access token in url after entering login credential. can you tell mw what is the problem

Leave a Reply

Your email address will not be published.