Include Facebook „Post to your wall“ in your App

I’m somhow a newbee in developing iPhone-Apps. This means a lot of searching in iNet, try-and-error and „throwning the mac out of the window“…

My task was to implement social networks in my app.
Twitter: 15 minutes
Mail: 2 hours
Facebook: 8 days (!!)

The examples from facebook, which are delivered with their framework, are somehow really good, but they do to much things for me. I only wanted to post to the users wall, nothing more. So I took the code from their samples, include them in my app -> DAMN, nothing works anymore.Then I searched a lot for other examples, and they all are good, if you want to see friend lists, post fotos or other things to the wall and the newsfeed, but a simple Wall-Post was not included their.

Other frameworks like ShareKit are also doing to much for me, so I started to try it on my own. I took the „Hackbook“-Example from facebook and reduces the functionality of it to what I only want to have: login, authorizise the app at your facebook account and post to the wall.

Afterwards I took this rest of code and implement it in my own app. But it was really a tie: The reduced example project worked exactly like I want but the same code in my app had two big problems:

  1. The app did not store the successfully authorization. After I stop the app and call it again, the authorization screen was shown again.
  2. After the authorization process the „Post to Wall“ Popup was not opening. I had to call it manually again.

The problem was, that the Facebook example uses only one UIViewController as RootViewController in the AppDelegate. In my own App I am using a UITabBarController, which means, all Events must pass the TabBarController over the including NavigationController to to ViewController and somewhere there are „lost in space“.

Then I took a look to the Source Code from other Frameworks how they have done it there and afterward I married the results with the reduced Hackbook example and now it works fine.

If anybody else has a problem like I had, I will post my results here to help you maybe.

Download the FacebookSDK.framework from Facebook: I’m using the version 3.0.8

Include the facbookSDK.framework in your „Link Binary With Libaries“ part.

Drag the FacebookSDK.framework/Versions/A/DeprecatedHeaders folder to the Frameworks section of your app. Important: Choose ‚Create groups for any added folders‘ and deselect ‚Copy items into destination group’s folder (if needed)‘. This adds the headers as a reference.

Import FBConnect.h to your AppDelegate.h and all ViewControllers (.h and .m), where you want to implement the share button.

#import "FBConnect.h"

create an configuration.h file, which you can include in all .m files where you want to implement the share button. Here define the enum for the apiCall events:


typedef enum apiCall {
} apiCall;

In your AppDelegate.h, define local and public variables for Facebook and userPermissions.


