Post photo on user's wall using Facebook iOS SDK

40,155

Solution 1

It's clearer what you wish to do - post a photo to FB, and guarantee that a post goes on the user's wall/stream.

Unfortunately, there are some things in the way.

FB Graph API appears to only allow you to post EITHER a picture to an album, or post to the wall directly, linking to a picture already existing somewhere on the web. In the first case, a post in the stream will probably be made, but FB appears to consolidate multiple posts in some manner so as to keep the user's stream from being bombarded. The mechanism for this is not documented anywhere I could see.

In the second case, you might think you could get away with posting to an album, and then explicitly posting a link to the album. You can add a parameter to the original album post, "no_story" with a value of 1, and suppress the wall post that might be made while you prepare to make an explicit one. However, FB will not have the source URL for a newly posted image for a while, AND, it doesn't appear to like URLs that include its own content delivery network, returning an error. You might think to simply put status update in the stream, talking about the post, However, the Graph API is also limited to 25 such direct feed posts per day per app, to prevent spamming.

One solution would be to post to something like Flickr, get the URL of the image, and then post to the wall. FB's preferred solution appears to be to use the FB dialogs that are part of the mobile toolkit - essentially little web pages much like the OAuth screen.

Personally, I plan to simply post to the album as above, and live with FB's idea of how the user should be notified. Curious how you choose to proceed.

Solution 2

I did this in three steps

1 post picture to album (returns imageID)

2 use imageID to request metadata for imageID

3 use the 'link' field (not the 'source' field) as a link to the image in a post to the user's wall

The downside is that there are now two posts to the wall, one for the image, and one for the actual post. I haven't figured out yet how to post a picture to an album, without also a wall post appearing (ideally it would just be the 2nd post that appears)

Step 1:

- (void) postImageToFacebook {

    appDelegate = (ScorecardAppDelegate *)[[UIApplication sharedApplication] delegate];

    currentAPICall = kAPIGraphUserPhotosPost;

    UIImage *imgSource = {insert your image here};
    NSString *strMessage = @"This is the photo caption";
    NSMutableDictionary* photosParams = [NSMutableDictionary dictionaryWithObjectsAndKeys:
                                         imgSource,@"source",
                                         strMessage,@"message",
                                         nil];

    [appDelegate.facebook requestWithGraphPath:@"me/photos"
                                     andParams:photosParams
                                 andHttpMethod:@"POST"
                                   andDelegate:self];     

    // after image is posted, get URL for image and then start feed dialog
    // this is done from FBRequestDelegate method
}

Step 2 (kAPIGraphUserPhotosPost) & step 3 (kAPIGraphPhotoData):

- (void)request:(FBRequest *)request didLoad:(id)result {

    if ([result isKindOfClass:[NSArray class]] && ([result count] > 0)) {
        result = [result objectAtIndex:0];
    }

    switch (currentAPICall) {
        case kAPIGraphPhotoData: // step 3
        {
            // Facebook doesn't allow linking to images on fbcdn.net.  So for now use default thumb stored on Picasa
            NSString *thumbURL = kDefaultThumbURL;
            NSString *imageLink = [NSString stringWithFormat:[result objectForKey:@"link"]];    

            currentAPICall = kDialogFeedUser;
            appDelegate = (ScorecardAppDelegate *)[[UIApplication sharedApplication] delegate];


            NSMutableDictionary* dialogParams = [NSMutableDictionary dictionaryWithObjectsAndKeys:
                                     kAppId, @"app_id",
                                     imageLink, @"link",
                                     thumbURL, @"picture",
                                     @"Just Played Wizard etc etc", @"name",
                                     nil];

            [appDelegate.facebook dialog:@"feed" 
                               andParams:dialogParams 
                             andDelegate:self];


            break;
        }
        case kAPIGraphUserPhotosPost: // step 2
        {

            NSString *imageID = [NSString stringWithFormat:[result objectForKey:@"id"]];            
            NSLog(@"id of uploaded screen image %@",imageID);

            currentAPICall = kAPIGraphPhotoData;
            appDelegate = (Scorecard4AppDelegate *)[[UIApplication sharedApplication] delegate];

            [appDelegate.facebook requestWithGraphPath:imageID
                                           andDelegate:self];
            break;
        }
    }
}

