Facebook Graph API with a Native iPhone Application

One of the biggest gripes that I have with working with the FBConnect iPhone SDK, and really the Facebook API, in general was having to deal with a very inefficient REST implementation.  Callback after callback, protocol after protocol, major bugs (that have yet to be fixed as far as I know), and my biggest issue is the nasty user experience having to login a user.  I was very excited to hear when last month Facebook announced they had came out with a new API that would allow great security, ease and flexibility.  The pains of having to go through currently working functionality and refactor the code to accommodate the new features wasn't too much of a problem for me because it would mean a reduced code set on my part and I would be able to get rid of the Facebook Connect SDK.  I set out to test my theories and functionality via a quick web app.  No problems.  Then I proceeded over to my native iPhone app.  EraseUrX v2.0.  The new authentication mechanism utilized in Open Graph is OAuth2.0.  While many of the headaches and complexities of using OAuth are addressed and the documentation for using it in a mobile web app are well documented with Facebook they TOTALLY dropped the ball on providing any direction on using it with a native iPhone app and they don't provide an updated SDK.

I could one of three things: 1. Use the old Facebook Connect which should still work for the forseeable future, but as stated above has too many issues that I don't want to deal with and they could drop support at any moment. 2. Wait for Facebook to publish a new SDK, but how long would it take them 3. Just figure it out myself and have a flexible solution that didn't relay any third party framework.  I went with option 3.
The first thing you need to do is setup your app with Facebook.  Second, you will need to create a "callback" page that Facebook will send the request back to once the appropriate code and token has been given to your original request.  Third, once you have gotten the access_token from Facebook then you need to put it in a DOM object. This is important so that you can retrieve it via the UIWebview's javascript string evaluation and then finally save the access_token in NSUserDefaults for any subsequent requests.  In my case I wanted to get a list of the currently logged in friends.  Instead of having to go through the callbacks and delegate methods associated with the FBConnect SDK I now have user's login via OAuth and I make a call to, https://graph.facebook.com/me/friends, and get a JSON response of what I need.  Simple. Beautiful.
Callback Example (PHP):

Custom ViewController (I am not including setting up the uiwebview. I assume you already know how to do that):


21 responses
Exactly what I was looking for!

However, problem is that I cannot call "file_get_contents()" on my webhoster due to security concerns on their side of remotely bringing in content.

Any ideas on alternative ways to do this? I didn't immediately see a way of getting the access token without this method.

@tc : yea that is a big problem with shared hosting companies. you could try using cURL
I checked with my webhoster and there are no issues with file_get_contents(). In fact, i wrote a test script that just did echo file_get_contents('http://google.com') and that worked as expected.

however, when I execute your code, I get the error:

