How can I upload a photo to facebook from an iOS app using their new API/SDK? I've already tried and I'm not getting anywhere, just keep running in circles. Here is the code I currently have:
-(void)dataForFaceboo{
self.postParams =
[[NSMutableDictionary alloc] initWithObjectsAndKeys:
self.uploadPhoto.image, #"picture", nil];
}
-(void)uploadToFacebook{
[self dataForFacebook];
NSLog(#"Going to facebook: %#", self.postParams);
// Hide keyboard if showing when button clicked
if ([self.photoCaption isFirstResponder]) {
[self.photoCaption resignFirstResponder];
}
// Add user message parameter if user filled it in
if (![self.photoCaption.text
isEqualToString:kPlaceholderPostMessage] &&
![self.photoCaption.text isEqualToString:#""])
{
[self.postParams setObject:self.photoCaption.text forKey:#"message"];
}
[FBRequestConnection startWithGraphPath:#"me/feed"
parameters:self.postParams
HTTPMethod:#"POST"
completionHandler:^(FBRequestConnection *connection,
id result,
NSError *error)
{
NSString *alertText;
if (error) {
alertText = [NSString stringWithFormat:
#"error: domain = %#, code = %d",
error.domain, error.code];
} else {
alertText = [NSString stringWithFormat:
#"Posted action, id: %#",
[result objectForKey:#"id"]];
}
// Show the result in an alert
[[[UIAlertView alloc] initWithTitle:#"Result"
message:alertText
delegate:self
cancelButtonTitle:#"OK!"
otherButtonTitles:nil] show];
}];
}
Your code is fine, some slight changes to be done:
add the image to the dictionary in NSData format, like
[params setObject:UIImagePNGRepresentation(_image) forKey:#"picture"];
and change the graph path to "me/photos" instead of "me/feed"
Make these changes, it worked for me.
Remember you need to use "publish_actions" permissions.
"me/photos" is meant for the photo actually be in the "Photo's" list on your Facebook profile. "me/feed" is just a post on the timeline.
Related
I'm building an app that is using the Instagram API to display photos but I'm running into some trouble. The app is crashing when there is no network connection and I have found the code that is causing the problem.
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
self.accessToken = [userDefaults objectForKey:#"accessToken"];
if (self.accessToken == nil) {
[SimpleAuth authorize:#"instagram" options:#{#"scope": #[#"likes"]} completion:^(NSDictionary *responseObject, NSError *error) {
self.accessToken = responseObject[#"credentials"][#"token"];
[userDefaults setObject:self.accessToken forKey:#"accessToken"];
[userDefaults synchronize];
[self refresh];
}];
} else {
[self refresh];
}
I have found that the [self refresh]; is causing the problem in the else block and I tried to replace it with a alert view like this
UIAlertView *networkError = [[UIAlertView alloc] initWithTitle:#"Network Error" message:#"Please connect your device to a network and restart application" delegate:nil cancelButtonTitle:nil otherButtonTitles:nil];
[networkError show];
However, with this problem I find that if I open the app with a network connection I still get the alert. Any help would be great because I'm still new to Objective C!
Thank you for the help!
I know this code from Treehouse :).
The thing is that the if (self.accessToken == nil) { /.../ } block will only get execute when the app is not authorized using your Instagram credentials.
Once you logged in successfully, it will always execute the code in the else { /.../ } block. If it has connection to Internet, it will do its work, download, display images etc. If you insert the code to display alert, it will always do that because you actually mean that by that code.
If you want to check if there is some connection, you need to do that before all that code, display an error and return instantly if connection is not available. However, the author tried to keep things simple, assuming there is always Internet connection.
Hope it makes you understand it.
This is the some code you can use for checking if there is connection:
// show some activity indicator
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
// Do something...
[[UIApplication sharedApplication] beginIgnoringInteractionEvents];
NSURL *url = [NSURL URLWithString:#"http://www.apple.com/"];
NSString *s = [NSString stringWithContentsOfURL:url
encoding:NSUTF8StringEncoding
error:nil];
dispatch_async(dispatch_get_main_queue(), ^{
// hide the activity indicator
self.connected = (s != nil);
[[UIApplication sharedApplication] endIgnoringInteractionEvents];
if (self.isConnected)
{
NSLog(#"self.connected == YES");
}
else
{
NSLog(#"self.connected == NO");
NSString *alertMessage = #"In order to load images, you need an active Internet connection. Please try again later!";
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Sorry!"
message:alertMessage
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
}
});
});
You obviously need to add a property to you class. You can insert this code:
#interface LDPhotosViewController ()
#property (nonatomic, copy, getter = isConnected) NSString *connected;
#end
at the top of LDPhotosViewController.m file, before the #implementation line.
I am making a call to twitters API to load some tweets for a specific section of my app.
A small chunk of users are reporting a crash when loading the tweets view, while the rest have no problem at all.
I have submitted the code to Apple Tech Support and they responded letting me know that NSJSONSerialization can sometimes return a NSArray or NSDictionary.
Obviously it will throw an error is objectAtIndex: is called on an NSDictionary object, which I believe is the culprit for all of my users.
The partial solution is to detect if it is an Array or NSDictionary.
Here is where I am at now:
id feedData = [NSJSONSerialization JSONObjectWithData:responseData options:0 error:&jsonError];
if ([feedData isKindOfClass:[NSArray class]]) {
//Is array
} else if ([feedData isKindOfClass:[NSDictionary class]]) {
//is dictionary
}
I basically need an NSArray every single time. So in the is array block, I basically just use the feedData, but in NSDictionary, how can I convert it to an NSArray that will match the structure I need.
Honestly the biggest issue is that I cannot see what the NSDictionary structure looks like because none of my testing devices or simulator return the NSDictionary data, they all return an NSArray.
Here is what the entire getUserFeed method that sends the request to twitter looks like:
// Get the twitter feed
NSURL *requestURL = [NSURL URLWithString:TW_API_TIMELINE];
// Set up proper parameters
NSMutableDictionary *timelineParameters = [[NSMutableDictionary alloc] init];
[timelineParameters setObject:kNumTweets forKey:#"count"];
[timelineParameters setObject:#"1" forKey:#"include_entities"];
// Create the Social Request
SLRequest *postRequest = [SLRequest requestForServiceType:SLServiceTypeTwitter requestMethod:SLRequestMethodGET URL:requestURL parameters:timelineParameters];
postRequest.account = self.delegate.userAccount;
// Perform the request
[postRequest performRequestWithHandler:^(NSData *responseData, NSHTTPURLResponse *urlResponse, NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^{
// Check if we reached the reate limit
if ([urlResponse statusCode] == 429) {
// Rate limit reached
// Display an alert letting the user know we have hit the rate limit
UIAlertView *twitterAlert = [[UIAlertView alloc] initWithTitle:kRateLimitTitle
message:kRateLimitMessage
delegate:nil
cancelButtonTitle:#"Ok"
otherButtonTitles:nil];
[twitterAlert show];
// Stop animating the pull to refresh if it is animating
[self.feedTableView.pullToRefreshView stopAnimating];
return;
}
// Check if there was an error
if (error) {
NSLog(#"Error: %#", error.localizedDescription);
// Stop animating the pull to refresh if it is animating
[self.feedTableView.pullToRefreshView stopAnimating];
return;
}
// Check if there is some response data
if (responseData) {
NSError *jsonError = nil;
id feedData = [NSJSONSerialization JSONObjectWithData:responseData options:NSJSONReadingMutableContainers error:&jsonError];
if ([feedData isKindOfClass:[NSArray class]]) {
//Is array
NSLog(#"It's an Array");
} else if ([feedData isKindOfClass:[NSDictionary class]]) {
//Is dictionary
NSLog(#"It's a Dictionary");
} else {
//is something else
}
if (!jsonError) {
[self gatherTweetsFromArray:feedData];
} else {
// Stop animating the pull to refresh if it is animating
[self.feedTableView.pullToRefreshView stopAnimating];
// Alert the user with the error
UIAlertView *twitterAlert = [[UIAlertView alloc] initWithTitle:kErrorTitle
message:kErrorMessage
delegate:nil
cancelButtonTitle:#"Ok"
otherButtonTitles:nil];
[twitterAlert show];
}
} else {
// Stop animating the pull to refresh if it is animating
[self.feedTableView.pullToRefreshView stopAnimating];
// Alert the user with the error
UIAlertView *twitterAlert = [[UIAlertView alloc] initWithTitle:kErrorTitle
message:kErrorMessage
delegate:nil
cancelButtonTitle:#"Ok"
otherButtonTitles:nil];
[twitterAlert show];
}
});
}];
This is a MAJOR bug and I need to squash it, so any ideas or information will be greatly appreciated! Thank you!
I'm trying to detect how many invites the user has sent while logged into their Facebook account. For example, I'm giving the user an option to purchase an item by inviting 3 friends to use the iOS application. If they invite 3, they are rewarded with the item. I'm really stuck on this one. Any help would be great and much appreciated!
I actually found code snippet for this after much research. I can't remember if it was on here or not, but here it is.
- (IBAction)inviteFacebookFriendsButton:(id)sender
{
// FBSample logic
// if the session is open, then load the data for our view controller
if (!FBSession.activeSession.isOpen)
{
// if the session is closed, then we open it here, and establish a handler for state changes
[FBSession openActiveSessionWithReadPermissions:nil
allowLoginUI:NO
completionHandler:^(FBSession *session,
FBSessionState state,
NSError *error) {
if (error) {
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Error"
message:error.localizedDescription
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alertView show];
} else if (session.isOpen) {
}
}];
}
MouseInTheHouseAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
if (appDelegate.session.isOpen)
{
NSMutableDictionary *postVariablesDictionary = [[NSMutableDictionary alloc] init];
[postVariablesDictionary setObject:#"Come play Mouse in the House with me!" forKey:#"message"];
[postVariablesDictionary setObject:#"Invite Friends" forKey:#"title"];
[FBWebDialogs presentDialogModallyWithSession:[FBSession activeSession] dialog:#"apprequests" parameters:postVariablesDictionary handler:^(FBWebDialogResult result, NSURL *resultURL, NSError *error)
{
if (error)
{
// Case A: Error launching the dialog or sending request.
NSLog(#"Error sending request.");
}
else
{
if (result == FBWebDialogResultDialogNotCompleted)
{
// Case B: User clicked the "x" icon
NSLog(#"User canceled request.");
}
else
{
NSRegularExpression * regex = [NSRegularExpression regularExpressionWithPattern:#"to%5B\\d+%5D=(\\d+)"
options:NSRegularExpressionCaseInsensitive
error:NULL];
NSArray * matches = [regex matchesInString:resultURL.absoluteString
options:0
range:(NSRange){0, resultURL.absoluteString.length}];
NSMutableArray * ids = [NSMutableArray arrayWithCapacity:matches.count];
for (NSTextCheckingResult * match in matches)
{
[ids addObject:[resultURL.absoluteString substringWithRange:[match rangeAtIndex:1]]];
}
NSLog(#"Number of friends invited: %lu", (unsigned long)ids.count);
}
}
}];
}
}
I am developing an iOS application in which I want to retrieve my facebook friends & send it to server for checking who are already using this app using their email or phone number. Once I get friends who are not using my application then I will show "Invite" button to send an email to their email address with app store link to download the app.
But as per facebook permissions , we can not retrieve the facebook friends email address.
Can anybody know how can I implement this feature in other way ?
Any kind of help is appreciated. Thanks.
you can not retrieve facebook friends email address but you can post on their wall whatever link you want to post i.e. app store link to download the app.
You can give a look to my this thread.
Since facebook does not provide email address so the idea behind this solution to offer is that, you can send invite friend request with the link to your application at AppStore. I have briefly described the steps in link to follow in order to accomplish this case.
Invitation message might look like this:
I would like you to try XYZ game. Here is the link for this
Application at AppStore:
Facebook iOS SDK - get friends list
You can use FB Graph API(/me/invitable_friends) as below for getting non app friends -
// m_invitableFriends - global array which will hold the list of invitable friends
- (void) getAllInvitableFriends
{
NSMutableArray *tempFriendsList = [[NSMutableArray alloc] init];
NSDictionary *limitParam = [NSDictionary dictionaryWithObjectsAndKeys:#"100", #"limit", nil];
[self getAllInvitableFriendsFromFB:limitParam addInList:tempFriendsList];
}
- (void) getAllInvitableFriendsFromFB:(NSDictionary*)parameters
addInList:(NSMutableArray *)tempFriendsList
{
[FBRequestConnection startWithGraphPath:#"/me/invitable_friends"
parameters:parameters
HTTPMethod:#"GET"
completionHandler:^(
FBRequestConnection *connection,
id result,
NSError *error
) {
NSLog(#"error=%#",error);
NSLog(#"result=%#",result);
NSArray *friendArray = [result objectForKey:#"data"];
[tempFriendsList addObjectsFromArray:friendArray];
NSDictionary *paging = [result objectForKey:#"paging"];
NSString *next = nil;
next = [paging objectForKey:#"next"];
if(next != nil)
{
NSDictionary *cursor = [paging objectForKey:#"cursors"];
NSString *after = [cursor objectForKey:#"after"];
//NSString *before = [cursor objectForKey:#"before"];
NSDictionary *limitParam = [NSDictionary dictionaryWithObjectsAndKeys:
#"100", #"limit", after, #"after"
, nil
];
[self getAllInvitableFriendsFromFB:limitParam addInList:tempFriendsList];
}
else
{
[self replaceGlobalListWithRecentData:tempFriendsList];
}
}];
}
- (void) replaceGlobalListWithRecentData:(NSMutableArray *)tempFriendsList
{
// replace global from received list
[m_invitableFriends removeAllObjects];
[m_invitableFriends addObjectsFromArray:tempFriendsList];
//NSLog(#"friendsList = %d", [m_invitableFriends count]);
[tempFriendsList release];
}
For Inviting non app friend -
you will get invite tokens with the list of friends returned by me/invitable_friends graph api. You can use these invite tokens with FBWebDialogs to send invite to friends as below
- (void) openFacebookFeedDialogForFriend:(NSString *)userInviteTokens {
NSMutableDictionary *params = [NSMutableDictionary dictionaryWithObjectsAndKeys:
userInviteTokens, #"to",
nil, #"object_id",
#"send", #"action_type",
actionLinksStr, #"actions",
nil];
[FBWebDialogs
presentRequestsDialogModallyWithSession:nil
message:#"Hi friend, I am playing game. Come and play this awesome game with me."
title:nil
parameters:params
handler:^(
FBWebDialogResult result,
NSURL *url,
NSError *error)
{
if (error) {
// Error launching the dialog or sending the request.
NSLog(#"Error sending request : %#", error.description);
}
else
{
if (result == FBWebDialogResultDialogNotCompleted)
{
// User clicked the "x" icon
NSLog(#"User canceled request.");
NSLog(#"Friend post dialog not complete, error: %#", error.description);
}
else
{
NSDictionary *resultParams = [g_mainApp->m_appDelegate parseURLParams:[url query]];
if (![resultParams valueForKey:#"request"])
{
// User clicked the Cancel button
NSLog(#"User canceled request.");
}
else
{
NSString *requestID = [resultParams valueForKey:#"request"];
// here you will get the fb id of the friend you invited,
// you can use this id to reward the sender when receiver accepts the request
NSLog(#"Feed post ID: %#", requestID);
NSLog(#"Friend post dialog complete: %#", url);
}
}
}
}];
}
So I'm creating an iPhone app that needs to be able to upload a photo when the user checks into a location using the Facebook Graph API.
Right now my code is this:
if (![delegate.facebook isSessionValid])
[delegate.facebook authorize:[NSArray arrayWithObjects:#"publish_stream", #"offline_access", #"publish_checkins", nil]];
parameters = [NSMutableDictionary dictionaryWithObjectsAndKeys:[placeDictionary objectForKey:#"id"] , #"place",
serialisedCoordinates, #"coordinates",
message, #"message",
pickedImage, #"picture",
#"Via the official REDACTED app", #"application", nil];
[delegate.facebook requestWithGraphPath:#"me/checkins" andParams:parameters andHttpMethod:#"POST" andDelegate:fbCheckInResultHandler];
Where 'pickedImage' is the UIImage returned from a UIImagePickerController.
Even when I pick an image (i.e., pickedImage != nil), no picture is uploaded when checked in. The check in appears on Facebook with the message, coordinates and app information, just no image.
Really hope someone can help.
Cheers,
Kiran
Here is the whole function that is being called when a checkin is made:
-(void)fbPostCheckInWithMessage:(NSString *)message andFriends:(NSArray *)friends {
if (![delegate.facebook isSessionValid]) {
NSLog(#"Session invalid");
[delegate.facebook authorize:[NSArray arrayWithObjects:#"publish_stream", #"offline_access", #"publish_checkins", nil]];
} else {
NSLog(#"Session valid");
}
NSMutableString *friendsIDString;
friendsIDString = [NSMutableString stringWithFormat:#"%#", [[friends objectAtIndex:0] userID]];
if ([friends count] > 1) {
for (User *f in taggedFriends) {
if (f != [taggedFriends objectAtIndex:0]) {
[friendsIDString appendString:[NSString stringWithFormat:#", %#", f.userID]];
}
}
}
NSLog(#"Tagged Friends: %#", friendsIDString);
SBJSON *jsonWriter = [SBJSON new];
NSMutableDictionary *locationDictionary = [NSMutableDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:#"%f", userLocation.coordinate.latitude], #"latitude",
[NSString stringWithFormat:#"%f", userLocation.coordinate.longitude], #"longitude", nil];
NSString *serialisedCoordinates = [jsonWriter stringWithObject:locationDictionary];
NSData *pictureData = UIImagePNGRepresentation(pickedImage);
NSLog(#"picture: %#", pictureData);
NSMutableDictionary *parameters = [NSMutableDictionary dictionaryWithObjectsAndKeys:[placeDictionary objectForKey:#"id"] , #"place",
serialisedCoordinates, #"coordinates",
pictureData, #"message",
pickedImage, #"picture",
#"Via the official REDACTED app", #"application", nil];
[delegate.facebook requestWithGraphPath:#"me/checkins" andParams:parameters andHttpMethod:#"POST" andDelegate:fbCheckInResultHandler];
}
I am using the friendsIDString to get the IDs of the friends the user with. I've removed this functionality from the example here because it was all commented out because I was trying to isolate what was causing the problem (which was the photo tagging). Just wanted to clear that up.
--UPDATE--
Here's how I'm setting pickedImage. I use the delegate methods from the UIImagePickerController:
-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:(UIImage *)image editingInfo:(NSDictionary *)editingInfo {
NSLog(#"Picked image");
pickedImage = [[UIImage alloc] init];
pickedImage = image;
[imagePickerController dismissModalViewControllerAnimated:YES];
}
You can upload photos to facebook using :- UIImagePNGRepresentation,UIImageJPEGRepresentation,etc based on type of image or imagewithdata from UIImage class..
NSData *yourImageData= UIImagePNGRepresentation(yourImage);
Initialize the dictionary :-
NSMutableDictionary *mutableDictWithParam= [NSMutableDictionary dictionaryWithObjectsAndKeys:#"Your text", #"message", yourImageWithData, #"theSource", nil];
finally send post :-
[facebook requestWithGraphPath:#"/me/photos" andParams:mutableDictWithParam andHttpMethod:#"POST" andDelegate:self];
In you app i think you have not initialized your NSData object(pickedimage) ..else everything seems fine.
As Per Our Discussion You can use this to compress image:-
NSData* UIImageJPEGRepresentation(UIImage *image, CGFloat compressionQuality);
NSData *compressedImage = UIImagePNGRepresentation(yourIMage, .5)//quality is ensured through second argument lies between o and 1