I've modified the code to show just the Facebook stuff condensed. If you want to check if the post is successful you'll want something like this:

- (void)dialogDidComplete:(FBDialog *)dialog {
    switch (currentAPICall) {
        case kDialogFeedUser:
        {
            NSLog(@"Feed published successfully.");
            break;
        }
    }
}

facebook post

The blue text in the Facebook post is whatever you put in the "name" parameter in Step 3. Clicking on the blue text in Facebook will take you to the photo posted in Step 1, in an album in Facebook (Facebook creates a default album for your app if you don't specify an album). In my app's case it's the full-sized image of the scorecard (but could be any image, e.g. from the camera). Unfortunately I couldn't figure out a way to make the thumb image a live link, but it's not very readable so a default thumb works in my case. The part in the Facebook post (in black font) that says "First game of the year..." is entered by the user.

Solution 3

I'm not sure what part isn't working for you, since you are posting and getting an ID back, but here is what I did in a quick and dirty way, in case someone reaches here via Google.

This is an HTTP POST function, and the binary data of the file goes up as multipart mime.

I'm a big fan of the ASIHTTPRequest library available here.

**UPDATE: 10/22/2012 ** - AFNetworking has replaced ASIHTTPRequest in my code in the past few months. Available on GitHub here

Facebooks docs are confusing, partly because they are incomplete and partly because they can be wrong. You'll probably tear some hair out figuring out exactly what post value to set for a caption or something, but this recipe puts a photo into an album, and that goes into the feed.

You still need to set up the Facebook OAuth stuff in the basic way - I happened to do that in the app delegate, so I grab the Facebook object from there to get my access token. I made sure to ask for the "publish_stream" permission when I authenticated, like this:

[facebook authorize:[NSArray arrayWithObjects:@"publish_stream", nil] delegate:self];

This will create or add to an album called "YOUR_APP_NAME Photos", and will appear in the user's feed. You can put it in any album, including the "Wall" album, by getting the ID of that album and changing the URL to http://graph.facebook.com/THE_ID_OF_THE_ALBUM/photos.

Here's the basic method:

-(void) postImageToFB:(UIImage *) image
{

    NSData* imageData = UIImageJPEGRepresentation(image, 90);
    Facebook* fb = [(uploadPicAppDelegate *)[[UIApplication sharedApplication] delegate] facebook   ];


    ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:[NSURL URLWithString:@"https://graph.facebook.com/me/photos"]];
    [request addPostValue:[fb accessToken] forKey:@"access_token"];
    [request addPostValue:@"image message" forKey:@"message"];
    [request addData:imageData forKey:@"source"];

    [request setDelegate:self];
    [request startAsynchronous];  
}

Using the Facebook provided iOS library looks like this:

-(void) postImageToFB:(UIImage *) image
{

    NSData* imageData = UIImageJPEGRepresentation(image, 90);
    Facebook* fb = [(uploadPicAppDelegate *)[[UIApplication sharedApplication] delegate] facebook   ];

    NSMutableDictionary * params = [NSMutableDictionary dictionaryWithObjectsAndKeys:[fb accessToken],@"access_token",
                                    @"message text", @"message",
                                    imageData, @"source",
                                    nil];
    [fb requestWithGraphPath:@"me/photos" 
                   andParams:params 
               andHttpMethod:@"POST" 
                 andDelegate:self];


}

Solution 4

Using Facebook SDK 3.0:

 - (void)postPhotoThenOpenGraphAction {
    FBRequestConnection *connection = [[FBRequestConnection alloc] init];

    // First request uploads the photo.
    FBRequest *request1 = [FBRequest 
        requestForUploadPhoto:self.selectedPhoto];
    [connection addRequest:request1
        completionHandler:
        ^(FBRequestConnection *connection, id result, NSError *error) {
            if (!error) {
            }
        }
            batchEntryName:@"photopost"
    ];

    // Second request retrieves photo information for just-created 
    // photo so we can grab its source.
    FBRequest *request2 = [FBRequest 
        requestForGraphPath:@"{result=photopost:$.id}"];
    [connection addRequest:request2
         completionHandler:
        ^(FBRequestConnection *connection, id result, NSError *error) {
            if (!error &&
                result) {
                NSString *source = [result objectForKey:@"source"];
                [self postOpenGraphActionWithPhotoURL:source];
            }
        }
    ];

    [connection start];
}