Warning: file_get_contents(https://graph.facebook.com/oauth/access_token?client_id=XXXXX&redirect_uri=http://mydomain.com/fb/callback3.php&client_secret=xxxx&code=YYYY) [function.file-get-contents]: failed to open stream: No error in E:\\htdocs\fb\callback3.php on line 5

(I have removed ClientID, clientSecret and the oAuth Code).

If I try to hit the fb access_token URL manually, I get an actual payload returned in the browser:

access_token=XYZ&expires=6508

(where XYZ is the access token)

So for some reason, there is a problem with the access_token URL specifically when used with file_get_contents().

Hi Corey,

I've spent hours with no luck. Could you please post some more details. For example. What's the initial authorize url? Is is anything like https://graph.facebook.com/oauth/authorize?client_id=...&redirect_uri=http://www.yourdomain.com/callback/&display=touch

thanks!

@matt @tc I apologize. The initial request to "start" the authentication off is: https://graph.facebook.com/oauth/authorize?client_id=xxxxxxx&redirect_uri=http://yoursite.com/fb/index.php

I think that the problems that both of you might be having is that you are requesting FB's own callback url instead of being redirected back to your site's callback url "http://yoursite.com/fb/index.php". The redirect url should be what you defined in your fb app setup console as the callback url.

I will work on a working example for next week if you are still having trouble. Most of the issues that I ran into were because of miss configuration in the app setup or making the incorrect call to their urls

Hi Cory, thanks again! I found adding &type=client_cred param (which is undocumented but on a stackoverflow post) to the access_token url on my server fixed the problem. You don't seem to have it in your server url so I'm a bit confused. I now get access_tokens so now I'm going to try using them with API calls. I pray it all works : )
Hi i am developing iphone native app and want to use facebook oauth API. remember this is not webkit app, its uiviewbased app. can i do authentication with having some thing on remote server. mean i want to make api request through iphone and get response there? no call to my own server. is it possible in current facebook Graph API. i am searching help and reading its documents but getting no clear idea? your help is appreciated. thanks
Hi can you share full example source code? thanks
Hey , thanks Cory ! I just have a small issue :
when doing the first redirection on the iphone, if the user is not connected to facebook, I get a classic browser-sized page to login, instead of an iPhone sized one (once I log in, I get the correctly sized authorize dialog). Any idea how to work around that ? I don't want to use the old SDK just for the sake of having a nice pop-in login dialog...
Thanks again,
Davy
@dav you just need to add &display=touch to the oauthurl in addition to your client_id and redirect_uri
I'm having the issue with the login page.. the size does not fit in the iPhone browser (I'm getting the brower classic size). I'm using display=touch but it's not working ... any clues?
By the way, there is a somewhat elegant solution if you don't want to deal with server side logic - use FBConnect session API and login dialog to authenticate the user and then translate the session key (in session delegate call) to access token using this approach: http://developers.facebook.com/docs/guides/upgrade#oauth
You would then be able to use the Graph API and don't have to deal rest of the FB Connect functionality..You don't need any server side redirect URLs...

In any case, thanks for sharing your original idea and post.

@My_2cents I agree you wouldn't have to deal with server side redirects, but one of the main things I was trying to get away from is having another framework in my apps. It adds alot of overhead and the facebook SDK is full of bugs and memory leaks that I would rather not deal with. I do appreciate the link to the upgrade for future readers.
noyhng
Thanks for the wonderful post.
I want to post images/messages to my news feed using the graph api. The documentations says that I need to use

curl -F 'access_token=...' \
-F 'message=Hello, Arjun. I like this new API.' \
https://graph.facebook.com/arjun/feed

Is there a way of doing this using NSURLRequest?

@Minar you can do that with NURLRequest. You just have to setup the request body and post those values to the above url, with the your friend's userid changed, but I would recommend to use ASIHttpRequest library to build the request. It is a lot easier.

http://allseeing-i.com/ASIHTTPRequest/How-to-use

@Cory I appreciate your response. Using ASIHTTPRequest I am now able to post messages on the feed but somehow I am not being able to post pictures.
See my code:
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
[request setPostValue:access_token forKey:@"access_token"];
[request setPostValue:@"Hello" forKey:@"message"];
NSString *pngName = @"bubble";
NSArray *paths = NSSearchPathForDirectoriesInDomains(
NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *pngPath = [documentsDirectory stringByAppendingPathComponent:
[NSString stringWithFormat: @"%@.png", pngName] ];

// If it's not there, copy it from the bundle
NSFileManager *fileManger = [NSFileManager defaultManager];
if ( ![fileManger fileExistsAtPath:pngPath] ) {
NSString *pathToSettingsInBundle = [[NSBundle mainBundle]
pathForResource:pngName ofType:@"png"];
NSError *error = nil;
[fileManger copyItemAtPath:pathToSettingsInBundle toPath:pngPath error:&error];
}
if ( [fileManger fileExistsAtPath:pngPath] ) {
NSLog(picturePath);
}
else {
NSLog(@"Picture did not get copied");
}

[request setFile:pngPath forKey:@"picture"];

[request startSynchronous];

This piece of code posts the message on the wall but not the picture.
Can you please tell what else should I do?

Hello cory wiles

i am new to develop iphone applciation with facebook. i would like to develop an application which post user score and retrieve it back from facebook. i dont know how to do it. help me

Hi Corey,
I've spent hours with no luck. Could you please post some more details.

I am trying to access location and then place id and wanted to comment to comment on that place id. so could u pls help me.
Thank you in advance.

You might find some help in the Facebook Developer Forum Archive here:

http://fbdevforum.com/

1 visitor upvoted this post.