@interface AppDelegate : NSObject <UIApplicationDelegate, UITabBarControllerDelegate, UINavigationControllerDelegate> {
    UIWindow *window; // The main Window of the application
    UITabBarController *myTabBarController; // the tab bar controller is the root view controller of the app
    Facebook *facebook;
    NSMutableDictionary *userPermissions;
 @property (nonatomic, retain) IBOutlet UIWindow *window;
@property (nonatomic, retain) IBOutlet UITabBarController *myTabBarController;
@property (nonatomic, retain) Facebook *facebook;
@property (nonatomic, retain) NSMutableDictionary *userPermissions;
 + (Facebook *)sharedInstance;

Also define the class method sharedInstance for creating a Singleton of Facebook.

In your AppDelegate.m, define the Facebook AppID and initialize the facebook instance with the singleton.


static NSString* kAppId = @"236618989793547";
@implementation AppDelegate
 @synthesize window, myTabBarController, facebook, userPermissions;
 + (Facebook *)sharedInstance {
    static Facebook *gFacebook = NULL;
    @synchronized(self) {
        if (gFacebook == NULL)
            gFacebook = [[Facebook alloc] initWithAppId:kAppId andDelegate:[[ViewController alloc] initWithIndex:2]];
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    facebook = (Facebook *) [AppDelegate sharedInstance];
    // Check and retrieve authorization information
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    if ([defaults objectForKey:@"FBAccessTokenKey"] && [defaults objectForKey:@"FBExpirationDateKey"]) {
        facebook.accessToken = [defaults objectForKey:@"FBAccessTokenKey"];
        facebook.expirationDate = [defaults objectForKey:@"FBExpirationDateKey"];
    userPermissions = [[NSMutableDictionary alloc] initWithCapacity:1];
    // Check App ID:
    // This is really a warning for the developer, this should not happen in a completed app
    if (!kAppId) {
        UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Setup Error" message:@"Missing app ID. You cannot run the app until you provide this in the code." delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil, nil];
        [alertView show];
        [alertView release];
    } else {
        // Now check that the URL scheme fb[app_id]://authorize is in the .plist and can
        // be opened, doing a simple check without local app id factored in here
        NSString *url = [NSString stringWithFormat:@"fb%@://authorize",kAppId];
        BOOL bSchemeInPlist = NO; // find out if the sceme is in the plist file.
        NSArray* aBundleURLTypes = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleURLTypes"];
        if ([aBundleURLTypes isKindOfClass:[NSArray class]] &&
            ([aBundleURLTypes count] > 0)) {
            NSDictionary* aBundleURLTypes0 = [aBundleURLTypes objectAtIndex:0];
            if ([aBundleURLTypes0 isKindOfClass:[NSDictionary class]]) {
                NSArray* aBundleURLSchemes = [aBundleURLTypes0 objectForKey:@"CFBundleURLSchemes"];
                if ([aBundleURLSchemes isKindOfClass:[NSArray class]] &&
                    ([aBundleURLSchemes count] > 0)) {
                    NSString *scheme = [aBundleURLSchemes objectAtIndex:0];
                    if ([scheme isKindOfClass:[NSString class]] &&
                        [url hasPrefix:scheme]) {
                        bSchemeInPlist = YES;
        // Check if the authorization callback will work
        BOOL bCanOpenUrl = [[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString: url]];
        if (!bSchemeInPlist || !bCanOpenUrl) {
            UIAlertView *alertView = [[UIAlertView alloc]  initWithTitle:@"Setup Error" message:@"Invalid or missing URL scheme. You cannot run the app until you set up a valid URL scheme in your .plist." delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil, nil];
            [alertView show];
            [alertView release];
    // .... Do whatever your app should do
- (void)applicationDidBecomeActive:(UIApplication *)application {
    // Although the SDK attempts to refresh its access tokens when it makes API calls,
    // it's a good practice to refresh the access token also when the app becomes active.
    // This gives apps that seldom make api calls a higher chance of having a non expired
    // access token.
    [[self facebook] extendAccessTokenIfNeeded];
- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url {
    return [self.facebook handleOpenURL:url];
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
    return [self.facebook handleOpenURL:url];
- (void)dealloc {
[window release];
    [facebook release];
    [userPermissions release];
    [super dealloc];

The ViewControllers .h files needs to implement now the Facebook Delegation methods and a lot of needed variables, which I copied from the Hackbook example:

#import "FBConnect.h"
@interface ViewController : UITableViewController <FBDialogDelegate, FBSessionDelegate, FBRequestDelegate> {
    int currentAPICall;
    NSUInteger childIndex;
    NSMutableArray *apiMenuItems;
    NSString *apiHeader;
    NSMutableArray *savedAPIResult;
    UIActivityIndicatorView *activityIndicator;
    UILabel *messageLabel;
    UIView *messageView;
    NSArray *permissions;
@property (nonatomic, retain) AppDelegate *appDelegate; // include appDelegate to read global variables
@property (nonatomic, retain) NSMutableArray *apiMenuItems;
@property (nonatomic, retain) NSString *apiHeader;
@property (nonatomic, retain) NSMutableArray *savedAPIResult;
@property (nonatomic, retain) UIActivityIndicatorView *activityIndicator;
@property (nonatomic, retain) UILabel *messageLabel;
@property (nonatomic, retain) UIView *messageView;
@property (nonatomic, retain) NSArray *permissions;
- (id)initWithIndex:(NSUInteger)index;


At last TODO, the .m files of the viewControllers must code the needed Methods, to call the facebook SDK correctly.


#import "FBConnect.h"
@implementation ViewController
@synthesize appDelegate, apiHeader, apiMenuItems, savedAPIResult, activityIndicator, messageView, messageLabel, permissions;
- (id)initWithIndex:(NSUInteger)index {
    self = [super init];
    if (self) {
        childIndex = index;
        savedAPIResult = [[NSMutableArray alloc] initWithCapacity:1];
    return self;
- (void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];
    // Hide the activitiy indicator
    [self hideActivityIndicator];
    // Hide the message.
    [self hideMessage];
- (void)dealloc {
    [permissions release];
    [apiMenuItems release];
    [apiHeader release];
    [savedAPIResult release];
    [activityIndicator release];
    [messageLabel release];
    [messageView release];
[super dealloc];
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
    // Activity Indicator
    int xPosition = (self.view.bounds.size.width / 2.0) - 15.0;
    int yPosition = (self.view.bounds.size.height / 2.0) - 15.0;
    activityIndicator = [[UIActivityIndicatorView alloc] initWithFrame:CGRectMake(xPosition, yPosition, 30, 30)];
    activityIndicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyleGray;
    [self.view addSubview:activityIndicator];
    // Message Label for showing confirmation and status messages
    CGFloat yLabelViewOffset = self.view.bounds.size.height-self.navigationController.navigationBar.frame.size.height-30;
    messageView = [[UIView alloc] initWithFrame:CGRectMake(0, yLabelViewOffset, self.view.bounds.size.width, 30)];
    messageView.backgroundColor = [UIColor lightGrayColor];
    UIView *messageInsetView = [[UIView alloc] initWithFrame:CGRectMake(1, 1, self.view.bounds.size.width-1, 28)];
    messageInsetView.backgroundColor = [UIColor colorWithRed:255.0/255.0 green:248.0/255.0 blue:228.0/255.0 alpha:1];
    messageLabel = [[UILabel alloc]
                    initWithFrame:CGRectMake(4, 1, self.view.bounds.size.width-10, 26)];
    messageLabel.text = @"";
    messageLabel.font = [UIFont fontWithName:@"Helvetica" size:14.0];
    messageLabel.backgroundColor = [UIColor colorWithRed:255.0/255.0 green:248.0/255.0 blue:228.0/255.0 alpha:0.6];
    [messageInsetView addSubview:messageLabel];
    [messageView addSubview:messageInsetView];
    [messageInsetView release];
    messageView.hidden = YES;
    [self.view addSubview:messageView];
- (void)facebookButtonClicked {
    if (![(Facebook *) [AppDelegate sharedInstance]  isSessionValid]) {
        permissions = [[NSArray alloc] initWithObjects:@"publish_stream",@"offline_access", nil];
        [(Facebook *) [AppDelegate sharedInstance] authorize:permissions];
        // News Feed, NEEDED PART OF THE DataSet.m FILE
        NSDictionary *newsMenu1 = [[NSDictionary alloc] initWithObjectsAndKeys: @"Publish to the user's wall", @"title", @"This allows a user to post something to their own Wall, which means it will also appear in all of their friends' News Feeds on Facebook.", @"description", @"Publish to your wall", @"button", @"apiDialogFeedUser", @"method", nil];
        NSArray *newsMenuItems = [[NSArray alloc] initWithObjects: newsMenu1, nil];
        NSDictionary *newsConfigData = [[NSDictionary alloc] initWithObjectsAndKeys: @"News Feed", @"title", @"Your app can prompt users to share on their own wall or their friend's wall.", @"description", @"", @"link", newsMenuItems, @"menu", nil];
        apiMenuItems = [[NSArray arrayWithArray:[newsConfigData objectForKey:@"menu"]] retain];
        apiHeader = [[newsConfigData objectForKey:@"description"] retain];
        [(Facebook *) [AppDelegate sharedInstance]  authorize:permissions];
    } else {
        [self apiButtonClicked];  
#pragma mark
#pragma Facebook functionality
- (void)didReceiveMemoryWarning {
    // Releases the view if it doesn't have a superview.
    [super didReceiveMemoryWarning];
    // Release any cached data, images, etc that aren't in use.
#pragma mark - Private Helper Methods
 * This method shows the activity indicator and
 * deactivates the table to avoid user input.
- (void)showActivityIndicator {
    if (![activityIndicator isAnimating]) {
        [activityIndicator startAnimating];
 * This method hides the activity indicator
 * and enables user interaction once more.
- (void)hideActivityIndicator {
    if ([activityIndicator isAnimating]) {
        [activityIndicator stopAnimating];
 * This method is used to display API confirmation and
 * error messages to the user.
- (void)showMessage:(NSString *)message {
    CGRect labelFrame = messageView.frame;
    labelFrame.origin.y = [UIScreen mainScreen].bounds.size.height - self.navigationController.navigationBar.frame.size.height - 20;
    messageView.frame = labelFrame;
    messageLabel.text = message;
    messageView.hidden = NO;
    // Use animation to show the message from the bottom then
    // hide it.
    [UIView animateWithDuration:0.5 delay:1.0 options: UIViewAnimationCurveEaseOut animations:^{
        CGRect labelFrame = messageView.frame;
        labelFrame.origin.y -= labelFrame.size.height;
        messageView.frame = labelFrame;
            completion:^(BOOL finished){
                if (finished) {
                    [UIView animateWithDuration:0.5 delay:3.0 options: UIViewAnimationCurveEaseOut animations:^{
                        CGRect labelFrame = messageView.frame;
                        labelFrame.origin.y += messageView.frame.size.height;
                        messageView.frame = labelFrame;
            completion:^(BOOL finished){
                if (finished) {
                    messageView.hidden = YES;
                    messageLabel.text = @"";
 * This method hides the message, only needed if view closed
 * and animation still going on.
- (void)hideMessage {
    messageView.hidden = YES;
    messageLabel.text = @"";
 * Helper method called when a button is clicked
- (void)apiButtonClicked {
    /*SEL selector = NSSelectorFromString([[apiMenuItems objectAtIndex:0] objectForKey:@"method"]);
    if ([self respondsToSelector:selector]) {
        [self performSelector:selector];
    [self apiDialogFeedUser];
 * Helper method to parse URL query parameters
- (NSDictionary *)parseURLParams:(NSString *)query {
NSArray *pairs = [query componentsSeparatedByString:@"&"];
NSMutableDictionary *params = [[[NSMutableDictionary alloc] init] autorelease];
for (NSString *pair in pairs) {
NSArray *kv = [pair componentsSeparatedByString:@"="];
NSString *val =  [[kv objectAtIndex:1] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
[params setObject:val forKey:[kv objectAtIndex:0]];
    return params;
 * --------------------------------------------------------------------------
 * News Feed
 * --------------------------------------------------------------------------
 * Dialog: Feed for the user
- (void)apiDialogFeedUser {
    currentAPICall = kDialogFeedUser;
    SBJSON *jsonWriter = [[SBJSON new] autorelease];
    // The action links to be shown with the post in the feed
    NSArray* actionLinks = [NSArray arrayWithObjects:[NSDictionary dictionaryWithObjectsAndKeys: @"Get Started",@"name",@"http://Link to the App",@"link", nil], nil];
    NSString *actionLinksStr = [jsonWriter stringWithObject:actionLinks];
    // Dialog parameters
    NSMutableDictionary *params = [NSMutableDictionary dictionaryWithObjectsAndKeys:
                                   @"Name of the Page", @"name",
                                   @"Subtitle of the page", @"caption",
                                   @"Description of the Page", @"description",
                                   @"Link of the page", @"link",
                                   @"Link to Image", @"picture",
                                   actionLinksStr, @"actions",
    [(Facebook *) [AppDelegate sharedInstance] dialog:@"feed" andParams:params andDelegate:self];
#pragma mark - FBSessionDelegate Methods
- (void)fbDidLogin {
    [self storeAuthData:[(Facebook *) [AppDelegate sharedInstance]  accessToken] expiresAt:[(Facebook *) [AppDelegate sharedInstance]  expirationDate]];
    [self userDidGrantPermission];
    [self apiButtonClicked];
-(void)fbDidExtendToken:(NSString *)accessToken expiresAt:(NSDate *)expiresAt {
    [self storeAuthData:accessToken expiresAt:expiresAt];
-(void)fbDidNotLogin:(BOOL)cancelled {
- (void)fbDidLogout {
- (void)fbSessionInvalidated {
- (void)storeAuthData:(NSString *)accessToken expiresAt:(NSDate *)expiresAt {
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    [defaults setObject:accessToken forKey:@"FBAccessTokenKey"];
    [defaults setObject:expiresAt forKey:@"FBExpirationDateKey"];
    [defaults synchronize];
 * Called when the user granted additional permissions.
- (void)userDidGrantPermission {
    [self updateCheckinPermissions];
    [self apiGraphUserCheckins];
- (void)updateCheckinPermissions {
    [[appDelegate userPermissions] setObject:@"1" forKey:@"user_checkins"];
    [[appDelegate userPermissions] setObject:@"1" forKey:@"publish_checkins"];
 * Graph API: Get the user's check-ins
- (void)apiGraphUserCheckins {
    [self showActivityIndicator];
    currentAPICall = kAPIGraphUserCheckins;
    [(Facebook *) [AppDelegate sharedInstance]  requestWithGraphPath:@"me/checkins" andDelegate:self];
#pragma mark - FBDialogDelegate Methods
 * Called when a UIServer Dialog successfully return. Using this callback
 * instead of dialogDidComplete: to properly handle successful shares/sends
 * that return ID data back.
- (void)dialogCompleteWithUrl:(NSURL *)url {
    if (![url query]) {
        NSLog(@"User canceled dialog or there was an error");
    NSDictionary *params = [self parseURLParams:[url query]];
    switch (currentAPICall) {
        case kDialogFeedUser:
        case kDialogFeedFriend:
            // Successful posts return a post_id
            if ([params valueForKey:@"post_id"]) {
                [self showMessage:@"Published feed successfully."];
                NSLog(@"Feed post ID: %@", [params valueForKey:@"post_id"]);
        case kDialogRequestsSendToMany:
        case kDialogRequestsSendToSelect:
        case kDialogRequestsSendToTarget:
            // Successful requests return one or more request_ids.
            // Get any request IDs, will be in the URL in the form
            // request_ids[0]=1001316103543&request_ids[1]=10100303657380180
            NSMutableArray *requestIDs = [[[NSMutableArray alloc] init] autorelease];
            for (NSString *paramKey in params) {
                if ([paramKey hasPrefix:@"request_ids"]) {
                    [requestIDs addObject:[params objectForKey:paramKey]];
            if ([requestIDs count] > 0) {
                [self showMessage:@"Sent request successfully."];
                NSLog(@"Request ID(s): %@", requestIDs);
- (void)dialogDidNotComplete:(FBDialog *)dialog {
    NSLog(@"Dialog dismissed.");
- (void)dialog:(FBDialog*)dialog didFailWithError:(NSError *)error {
    NSLog(@"Error message: %@", [[error userInfo] objectForKey:@"error_msg"]);
    [self showMessage:@"Oops, something went haywire."];

Now everything works like it should.






Print Friendly, PDF & Email

One thought on “Include Facebook „Post to your wall“ in your App

Leave a Comment

Deine E-Mail-Adresse wird nicht veröffentlicht.