They follow this post with an OpenGraph action publish ([self postOpenGraphActionWithPhotoURL:source];), but if you just want the image on the user's wall, you wont need that.

More info: https://developers.facebook.com/docs/tutorials/ios-sdk-tutorial/publish-open-graph-story/#step7

Yay!, FB SDK 3.0 rocks! No more AppDelegate.facebook :)

Solution 5

I searched far and wide for a solution that worked on the latest APIs, until I came across this:

http://xcodenoobies.blogspot.co.uk/2012/09/how-to-upload-photo-and-update-status.html

By far the clearest solution I've come across, simple and works with the latest API.

Share:
40,155

Related videos on Youtube

Ben Williams
Author by

Ben Williams

iOS for life!

Updated on July 09, 2022

Comments

  • Ben Williams
    Ben Williams almost 2 years

    I'm trying to upload a photo from the camera to a user's Facebook wall. I'm not entirely sure what the correct strategy is, but from reading around it seems the thing to do is upload the photo to an album, and then someone post on the wall a link to that album/photo. Ideally this would involve the dialog, but from what I can tell that's not possible.

    I've managed to upload a photo to an album, and get back an ID for that photo, but I'm not sure what to do after that.

    Can anyone provide some straightforward code for achieving this?

    Bonus question: Is it possible to post the photo to the application wall, as well (or instead)?

    Edit: Graph API is preferable, but anything that works at this stage is good.

  • Ben Williams
    Ben Williams almost 13 years
    Thanks, to clarify I can get the photo to appear in the user's feed, but only the first photo. Uploading successive photos after that still adds the photo to the album, but it doesn't seem to do anything else to the feed. Does that sound normal?
  • Ben Williams
    Ben Williams almost 13 years
    Also, I gave the ASIFormDataRequest method a go - the image message appears, but name, caption and description don't seem to do anything?
  • giff
    giff almost 13 years
    You are correct - posting a photo appears to only allow the "message" field. I've edited the above.
  • Ben Williams
    Ben Williams almost 13 years
    I think I came to the same conclusion, that posting a photo and having it appear as a wall post just isn't going to work easily, which is surprising. Options are to use an external photo hosting service, or just live with how FaceBook handles it. Since you're curious - I've chosen to just post to the wall without the photo. The important part for me was the actual post, and the photo was just a nice addition. If I did need the photo though, I'd choose to go with posting to an album I think, adding a 3rd party photo host just adds another layer of complexity. Thanks for your help!
  • el.severo
    el.severo over 12 years
    Can you add also result method ?
  • el.severo
    el.severo over 12 years
    Oh, Thanks a lot! I was wondering if you managed to add the picture to default 'Wall Photos' album of the user; searched for couple of examples but I didn't found anything yet...
  • Ben G
    Ben G over 12 years
    Seems like using [result objectForKey:@"picture"] for the thumbURL is working now.
  • Arslan
    Arslan about 12 years
    Thank you dear @EricD'Souza. It worked perfectly fine for me.
  • Arbie Samong
    Arbie Samong almost 12 years
    @PsychoDad Instagram also hosts the images themselves, which they seem to use for the wall post. The image in the album looks to be like a different operation altogether (looks like a side effect but probably a different request)
  • JimmyJammed
    JimmyJammed almost 12 years
    Hi, I am trying to do the same thing, but am having issues with your code. Getting errors for kAPIGraphUserPhotosPost & kAPIGraphPhotoData. Do I need to include something else or set those somewhere? Thanks in advance!
  • Bharat Ahluwalia
    Bharat Ahluwalia over 11 years
    After some looking around, I came to the same conclusion. Overtime I will have a website for the images and at that time I can do a link with the message