Powered by Squarespace
Development Blog Archive
CIRCUS BLAST

Test your aiming skills! 

Circus Blast -- 3D Puzzle Shooter. You're a monkey. In a circus. Trying to help the other animals escape, with a cannon!

 

 App. is no longer available. 

SUMO TAP

Enter the dohyou to challenge yourself to a fast pace game of Sumo Tap! Play online with friends, using Bluetooth and post your high scores to Twitter.

 

 App is no longer available.

Wednesday
Dec092009

iPhone Facebook Integration on Rails

One the attractive features of the iPhone is the seamless integration of many essential daily functions in a cool, shiny package: your photos, your music, your email, your games and your social network – all in the palm of your hand. From the start, we wanted to take advantage of social networks in our applications and launched with two essentials: email and Facebook. Some have said Facebook is the new email, but from a user experience the difference is the social graph of Facebook is built-in and we wanted to leverage this. For us, this meant using your Facebook photo in our app as well as listing the high-scores of your Friends. This means both iPhone app and Rails server app integration with Facebook.

The user experience on the iPhone app needed to be seamless. You can simply click on this “Connect with Facebook” button in the settings screen and log into Facebook to grab your photo:

Also, when showing the top scores of your Facebook friends we wanted this to be seamless:

First, the system diagram. We need to use the iPhone app to register with Facebook Connect API to grab the user Facebook ID (fb_uid). With this, we can grab the Facebook user photo within the iPhone app. But to check the high scores of your Facebook friends, we needed to run a query on the Rails server to see which of your friends are also registered users of Play-N-Give. To do this, we needed to enable Facebook Connect on Rails. This allows us to use the same XML based global leader board view mechanism described earlier – and should offer a better user experience given the slow response time of the Facebook API and the asynchronous XML parsing support in the iPhone app.

We need to register our app with Facebook to get the Facebook Connect API keys, and then we can make a request for the users Facebook photo by implementing the method in our UIViewController:

 1.// FBSessionDelegate
 2. 
 3.- (void)session:(FBSession*)session didLogin:(FBUID)uid {
 4. //! Facebook session didLogin delegate, handle the login
 5.             
 6. fb_uid = [[NSString stringWithFormat:@"%lld", session.uid] retain];
 7.             
 8. NSString* fql = [NSString stringWithFormat:
 9.   @"select uid,name,pic_square_with_logo from user where uid == %lld"
 10.   , session.uid];
 11.             
 12. NSDictionary* params = [NSDictionary dictionaryWithObject:fql forKey:@"query"];
 13. [[FBRequest requestWithDelegate:self] call:@"facebook.fql.query" params:params];
 14.}

Line #3 is the FBSession delegate which is called after the user successfully logs into Facebook Connect. We make an SQL query to the Facebook Connect API in line #8 to obtain the users photo. Later, we parse the results of the query in a request: didLoad: method:

 1.- (void)request:(FBRequest*)request didLoad:(id)result {
 2. //! Facebook session request didLoad delegate, parse the response
 3. NSArray* users = result;
 4. NSDictionary* user = [users objectAtIndex:0];
 5. NSString* pic = [user objectForKey:@"pic_square_with_logo"];
 6. NSData *receivedData = [NSData dataWithContentsOfURL:[NSURL URLWithString:pic]];
 7. image = [[UIImage alloc] initWithData:receivedData];  // Do something with the image
 8. [_session logout];
 9.}

When we’re ready to view the top scores of our Facebook friends we implement an session: didLogin: method to request the XML data from the Rails server:

 1.- (void)session:(FBSession*)session didLogin:(FBUID)uid {
 2. //! Facebook session didLogin delegate, handle the login
 3.    stringWithFormat:@"%@/Facebook/%@.xml?fbsession=%@",feedURLString,customerID,session.sessionKey];
 4.    [NSThread detachNewThreadSelector:@selector(getCustomerFB:) toTarget:self withObject:url];
 5.}

Note that in line #26 we pass the Facebook sessionkey to the Rails server in order to authenticate the server side query.

This triggers a controller on the Rails server to poll the Facebook Connect API and generate a list of Friends, their photos and their scores. The resulting data is rendered in XML and parsed by the asynchronous XMLparser on the iPhone:

 1.def fcbk(method, params={})
 2.  params.merge! :method => "facebook.#{method}", :v => "1.0", :call_id => Time.now.to_f.to_s, :api_key => API_KEY
 3.  params[:sig] = Digest::MD5.hexdigest(params.inject([]) { |args, pair| args << pair.join('=') }.sort.join + API_SECRET)
 4.  result,data = Net::HTTP.post_form(URI.parse('http://api.facebook.com/restserver.php'), params)
 5.  return data
 6.end
 7. 
 8.  ##--- Method to display top 50 Facebook friend's scores
 9.  # GET /Facebook/1.xml
 10.  def Facebook
 11.    @scores = []
 12.    if !Customer.find(params[:id]).fb_uid.nil?
 13.     if !params[:fbsession].nil?
 14.      data = fcbk("fql.query", {:session_key => params[:fbsession], :query => "select uid2 from friend where uid1 = #{Customer.find(params[:id]).fb_uid}"})
 15.      doc = REXML::Document.new( data )
 16.      root = doc.root
 17.      if root.elements['error_code'].nil?
 18.       root.elements.each('friend_info/uid2') do |element|
 19.       data = fcbk("fql.query", :query => "select name,pic_square_with_logo,is_app_user from user where uid = #{element.text}")
 20.       doc = REXML::Document.new( data )
 21.       root = doc.root
 22.       cust = Customer.find(:first, :conditions => { :fb_uid => element.text })
 23.       @top50 = [{:name => root.elements['user/name'].text, :image => root.elements['user/pic_square_with_logo'].text, :points => totalPoints}]
 24.       @scores = @scores + @top50
 25.      end
 26.     else
 27.      @scores = [{:error_code => 1, :error => 'No uid, customer has not registered Facebook account'}]
 28.     end
 29.    respond_to do |format|
 30.      format.html # index.html.erb
 31.      format.xml  { render :xml => @scores.to_xml(:root=>'customers', :child => 'customer') }
 32.    end
 33.  end

The tricky part is incorporating the Facebook photos of the users friends in the top scores list displayed on the iPhone rather than just listing names. The call to the Facebook API on line #32 only returns the URL of the Facebook photo, so we actually need to make an asynchronous call to load the image on the iPhone. We could have used the Rails server to send back a uuencoded image but it was actually easier to use the iPhone SDK [NSData dataWithContentsOfURL:] method!

We also need to ensure each user registers their Facebook ID (fb_uid) with Play-N-Give so that we can do the necessary lookup. We enforce this loosely by suggesting that if the user wants to use their Facebook photo they need to register with our server. Again, our Privacy Policy is clearly posted.

So that’s how we enabled Facebook integration within our iPhone app using Rails.

--yarri