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.
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;
}
}
}
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.
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.
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];
}
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 :)
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.
Related
I'm making an app with Facebook login. I get user profile pics the normal way:
https://graph.facebook.com/[USER_ID]/picture?type=large
but one of my test users only has a facebook page, not a facebook profile. His userID shows up as normal, but I only get the silhouette image for him.
Is there a way, ideally parallel to the above method for users, to get the picture associated with a page, given the userID of the page's owner/admin?
EDIT: To clarify, I want to get the publicly-available picture that's in the 'profile pic' UI section for a page, but which isn't associated with any particular user. See https://www.facebook.com/cajitamusic for example.
No, you'd have to ask for permission to access the user's pages first (which could be an extra unwanted threshold to use your app).
I think you can. You can using the same with
https://graph.facebook.com/[PAGE_ID]/picture?type=large
The problem for you seems is how to get object id of the page. You can try search API as it works for me when I try to get city profile picture.
fbPageInfo = [FBRequestConnection startWithGraphPath:[NSString stringWithFormat:#"search?q=%#&type=page",[cityName stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]
completionHandler:^(FBRequestConnection *connection, id result, NSError *error) {
if (!error) {
// Sucess! Include your code to handle the results here
NSLog(#"result: %#", result);
NSArray* pages = (NSArray *)[result data];
if (pages.count > 0) {
NSDictionary *firstCityPage = [pages objectAtIndex:0];
for (NSDictionary *page in pages) {
//NSLog(#"user events: %#", page);
if ([[page objectForKey:#"category"] isEqualToString:#"City"]) {
firstCityPage = page;
break;
}
}
NSString *profileImgUrl = [NSString stringWithFormat:#"http://graph.facebook.com/%#/picture?type=large", [firstCityPage objectForKey:#"id"]];
...
}
} else {
// An error occurred, we need to handle the error
// See: https://developers.facebook.com/docs/ios/errors
// do nothing - user default image
fbPageInfo = nil;
NSLog(#"Can't get image for %#. Error:%#", cityName, [error description]);
}
}];
Also how to get bigger picture you can find it in this answer:
How to get the bigger profile picture of a facebook page
I want to implement location check-in feature in ios. My application is using google+ ios sdk. The problem which I am facing is that after I have implemented google+ check-in feature then that post is not being displayed on my google+ account.
The technique which I have tried and implemented is written below.
-(IBAction)checkIn
{
GTMOAuth2Authentication *auth = [GPPSignIn sharedInstance].authentication;
GTLServicePlus* plusService = [[GTLServicePlus alloc] init] ;
plusService.retryEnabled = YES;
[plusService setAuthorizer:auth];
GTLPlusMoment *moment = [[GTLPlusMoment alloc] init];
moment.type = #"http://schemas.google.com/CheckInActivity";
GTLPlusItemScope *target = [[GTLPlusItemScope alloc] init] ;
target.url =#"https://developers.google.com/+/plugins/snippet/examples/place";
moment.target = target;
GTLQueryPlus *query =
[GTLQueryPlus queryForMomentsInsertWithObject:moment
userId:#"me"
collection:kGTLPlusCollectionVault];
[plusService executeQuery:query
completionHandler:^(GTLServiceTicket *ticket,
id object,
NSError *error) {
if (error) {
GTMLoggerError(#"Error: %#", error);
NSString *failure =
[NSString stringWithFormat:#"Status: Error: %#", error];
NSLog(#"%#",failure);
} else {
NSString *result = #"CheckedIn Saved in Google+";
NSLog(#"%#",result);
}
}];
}
Can any one please help me out. Is this the right way of implementing location check-in feature of google+ or is there any other method for it?
The method you're using is writing an "app activity" to Google+, which stores a "moment" in the user's app activity vault. As noted on https://developers.google.com/+/mobile/ios/app-activities these moments are not directly visible on the user's stream, although users may choose to share them to the stream if they wish.
To see the moments that have been shared, you will need to use the desktop app. Your profile has a list of apps that are using the Google+ Sign-In and you can view, share, and delete the activities for each of these apps. The mobile Google+ clients don't let you view the activities yet.
Can you help me to understand when should I use UIActivityViewController. I have a button which shares common information about my app (something like "I like this app" with link and image). My old code was:
NSMutableDictionary *params = [NSMutableDictionary dictionary];
[params setObject:picture forKey:#"picture"];
[params setObject:link forKey:#"link"];
[params setObject:#"I like MY app!" forKey:#"caption"];
[params setObject:#"I am now using MY iPhone app." forKey:#"description"];
[params setObject:linkToTheIcon forKey:#"icon"];
[params setObject:#"including link" forKey:#"type"];
[[FacebookConnection instance] feedLink:params andDelegate:self];
Now I want to use UIActivityViewController but I'm a bit confused how to pass all those parameters to it. Or should I do things in other way?
ADDED:
So I understood that I need silent posting procedure.
Could you please guide me through silent post procedure using iOS 6 features (e.d. using built-in FB account). For now I can't understand how to check if FB account exists on the device and if it is not how to prompt to create it? There is a method in ACAccount store class – requestAccessToAccountsWithType:options:completion: to access an account. But If an account does not exists it returns an error. Many thanks in advance.
In your situation it seems obvious that you should not use UIActivityViewController because you want to post on Facebook and not on twitter or anywhere else, right?
Firstly you need to get access to user's account. You do this like this:
-(void)requestBasicPermissionsForFacebookAccount {
ACAccountType * facebookAccountType = [self.accountStore accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierFacebook];
NSArray * permissions = #[#"email"];
NSDictionary * options = #{ACFacebookAppIdKey : kFacebookAppId, ACFacebookPermissionsKey : permissions, ACFacebookAudienceKey : ACFacebookAudienceEveryone};
FacebookAccountManager * fbMgr = [[FacebookAccountManager alloc] init];
[self.accountStore requestAccessToAccountsWithType:facebookAccountType options:options completion:^(BOOL granted, NSError *error) {
if (granted) {
NSArray * accounts = [self.accountStore accountsWithAccountType:facebookAccountType];
fbMgr.account = [accounts lastObject];
fbMgr.isBasicPermissionsGranted = YES;
[self.accountManagers addObject:fbMgr];
NSLog(#"granted!");
}
else {
fbMgr.account = nil;
fbMgr.isBasicPermissionsGranted = NO;
switch ([error code]) {
case 1:
[self showErrorAlertWithMessage:#"Unknown error occured, try again later!"];
break;
case 3:
[self showErrorAlertWithMessage:#"Authentication failed, try again later!"];
break;
case 6:
[self showErrorAlertWithMessage:#"Facebook account does not exists. Please create it in Settings and come back!"];
break;
case 7:
[self showErrorAlertWithMessage:#"Permission request failed. You won't be able to share information to Facebook"];
break;
default:
break;
}
NSLog(#"error is: %#", error);
}
}];
}
If an account does not exists you should prompt user to create it in settings and then try to to obtain basic permissions again.
You first need to subclass UIActivity.
Then you need to override certain methods, including activityImage for setting the icon and performActivity for performing the action .
If instead of performing the action silently, you first need further user interaction and info for your custom activity (e.g., like the Twitter post for the standard UIActivity), you should override activityViewController rather than performActivity.
After you have subclassed UIActivity (as, e.g, MyActivity), you should create an instance of MyActivity and make it an element of the applicationActivities array that you pass to initWithActivityItems:applicationActivities:.
Have a look at the documentation for UIActivity for exactly what you need to override when subclassing and for icon requirements.
Hope this helps a little
I am getting an image from facebook by the URL: http://external.ak.fbcdn.net/safe_image.php?d=d282e1e7c86c9270232f97ddc737df39&w=90&h=90&url=http%3A%2F%2Fi52.tinypic.com%2F2q0ixzl.jpg
Now, I want a bigger version, like 200 by 200. Is there a URL for that? If not, how can I convert this image to a larger size?
Generally if you want to collect the profile pic of a user or page, the format for the icon size picture is:
http://graph.facebook.com/[page id/profile id]/picture
and for the large picture:
http://graph.facebook.com/[page id/profile id]/picture?type=large
EDIT Points to note:
If the image stored on the facebook servers is less than the 200*200 dimensions, you would get the image as the highest resolution avaiable eg: 128*160. Either you can resize it using the GD library.
AND ONE MORE THING
Facebook supports 200*600px as the highest resolution for the profile pic. It will resize an image to fit into these dimensions by maintaining the aspect ratio.
*UPDATE as on 19th Feb, 2017 *
We need to use this new URL formation to get a desired profile image.
http://graph.facebook.com/{profile_id}/picture?width={number}&height={number}
[Thank you https://stackoverflow.com/users/2829128/vay]
If you want to get a larger picture you can just set the height and width you want like this:
http://graph.facebook.com/[page id/profile id]/picture?width=[number]&height=[number]
More info and examples here: Pictures - Facebook Developers
this will also work
picture.type(large)
example
if ([FBSDKAccessToken currentAccessToken]) {
[[[FBSDKGraphRequest alloc] initWithGraphPath:#"me" parameters:#{#"fields": #"picture.type(large),name, email"}]
startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) {
if (!error) {
NSLog(#"fetched user:%#", result);
NSMutableDictionary *data=[[NSMutableDictionary alloc]init];
data=result;
fbId.text=[data valueForKey:#"id"];
userName.text=[data valueForKey:#"name"];
_emailFB.text=[data valueForKey:#"email"];
NSDictionary *dictionary = (NSDictionary *)result;
NSDictionary *data3 = [dictionary objectForKey:#"picture"];
NSDictionary *data2 = [data3 objectForKey:#"data"];
NSString *photoUrl = (NSString *)[data2 objectForKey:#"url"];
NSLog(#"Photo : %#",photoUrl);
}
}];
}
}
YES, there is a way to get the original (most of time bigger) profile picture of a facebook page.
Actually the answer is already in the question. The original image url is already embedded in the save_image url. In your case it is "url=http%3A%2F%2Fi52.tinypic.com%2F2q0ixzl.jpg” which means "http://i52.tinypic.com/2q0ixzl.jpg"
In my case, the page for London is
https://www.facebook.com/pages/London-United-Kingdom/106078429431815?fref=ts
I can easily get its fb object id by search keyword London.
I have tried to use width and height parameter. They work with user profile picture or user shared picture but can’t work with public pages profile picture.
https://graph.facebook.com/106078429431815/picture?width=300&height=300 // can’t work
The largest picture I can get it by following url which is only 180x77
https://graph.facebook.com/106078429431815/picture?type=large
But I can get safe_image.php url by using fb graph api, and the original image url is also inside the parameters' url section
"url": "https://fbexternal-a.akamaihd.net/safe_image.php?d=AQCrtKykRotXBuaS&w=180&h=540&url=http%3A%2F%2Fupload.wikimedia.org%2Fwikipedia%2Fcommons%2Fthumb%2Farchive%2F2%2F21%2F20141005220235%2521City_of_London_skyline_at_dusk.jpg%2F720px-City_of_London_skyline_at_dusk.jpg&fallback=hub_city&prefix=d"
Here is code I used.
[FBRequestConnection startWithGraphPath:[NSString stringWithFormat:#"/%#/picture?redirect=false&type=large",[firstCityPage objectForKey:#"id"]]
completionHandler:^(
FBRequestConnection *connection,
id result,
NSError *error
) {
NSString *profileImgUrl = [NSString stringWithFormat:#"http://graph.facebook.com/%#/picture?type=large", [firstCityPage objectForKey:#"id"]];
if (error==nil) {
NSString *fbSaveImgUrl = [[(NSDictionary*)result objectForKey:#"data"] objectForKey:#"url"];
NSURLComponents *urlComponents = [NSURLComponents componentsWithURL:[NSURL URLWithString:fbSaveImgUrl]
resolvingAgainstBaseURL:NO];
for (NSURLQueryItem *queryItem in urlComponents.queryItems) {
if ([queryItem.name isEqualToString:#"url"]) {
profileImgUrl = queryItem.value;
break;
}
}
} else {
NSLog(#"%#",[error description]);
}
NSLog(#"url: %#", profileImgUrl);
...
}];
BUT, there are risks.
No guarantee the external image url will be validate.
Facebook may remove the explicit external url in the safe_image url or hide the safe_image url from developer in future.
Use it at your own risk.
I would like to know how I can fetch friends' profile picture and display them with the Facebook API for iOS
Thanks
One line solution:
https://graph.facebook.com/me/friends?access_token=[oauth_token]&fields=name,id,picture
You can get a list of your friends at this endpoint: https://graph.facebook.com/me/friends. Then, you can get a friend's profile picture at this endpoint: https://graph.facebook.com/[profile_id]/picture.
Be sure to use this SDK: https://github.com/facebook/facebook-iphone-sdk
Hope this helps!
If you use Three20, you can try this extension:
https://github.com/RIKSOF/three20/tree/development/src/extThree20Facebook
It allows you to use all Graph API features with just a few line of code.
for iOS users looking for this, here is what helped me out (using version 5 of the graph, June 2016):
- (void)getUsersFaceBookFriends {
NSDictionary *params = #{#"fields": #"name, id, picture"};
FBSDKGraphRequest *request = [[FBSDKGraphRequest alloc] initWithGraphPath:#"/me/friends" parameters:params HTTPMethod:#"GET"];
[request startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) {
if (!error) {
NSArray * friendList = [result objectForKey:#"data"];
for (NSDictionary * friend in friendList) {
NSLog(#"Friend id: %#", friend[#"id"]);
NSLog(#"Friend name: %#", friend[#"name"]);
NSLog(#"Friend picture: %#", friend[#"picture"]);
}
}
}];
}
this code will get the user's Facebook friends who are also using the app, along with their name, id, and profile photo url.