I'm trying to share to Facebook using code from their iOS game tutorial. The dialog pops up and the image and text I specified is present, but when I hit "Send" the loading bar appears, doesn't load, then I am redirected to my app. No errors are printed to the console and the app does not crash.
When I go on Facebook to check if the message has posted, I get the following:
"Oops, Something Went Wrong. There was a problem posting your status. We've logged the error and will look into it."
I've used this code in the previous app and it worked perfectly fine. I've updated the Facebook ID, Facebook Display Name, and URL Scheme in the plist.
Here is the code:
FacebookHandler class (derived from Facebook tutorial)
#import "FacebookHandler.h"
#implementation FacebookHandler
+ (void) Facebook_CreateNewSession
{
// initialize Facebook
FBSession* session = [[FBSession alloc] init];
[FBSession setActiveSession: session];
}
+ (void) Facebook_Login
{
NSArray *permissions = [[NSArray alloc] initWithObjects:
#"email",
nil];
// Attempt to open the session. If the session is not open, show the user the Facebook login UX
[FBSession openActiveSessionWithReadPermissions:permissions allowLoginUI:true completionHandler:^(FBSession *session, FBSessionState status, NSError *error)
{
// Did something go wrong during login? I.e. did the user cancel?
if (status == FBSessionStateClosedLoginFailed || status == FBSessionStateCreatedOpening) {
// If so, just send them round the loop again
[[FBSession activeSession] closeAndClearTokenInformation];
[FBSession setActiveSession:nil];
[self Facebook_CreateNewSession];
}
else
{
}
}];
}
+ (void) Facebook_PostToNewsFeedWithTitle:(NSString*)title withCaption:(NSString*)caption withDescription:(NSString*)description withLink:(NSString*)link withPictureURL:(NSString*)picURL
{
// check if user is logged in
if ([FBSession activeSession] == nil)
{
[FacebookHandler Facebook_CreateNewSession];
[FacebookHandler Facebook_Login];
}
// This function will invoke the Feed Dialog to post to a user's Timeline and News Feed
// It will attemnt to use the Facebook Native Share dialog
// If that's not supported we'll fall back to the web based dialog.
NSString *linkURL = link;
NSString *pictureURL = picURL;
// Prepare the native share dialog parameters
FBShareDialogParams *shareParams = [[FBShareDialogParams alloc] init];
shareParams.link = [NSURL URLWithString:linkURL];
shareParams.name = title;
shareParams.caption= caption;
shareParams.picture= [NSURL URLWithString:pictureURL];
shareParams.description = description;
if ([FBDialogs canPresentShareDialogWithParams:shareParams]){
[FBDialogs presentShareDialogWithParams:shareParams
clientState:nil
handler:^(FBAppCall *call, NSDictionary *results, NSError *error) {
if(error) {
NSLog(#"Error publishing story.");
} else if (results[#"completionGesture"] && [results[#"completionGesture"] isEqualToString:#"cancel"]) {
NSLog(#"User canceled story publishing.");
} else {
NSLog(#"Story published.");
}
}];
}else {
// Prepare the web dialog parameters
NSDictionary *params = #{
#"name" : shareParams.name,
#"caption" : shareParams.caption,
#"description" : shareParams.description,
#"picture" : pictureURL,
#"link" : linkURL
};
// Invoke the dialog
[FBWebDialogs presentFeedDialogModallyWithSession:nil
parameters:params
handler:
^(FBWebDialogResult result, NSURL *resultURL, NSError *error) {
if (error) {
NSLog(#"Error publishing story.");
} else {
if (result == FBWebDialogResultDialogNotCompleted) {
NSLog(#"User canceled story publishing.");
} else {
NSLog(#"Story published.");
}
}}];
}
}
#end
My Call
[FacebookHandler Facebook_PostToNewsFeedWithTitle:title withCaption:caption withDescription:description withLink:link withPictureURL:picURL];
UPDATE
It seems to be a problem with the Facebook app. When trying it on a device with Facebook uninstalled, I am asked to log in and then it posts successfully. However, if Facebook is installed, it doesn't post.
I fix it by manually typing the "URL types" key at the plist file.
Don't copy paste the plist values from another plist file - it's Apple's bug!!!
Related
I want to fetch friend list of login user without using "FBFriendPickerViewController". So I used Graph API to do so but its not giving me the list of friends. I can login successfully and can able to fetch login user's information as well. I have followed this link https://developers.facebook.com/docs/graph-api/reference/v2.0/user/friendlists.
I have tried this code of snippet till now
-(IBAction)loginWithFacebook:(id)sender {
if (FBSession.activeSession.state == FBSessionStateOpen || FBSession.activeSession.state ==FBSessionStateOpenTokenExtended) {
// Close the session and remove the access token from the cache
// The session state handler (in the app delegate) will be called automatically
[FBSession.activeSession closeAndClearTokenInformation];
}
else {
[FBSession openActiveSessionWithPublishPermissions:#[#"publish_actions",#"manage_friendlists",#"public_profile",#"user_friends"]
defaultAudience:FBSessionDefaultAudienceEveryone
allowLoginUI:YES
completionHandler:^(FBSession *session, FBSessionState status, NSError *error) {
[self sessionStateChanged:session state:status error:error];
}];
}
}
-(void)sessionStateChanged:(FBSession *)session state:(FBSessionState) state error:(NSError *)error
{
// If the session was opened successfully
if (!error && state == FBSessionStateOpen){
NSLog(#"Session opened");
// Show the user the logged-in UI
[[FBRequest requestForMe] startWithCompletionHandler:^(FBRequestConnection *connection, NSDictionary<FBGraphUser> *user, NSError *error) {
NSLog(#"%#",user);
NSLog(#"email::: %#",[user objectForKey:#"email"]);
}];
return;
}
if (state == FBSessionStateClosed || state == FBSessionStateClosedLoginFailed){
// If the session is closed
NSLog(#"Session closed");
}
// Handle errors
if (error){
NSLog(#"Error");
NSString *alertText;
NSString *alertTitle;
// If the error requires people using an app to make an action outside of the app in order to recover
if ([FBErrorUtility shouldNotifyUserForError:error] == YES){
alertTitle = #"Something went wrong";
alertText = [FBErrorUtility userMessageForError:error];
[self showMessage:alertText withTitle:alertTitle];
} else {
// If the user cancelled login, do nothing
if ([FBErrorUtility errorCategoryForError:error] == FBErrorCategoryUserCancelled) {
NSLog(#"User cancelled login");
// Handle session closures that happen outside of the app
} else if ([FBErrorUtility errorCategoryForError:error] == FBErrorCategoryAuthenticationReopenSession){
alertTitle = #"Session Error";
alertText = #"Your current session is no longer valid. Please log in again.";
[self showMessage:alertText withTitle:alertTitle];
} else {
//Get more error information from the error
NSDictionary *errorInformation = [[[error.userInfo objectForKey:#"com.facebook.sdk:ParsedJSONResponseKey"] objectForKey:#"body"] objectForKey:#"error"];
// Show the user an error message
alertTitle = #"Something went wrong";
alertText = [NSString stringWithFormat:#"Please retry. \n\n If the problem persists contact us and mention this error code: %#", [errorInformation objectForKey:#"message"]];
[self showMessage:alertText withTitle:alertTitle];
}
}
// Clear this token
[FBSession.activeSession closeAndClearTokenInformation];
}
}
Now after login I tried to fetch friend list for that I have written
- (IBAction)fetchFrinds:(id)sender {
[FBRequestConnection startWithGraphPath:#"/me/friendlists"
parameters:#{#"fields": #"id,name"}
HTTPMethod:#"GET"
completionHandler:^(
FBRequestConnection *connection,
id result,
NSError *error
) {
NSLog(#"%#",result);
}];
}
As per the Facebook Graph API 2.0 docs on Friendlists:
/{user-id}/friendlists
A person's 'friend lists' - these are groupings of friends such as "Acquaintances" or "Close Friends", or any others that may have been created. They do not refer to the list of friends that a person has, which is accessed instead through the /{user-id}/friends edge.
So, with your current request, you're getting the friend-lists rather than the list of friends.
For getting a list of friends, you need to refer to:
Facebook Graph API 2.0 docs on List of Friends
NOTE:
Facebook seems to have changed it's implementation.
You can no longer get the entire list of friends.
Now... the list will be limited to only those friends who also happen to use your app.
To quote Facebook Graph API 2.0 doc:
Permissions
A user access token with user_friends permission is required to view the current person's friends.
This will only return any friends who have used (via Facebook Login) the app making the request.
If by friendslist you mean a list of friends for the logged in user then the graph path is me/friends. Something like this works for me after you have opened an active FBSession with read permissions.
NSMutableDictionary *params = [NSMutableDictionary dictionaryWithObjectsAndKeys:#"id,name,picture",#"fields",nil];
[FBRequestConnection startWithGraphPath:#"me/friends"
parameters:params
HTTPMethod:#"GET"
completionHandler:^(FBRequestConnection *connection, id result, NSError *error) {
if(error == nil) {
FBGraphObject *response = (FBGraphObject*)result;
NSLog(#"Friends: %#",[response objectForKey:#"data"]);
}
}];
Note that the result of the FBRequestConnection request on success is an FBGraphObject with the required information returned for key 'data'.
You can open an active FBSession with read permission of just basic_info before making an FBRequestConnection for the list of friends.
Hope this helps
I'm using facebook-ios-sdk-3.10, Using this SDK I'll login and fetch user details from FB Its working fine for me.
This is the code I'm uisng
- (IBAction)fbLogin_click:(id)sender
{
if (AppDelegate.fbsession.state != FBSessionStateCreated) {
// Create a new, logged out session.
NSArray *permissions = [NSArray arrayWithObjects:#"offline_access", #"email", #"publish_stream", #"read_stream",#"read_friendlists",#"manage_friendlists",#"friends_about_me",#"publish_actions", nil];
// create a session object, with defaults accross the board, except that we provide a custom
// instance of FBSessionTokenCachingStrategy
AppDelegate.fbsession = [[FBSession alloc] initWithAppID:nil
permissions:permissions
urlSchemeSuffix:nil
tokenCacheStrategy:nil];
}
FBSessionLoginBehavior behavior = FBSessionLoginBehaviorForcingWebView;
if (AppDelegate.fbsession.state != FBSessionStateCreatedTokenLoaded) {
// even though we had a cached token, we need to login to make the session usable
[AppDelegate.fbsession openWithBehavior:behavior completionHandler:^(FBSession *session,
FBSessionState status,
NSError *error) {
if (error)
{
NSLog(#"Error");
}
[self GetFBUserDetails];
}];
}
}
-(void) GetFBUserDetails
{
if (AppDelegate.fbsession.isOpen)
{
[HUD show:YES];
// fetch profile info such as name, id, etc. for the open session
FBRequest *me = [[FBRequest alloc] initWithSession:AppDelegate.fbsession graphPath:#"me"];
self.pendingRequest= me;
[me startWithCompletionHandler:^(FBRequestConnection *connection,
NSDictionary<FBGraphUser> *user,
NSError *error) {
// because we have a cached copy of the connection, we can check
// to see if this is the connection we care about; a prematurely
// cancelled connection will short-circuit here
if (me != self.pendingRequest) {
return;
}
self.pendingRequest = nil;
// self.pendingLoginForSlot = -1;
// we interpret an error in the initial fetch as a reason to
// fail the user switch, and leave the application without an
// active user (similar to initial state)
if (error) {
return;
}
[AppDelegate.fbsession closeAndClearTokenInformation];
[FBSession.activeSession close];
[FBSession.activeSession closeAndClearTokenInformation];
FBSession.activeSession=nil;
[self FacebookCustomerRegister:user];
}];
}
}
In such case some user create Facebook account and not very his account through email, when he try to login via my app it shows empty screen after click login button, there is no action further. how can I notify the user "You not yet verify your FB account" and it not return to my app. how can I fetch the response from there ?
can anyone help me for this ?
The email address you get from Facebook using the Graph API or a FQL query is a verified email. If an account hasn't verified it's email yet it's not possible to get it.
so when you fetch user info and if you are not getting the email when you have the permission to get then user is no verified and you can show an alert or any info to user about verifying the email and information
check more detail here Is it possible to check if an email is confirmed on Facebook?
Facebook content looks different in wall and home page , after posting the content from iOS app using facebook sdk of iOS,
Used Code : We are using following code for posting the data in facebook wall.
[NSMutableDictionary dictionaryWithObjectsAndKeys:
#"Found this app ", #"message",
#"AppName", #"name",
#"App Title", #"caption",
#"Description data", #"description",
#"Link URL", #"link",
#"Image URL", #"picture",nil];
// create the connection object.
FBRequestConnection *newConnection = [[[FBRequestConnection alloc] initWithTimeout:kRequestTimeoutInterval] autorelease];
// create the request object, using the fbid as the graph path as an alternative the request* static methods of the
// FBRequest class could be used to fetch common requests, such as /me and /me/friends
FBRequest *request=[[[FBRequest alloc] initWithSession:activeSession
graphPath:#"me/feed"
parameters:params
HTTPMethod:#"POST"] autorelease];
Detail: When we are going to post this data and link url ia available then content are looks different in home screen and profile screen .
Instead od App Name is display the Link URL title in home page but in profile page it display right content like App Title.
It happen only posting from iOS app , it looks good from Android app.
Please help Me tikamchandrakar#gmail.com or tikam.chandrakar#xymob.com
Let me know if any thing is not clear.
Thanks
Try This code. It works Perfect for me -
// Helper method to request publish permissions and post.
- (void)requestPermissionAndPost {
[FBSession.activeSession requestNewPublishPermissions:[NSArray arrayWithObject:#"publish_actions"]
defaultAudience:FBSessionDefaultAudienceFriends
completionHandler:^(FBSession *session, NSError *error) {
if (!error && [FBSession.activeSession.permissions indexOfObject:#"publish_actions"] != NSNotFound) {
// Now have the permission
[self postOpenGraphAction];
} else if (error){
// Facebook SDK * error handling *
// if the operation is not user cancelled
if (error.fberrorCategory != FBErrorCategoryUserCancelled) {
// [self presentAlertForError:error];
}
}
}];
}
// Creates the Open Graph Action.
- (void)postOpenGraphAction {
NSString *pageId = #"";
if ([pageIdArray count] > 0) {
pageId = [[pageIdArray objectAtIndex:0] objectForKey:#"page_id"];
}else{
pageId = #"";
}
//http://mistoh.com/mistohws/CategoriesIcon/CategoryIcon_%1$s.png
[FBRequestConnection startWithGraphPath:#"me/feed"
parameters:#{
#"link":#"http://mistoh.com/mistohws/CategoriesIcon/CategoryIcon_1.png",
#"message":[NSString stringWithFormat:#"I just shared a Mistoh at %#",self.mistohNameStr],
#"place":[NSString stringWithFormat:#"%#",pageId],
#"name":[NSString stringWithFormat:#"%#",self.mistohNameStr],
#"description":[NSString stringWithFormat:#"%#",self.mistohDescStr],
#"address":[NSString stringWithFormat:#"%#",self.mistohAddressStr],
#"tags":[NSString stringWithFormat:#"%#",self.selectedFriendsStr]
}
HTTPMethod:#"POST"
completionHandler:^(FBRequestConnection *connection, id result, NSError *error) {
//verify result
if (!error) {
[[[UIAlertView alloc] initWithTitle:#"Shared Mistoh Successfully!!"
message:#""
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil]
show];
}else{
[[[UIAlertView alloc] initWithTitle:#"Error"
message:#"Error while sharing mistoh with friends."
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil]
show];
NSLog(#"Error : %#",[error description]);
}
}];
}
It looks good on facebook wall and timeline. Thank You..
I am fetching a facebook token from my server (where it was stored from a previous login on another device). I am using that to open a session and then I am making a relatively simple call with
[FBWebDialogs presentRequestsDialogModallyWithSession:[FBSession activeSession]
message:#"Message"
title:#"Title"
parameters:params
handler:^(FBWebDialogResult result,
NSURL *resultURL, NSError *error) {}}];
The web window that pops up has a message saying "An Error occured. Please try again later.". I click OK and I trigger the callback (which I omitted above). When I trace the resultURL I get
fbconnect://success?error_code=110&error_msg=Missing+user+cookie+%28to+validate+session+user%29
I can use the session to post on my wall just fine. What am I missing?
I found that the token retuned by Facebook contains additional metadata such as the c_user cookie which is used by all web views subsequently. When setting up a remote caching system you must store expiry date and refresh date on the remote server and return them for use in the TokenData object. If this is not done correctly them the correct metadata is not set.
Make sure you have "publish_actions" permission on your active Facebook session.
bool hasPublishPermission = NO;
for( NSString* permission in [FBSession.activeSession permissions] )
{
if( [permission isEqualToString:#"publish_actions"] )
{
hasPublishPermission = YES;
break;
}
}
if( !hasPublishPermission )
{
[FBSession openActiveSessionWithPublishPermissions:#[#"publish_actions"]
defaultAudience:FBSessionDefaultAudienceFriends
allowLoginUI:YES
completionHandler:^(FBSession *session,
FBSessionState status,
NSError *error) {
if( status==FBSessionStateOpen )
{
//Present dialog
}
}];
}
else
{
//Present dialog
}
Also, make sure you have added your "FacebookAppID" to your project's plist. (See the tab, "Configure a new Xcode Project", at https://developers.facebook.com/docs/getting-started/facebook-sdk-for-ios/ ) This may cause the error you are describing.
Hope this helps
I have integrated Embedded webview in my app with Facebook sdk 3.5.3
I hope my code will give some idea to you...
-(IBAction)fblogin:(id)sender{
NSArray * arr=[NSArray arrayWithObjects:#"publish_actions",#"email",#"basic_info",#"user_location",#"user_birthday",#"user_likes", nil];
Interest_Status=[NSString stringWithFormat:#"%#",txt_interest.text];
[FBSession setActiveSession:session];
if (FBSession.activeSession.isOpen) {
if ([btn_Login.titleLabel.text isEqualToString:#"Logout"]) {
[btn_Login setTitle:#"Login" forState:UIControlStateNormal];
[btn_Login setImage:[UIImage imageNamed:#"FBLogin.png"] forState:UIControlStateNormal];
FBSessionTokenCachingStrategy *tokenCachingStrategy = [[FBSessionTokenCachingStrategy alloc]
initWithUserDefaultTokenInformationKeyName:nil];
tokenCachingStrategy=nil;
FBSession *seession=[FBSession activeSession];
[seession closeAndClearTokenInformation];
[session close];
[FBSession setActiveSession:nil];
session=nil;
session=[[FBSession alloc]initWithPermissions:arr];
self.ProfileLale.hidden=YES;
}
/*else if ([btn_Login.titleLabel.text isEqualToString:#"Login"]) {
[self updateForSessionChangeForSlot:1];
}*/
}else{
[session openWithBehavior:FBSessionLoginBehaviorForcingWebView
completionHandler:^(FBSession *session,
FBSessionState status,
NSError *error) {
// this handler is called back whether the login succeeds or fails; in the
// success case it will also be called back upon each state transition between
// session-open and session-close
if (error)
{
NSLog(#"error=%# \n\n description=%# \n\n,",error,error.description);
[self switchToNoActiveUser];
}else{
[self updateForSessionChangeForSlot:1];
}
}];
}
}
- (void)updateForSessionChangeForSlot:(int)slot {
if (session.isOpen) {
// fetch profile info such as name, id, etc. for the open session
// Fetch user data
FBRequest *me = [[FBRequest alloc] initWithSession:session
graphPath:#"me"];
[me startWithCompletionHandler:^(FBRequestConnection *connection,
NSDictionary<FBGraphUser> *user,
NSError *error) {
// because we have a cached copy of the connection, we can check
// to see if this is the connection we care about; a prematurely
// cancelled connection will short-circuit here
// if (me != self.pendingRequest) {
// return;
// }
NSLog(#"user=%#",user);
// self.pendingRequest = nil;
// self.pendingLoginForSlot = -1;
// we interpret an error in the initial fetch as a reason to
// fail the user switch, and leave the application without an
// active user (similar to initial state)
if (error) {
NSLog(#"error=%#",error);
NSLog(#"Couldn't switch user: %#", error.localizedDescription);
[self switchToNoActiveUser];
return;
}else{
NSLog(#"user=%#",user);
[btn_Login setTitle:#"Logout" forState:UIControlStateNormal];
[btn_Login setImage:[UIImage imageNamed:#"FBLogout.png"] forState:UIControlStateNormal];
}
}];
} else {
// in the closed case, we check to see if we picked up a cached token that we
// expect to be valid and ready for use; if so then we open the session on the spot
if (session.state == FBSessionStateCreatedTokenLoaded) {
// even though we had a cached token, we need to login to make the session usable
[session openWithCompletionHandler:^(FBSession *session,
FBSessionState status,
NSError *error) {
[self updateForSessionChangeForSlot:slot];
}];
}
}
}
- (void)switchToNoActiveUser {
/*UIAlertView *alter=[[UIAlertView alloc]initWithTitle:#"Message" message:#"No Internet connecton" delegate:nil cancelButtonTitle:#"Ok" otherButtonTitles:nil, nil];
[alter show];
*/
NSArray * arr=[NSArray arrayWithObjects:#"publish_actions",#"email",#"basic_info",#"user_location",#"user_birthday",#"user_likes", nil];
session = nil;
session=[[FBSession alloc]initWithPermissions:arr];
[btn_Login setTitle:#"Login" forState:UIControlStateNormal];
self.ProfileLale.hidden=YES;
[btn_Login setImage:[UIImage imageNamed:#"FBLogin.png"] forState:UIControlStateNormal];
}
I am requesting my friend, using simple code as below which is working very fine.
- (NSDictionary*)parseURLParams:(NSString *)query {
NSArray *pairs = [query componentsSeparatedByString:#"&"];
NSMutableDictionary *params = [[NSMutableDictionary alloc] init];
for (NSString *pair in pairs) {
NSArray *kv = [pair componentsSeparatedByString:#"="];
NSString *val =
[kv[1] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
params[kv[0]] = val;
}
return params;
}
- (void)sendRequest {
// Display the requests dialog
[FBWebDialogs
presentRequestsDialogModallyWithSession:nil
message:#"Learn how to make your iOS apps social."
title:nil
parameters:nil
handler:^(FBWebDialogResult result, NSURL *resultURL, NSError *error) {
if (error) {
// Error launching the dialog or sending the request.
NSLog(#"Error sending request.");
} else {
if (result == FBWebDialogResultDialogNotCompleted) {
// User clicked the "x" icon
NSLog(#"User canceled request.");
} else {
// Handle the send request callback
NSDictionary *urlParams = [self parseURLParams:[resultURL query]];
if (![urlParams valueForKey:#"request"]) {
// User clicked the Cancel button
NSLog(#"User canceled request.");
} else {
// User clicked the Send button
NSString *requestID = [urlParams valueForKey:#"request"];
NSLog(#"Request ID: %#", requestID);
}
}
}
}];
}
as the received user click the request, it redirect it too appStore link of my App, whose Facebook ID I have used in .plist file.
I want to show URL which is mind, say www.myiosdeveloper.com, so How can I redirect it.
I found something in documentation, but I am unable to understand it.
Request Dialog Documentation
Below in the page of above given documentation, it says,
https://www.facebook.com/dialog/apprequests?
app_id=APP_ID&
=Facebook%20Dialogs%20are%20so%20easy!&
redirect_uri=http://www.example.com/response
So, what is it, please explain.
Can SDK gives me permission to do as I want to, i.e redirect to my page.
Assign that URL to the Canvas URL. Its simple.