Facebook SDK for Android meets link sharing (and querying)

Facebook SDK for Android does a pretty good job of providing Facebook support for your app. However, SDK doesen’t give you a direct way to do stuff that web users find trivial. Link sharing and link querying being two of them.

Sharing a link actually means posting a link to your wall. Keep in mind that posting a link is different from posting a status with a link attached. Posting a link brings much more value then just attaching it to a wall post, key value being the link statistics. Some of the statistics gathered for a shared link (available via Facebook Query Language) are the number of times someone shared a link, liked a link, commented on a link, etc.

Facebook explained link posting in the old REST API docs
but for some reasong its not quite clear in Graph API docs. Graph API docs claim that links are posted through http://graph.facebook.com/me/feed which is IMO wrong since this url is used for wall posts.

We know that reading and posting wall statuses is done via GET, POST and DELETE requests to http://graph.facebook.com/me/feed. Links are managed the same way but through the link url: http://graph.facebook.com/me/links !

Now that we know how to post links, we should take a look at the metadata Facebook allows us to post with a link. It seems again that the old REST API docs are more correct then Graph API docs since the later will lead you into believing you have a lot of options. But you actually don’t. After playing with Graph API it turns out all you can post with a link is a comment and an image. All other information, e.g. link title, subtitle etc. are fetched by Facebook from the link you shared.

It’s hard to say for sure since Facebook changes things pretty dynamically, but my gut feeling is that Graph API docs on link sharing are just plain wrong.

Finally getting to the code, easiest road to take is to reuse the wall posting code. If you ever took a glimpse into the SDK you’ll find the classes familiar. Notice that we just replaced me/feed with me/links and we are set to go.

AsyncFacebookRunner fbRunner = new AsyncFacebookRunner(mFacebook);
fbRunner.request("me/links", params, "POST",
     new GraphAPIRequestListener() {
   @Override
   public void onRequestCompleted(final JSONObject response,
     final Object state) {
     // Do your stuff here.
   }
   @Override
   public void onRequestFailed(final String response) {
    // Do your stuff here.
   }
  }, null);

Don’t be confused by the GraphAPIRequestListener. It’s still the RequestListener from AsyncFacebookRunner but I like the new name better ;-)

The more fun part is getting some information about a link. Naturally, FQL is the way to go, but the SDK so far has no FQL support. Luckily, executing an FQL query is nothing more then a plain GET. So we can still reuse most of the SDK stuff, with some minor adjustments to make up for the fact that FQL requests aren’t handled by the Graph API (on which the SDK is based).

AsyncFacebookRunner fbRunner = new AsyncFacebookRunner(mFacebook);
fbRunner.runFQLQuery(FQLQueryGenerator.getLinkStatsQuery(),
    new FQLRequestListener() {
      @Override
      public void onFQLRequestCompleted(final JSONArray response,
        final Object state) {
        // Do your stuff here.
      }
      @Override
      public void onRequestFailed(final String response) {
        // Do your stuff here.
      }
   }, null);
}

What happens in the AsyncFacebookRunner?

public final void runFQLQuery(String query,
RequestListener listener, Object state) {
new Thread() {
@Override public void run() {
try {
    String response = mFacebook.executeFQLQuery(query);
    listener.onComplete(response , state);
} catch (FileNotFoundException e) {
    listener.onFileNotFoundException(e, state);
} catch (MalformedURLException e) {
    listener.onMalformedURLException(e, state);
} catch (IOException e) {
    listener.onIOException(e, state);
} catch (Exception e) {
    listener.onException(e, state);
}
}
}.start();
}

Finally, how Facebook object handles the request?

public final String executeFQLQuery(String query)
  throws FileNotFoundException, MalformedURLException, IOException {
     Bundle params = new Bundle();
     params.putString("format", "json");
     params.putString("query", query);
     if (isSessionValid()) {
        params.putString(TOKEN, getAccessToken());
     }
        String baseUrl = "https://api.facebook.com/method/fql.query";
        return Util.openUrl(baseUrl, "GET", params);
}

After playing with the SDK, FQL and studying the documentation all this looks pretty simple. In fact so simple that a developer might get bold enough to create a native share widget ;-)