How to Check-In Using the Facebook iOS SDK and Graph API
Update (Nov, 22 2011): The Facebook Graph API and iOS SDK have changed since I posted this tutorial. Message me on Twitter if you have any questions: http://twitter.com/tygeo I may be able to help! *crosses fingers*
I’d like to explain the simple procedure of checking in using the Facebook API on an iPhone. This is a fairly technical post which may fly over the heads of non-iOS-programmers but may be of some general value to those people who carry an interest in Location Based Services like Facebook Places.
I’ll also mention an idea that I think would do well in the App Store and that can be easily implemented using this tutorial. I have not seen this app in the store yet and I hope that one of you beats me to it.
Ok, let’s get started. First, let’s assume that you’ve already integrated the latest iOS Facebook SDK into your XCode project and you’ve already registered your app with developers.facebook.com and now you’d like to be able to find nearby places and then check in to one of those places. The general workflow is as follows:
- To publish a checkin on behalf of the user, you need to have the “publish_checkins” extended permission granted to your app by the user. Get it.
- Get the latitude and longitude of your user’s device. One way to do this is using the CLLocationManager singleton provided by the Core Location Framework.
- Send a GET request to the Facebook Graph API which contains the user’s latitude and longitude: https://graph.facebook.com/search?type=place¢er=35.6869444,-105.9372222&distance=1000
- Display the nearby place list produced from step 2 in a table view or something similar that allows the user to select which place she wants to check in to.
- Send a POST request to the Facebook Graph API with path “me/checkins” containing the PlaceID, user coordinates (from step 2), and optional tags (friend IDs) and a status message.
These five steps are all it takes to check in. Let’s go over them in detail.
1. Get the “publish_checkins” extended permissions from your user.
- (void) login {
permissions = [[NSArray arrayWithObjects: @"user_checkins", @"friends_checkins", @"publish_checkins", nil] retain];
[ facebook authorize:appID permissions:permissions delegate:self];
}
2. Get the latitude and longitude of the user’s device by instantiating the CLLocationManager object, starting it up, and accessing it’s properties. Don’t forget to add the CoreLocation Framework to your project.
- (void) init {
locationManager = [[CLLocationManager alloc] init];
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
locationManager.delegate = self;
[locationManager startUpdatingLocation];
}
- (void) saveLocation {
latitude = locationManager.location.coordinate.latitude;
longitude = locationManager.location.coordinate.longitude;
}
3. Get the list of nearby places. In this example, I’m using my custom class “NearbyPlacesRequestResult” to handle the Facebook request response (as an FBRequestDelegate). I handle all of my Facebook requests this way, each one having their own separate class to handle their individualized response. This is also how Facebook does it in their sample iOS SDK project.
- (void) getNearbyPlaces {
NSString *centerString = [NSString stringWithFormat: @"%f,%f", latitude, longitude];
NearbyPlacesRequestResult *nearbyPlacesRequestResult =
[[[[NearbyPlacesRequestResult alloc] initializeWithDelegate:self] autorelease] retain];
NSMutableDictionary *params = [NSMutableDictionary dictionaryWithObjectsAndKeys:
@"place",@"type",
centerString,@"center",
@"1000",@"distance", // In Meters (1000m = 0.62mi)
nil];
[_facebook requestWithGraphPath:@"search" andParams: params andDelegate:nearbyPlacesRequestResult];
}
NearbyPlacesRequestResult.h – This class has its own delegate which it calls when the request succeeds or fails. So make sure your class conforms to this class’ delegate protocol if you choose to use it.
#import
#import "FBConnect.h"
@protocol NearbyPlacesRequestDelegate;
@interface NearbyPlacesRequestResult : NSObject {
id _nearbyPlacesRequestDelegate;
}
- (id) initializeWithDelegate: (id)delegate;
@end
@protocol NearbyPlacesRequestDelegate
- (void) nearbyPlacesRequestCompletedWithPlaces:(NSArray *)placesArray;
- (void) nearbyPlacesRequestFailed;
@end
}
NearbyPlacesRequestResult.m
#import "NearbyPlacesRequestResult.h"
@implementation NearbyPlacesRequestResult
- (id) initializeWithDelegate:(id )delegate {
self = [super init];
_nearbyPlacesRequestDelegate = [delegate retain];
return self;
}
/**
* FBRequestDelegate
*/
- (void)request:(FBRequest *)request didLoad:(id)result {
NSArray *placesArray = [result objectForKey:@"data"];
[_nearbyPlacesRequestDelegate nearbyPlacesRequestCompletedWithPlaces: placesArray];
}
- (void)request:(FBRequest*)request didFailWithError:(NSError*)error {
NSLog(@"NearbyPlaces %@", [error localizedDescription]);
[_nearbyPlacesRequestDelegate nearbyPlacesRequestFailed];
}
@end
When the nearby places response returns successfully, the method nearbyPlacesRequestCompletedWithPlaces: will be called on your NearbyPlacesRequestDelegate, passing an array filled with nearby place dictionaries in this format:
{
"name" : "Institute of American Indian Arts Iaia Iaia Museum",
"category" : "Local business",
"location": {
"street" : "108 Cathedral Pl",
"city" : "Santa Fe",
"state" : "NM",
"country" : "United States",
"zip" : "87501-2027",
"latitude" : 35.686501,
"longitude" : -105.936913
},
"id" : 111664535537155
},
{
"name" : "Long John Silvers Seafood",
"category" : "Local business",
"location": {
"street" : "115 E San Francisco St",
"city" : "Santa Fe",
"state" : "NM",
"country" : "United States",
"zip" : "87501-2109",
"latitude" : 35.687032,
"longitude" : -105.937745
},
"id" : 111626122209166
},
{
"name" : "La Casa Sena Restaurant",
"category" : "Local business",
"location": {
"street" : "125 E Palace Ave Ste 20",
"city" : "Santa Fe",
"state" : "NM",
"country" : "United States",
"zip" : "87501-2304",
"latitude" : 35.68755,
"longitude" : -105.936941
},
"id" : 115120131844030
},
...etc...
4. At this point, you should probably display the nearby places in a list format. Here’s how I displayed them in a UITableView.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
}
cell.textLabel.text = (NSString *)[[placesArray objectAtIndex:indexPath.row] objectForKey:@"name"];
cell.detailTextLabel.text = (NSString *)[[placesArray objectAtIndex:indexPath.row] valueForKeyPath:@"location.street"];
return cell;
}
5. Finally! Here’s where we check in. postCheckinWithDictionary takes a dictionary that contains the checkin information (PlaceID, tags, and message).
- (void) postCheckinWithDictionary:(NSMutableDictionary *)dictionary {
PostCheckinRequestResult *postCheckinRequestResult =
[[[[PostCheckinRequestResult alloc] initializeWithDelegate:self] autorelease] retain];
SBJSON *jsonWriter = [[SBJSON new] autorelease];
NSMutableDictionary *coordinatesDictionary = [NSMutableDictionary dictionaryWithObjectsAndKeys:
[NSString stringWithFormat: @"%f", latitude], @"latitude",
[NSString stringWithFormat: @"%f", longitude], @"longitude",
nil];
NSString *coordinates = [jsonWriter stringWithObject:coordinatesDictionary];
NSMutableDictionary *params = [NSMutableDictionary dictionaryWithObjectsAndKeys:
[dictionary objectForKey:@"place"], @"place", //The PlaceID
coordinates, @"coordinates", // The latitude and longitude in string format (JSON)
message, @"message", // The status message
tags, @"tags", // The user's friends who are being checked in
nil];
[_facebook requestWithGraphPath:@"me/checkins" andParams:params andHttpMethod:@"POST" andDelegate: postCheckinRequestResult];
}
Just like in step 3 where we request the nearby places, this request has its own request result handler class, “PostCheckinRequestResult.”
PostCheckinRequestResult.h
#import
#import "FBConnect.h"
@protocol PostCheckinRequestDelegate;
@interface PostCheckinRequestResult : NSObject {
id _postCheckinRequestDelegate;
}
- (id) initializeWithDelegate: (id)delegate;
@end
@protocol PostCheckinRequestDelegate
- (void) postCheckinRequestCompleted;
- (void) postCheckinRequestFailed;
@end
PostCheckinRequestResult.m
#import "PostCheckinRequestResult.h"
@implementation PostCheckinRequestResult
- (id) initializeWithDelegate:(id )delegate {
self = [super init];
_postCheckinRequestDelegate = [delegate retain];
return self;
}
/**
* FBRequestDelegate
*/
- (void)request:(FBRequest *)request didLoad:(id)result {
[_postCheckinRequestDelegate postCheckinRequestCompleted];
}
- (void)request:(FBRequest*)request didFailWithError:(NSError*)error {
NSLog(@"Post Checkin Failed:%@", [error localizedDescription]);
[_postCheckinRequestDelegate postCheckinRequestFailed];
}
@end
When the checkin post goes through, the postCheckinRequestCompleted method is called on the PostCheckinRequestDelegate telling you that it worked. Now the user should have no doubt about where she is at the moment!
I have an idea. You thought I’d forget didn’t you? There needs to be an app for checking in with one tap. One tap should be all that’s needed to do the whole checkin process. Our users are busy, flying from place to place after all, so checking in should be QUICK! Since the nearby places result list is returned by Facebook in descending order by proximity, the 1st place on the list might suffice. Or, an algorithm taking into account the user’s most frequented places might be better (but harder to implement).





Programming and design are both my play and my work. I feel like a digital alchemist on most days and look forward to the creative process. I love discovering new ways to apply the magic of technology to complex communication challenges. Most of all, the worlds of technology and design feed my soul!