I want to use Facebook graph API to share on Facebook through my app, without presenting share dialog.But on reading various threads on internet i'm really confused about how to achieve this. i found this post on stack overflow but didn't able to find out how to make it works.
Can anyone give me step by step guideline or source code. any help would be highly appreciated.
Edit: code i used so far-
- (IBAction)StatusUpdateWithAPICalls:(id)sender {
[self openSessionForReadPermissions];
}
- (void)openSessionForReadPermissions
{
[FBSession openActiveSessionWithReadPermissions:nil
allowLoginUI:YES
completionHandler:
^(FBSession *session,
FBSessionState state, NSError *error) {
//this is called even from the reauthorizeWithPublishPermissions
if (state == FBSessionStateOpen && !error)
{
//[self openSessionForPublishPermissions];
//dispatch_async(dispatch_get_current_queue(), ^{
[self openSessionForPublishPermissions];
//});
}
else if (state == FBSessionStateClosedLoginFailed)
{
[FBSession.activeSession closeAndClearTokenInformation];
// [[NSNotificationCenter defaultCenter] postNotificationName:FBLoginErrorNotification object:session];
}
}];
}
-(void)openSessionForPublishPermissions
{
// We will post on behalf of the user, these are the permissions we need:
NSArray *permissionsNeeded = #[#"publish_actions"];
// Request the permissions the user currently has
[FBRequestConnection startWithGraphPath:#"/me/permissions"
completionHandler:^(FBRequestConnection *connection, id result, NSError *error) {
if (!error){
// Parse the list of existing permissions and extract them for easier use
NSMutableArray *currentPermissions = [[NSMutableArray alloc] init];
NSArray *returnedPermissions = (NSArray *)[result data];
for (NSDictionary *perm in returnedPermissions) {
if ([[perm objectForKey:#"status"] isEqualToString:#"granted"]) {
[currentPermissions addObject:[perm objectForKey:#"permission"]];
}
}
// Build the list of requested permissions by starting with the permissions
// needed and then removing any current permissions
NSMutableArray *requestPermissions = [[NSMutableArray alloc] initWithArray:permissionsNeeded copyItems:YES];
[requestPermissions removeObjectsInArray:currentPermissions];
NSLog(#"Asking: %#", requestPermissions);
// If we have permissions to request
if ([requestPermissions count] > 0){
// Ask for the missing permissions
[FBSession.activeSession requestNewPublishPermissions:requestPermissions
defaultAudience:FBSessionDefaultAudienceFriends
completionHandler:^(FBSession *session, NSError *error) {
if (!error) {
// Permission granted, we can request the user information
[self makeRequestToUpdateStatus];
} else {
// An error occurred, handle the error
NSLog(#"%#", error.description);
}
}];
} else {
// Permissions are present, we can request the user information
[self makeRequestToUpdateStatus];
}
} else {
// There was an error requesting the permission information
// See our Handling Errors guide: https://developers.facebook.com/docs/ios/errors/
NSLog(#"%#", error.description);
}
}];
}
- (void)makeRequestToUpdateStatus {
// NOTE: pre-filling fields associated with Facebook posts,
// unless the user manually generated the content earlier in the workflow of your app,
// can be against the Platform policies: https://developers.facebook.com/policy
[FBRequestConnection startForPostStatusUpdate:#"User-generated status update."
completionHandler:^(FBRequestConnection *connection, id result, NSError *error) {
if (!error) {
// Status update posted successfully to Facebook
NSLog(#"result: %#", result);
} else {
// An error occurred, we need to handle the error
// See: https://developers.facebook.com/docs/ios/errors
NSLog(#"%#", error.description);
}
}];
}
but i getting this error-
Error Domain=com.facebook.sdk Code=2 "The operation couldn’t be completed. com.facebook.sdk:ErrorReauthorizeFailedReasonUserCancelled" UserInfo=0x78788e60 {com.facebook.sdk:ErrorLoginFailedReason=com.facebook.sdk:ErrorReauthorizeFailedReasonUserCancelled, NSLocalizedFailureReason=com.facebook.sdk:ErrorReauthorizeFailedReasonUserCancelled, com.facebook.sdk:ErrorSessionKey=<FBSession: 0x787ac750, state: FBSessionStateOpen, loginHandler: 0x787ac710, appID: 4201XXXXXXXXXXX, urlSchemeSuffix: , tokenCachingStrategy:<FBSessionTokenCachingStrategy: 0x7a1c1b50>, expirationDate: 2015-04-20 06:48:00 +0000, refreshDate: 2015-02-19 09:39:47 +0000, attemptedRefreshDate: 0000-12-30 00:00:00 +0000, permissions:(
"public_profile"
)
And i'm not sure if i'm doing it right. please suggest me.
Use fallbacks.
Upload a photo via an app. FB logged in account
Related
Using SDK 3.22.0.
if (FBSession.activeSession.isOpen) {
[FBSession.activeSession
requestNewPublishPermissions:#[#"publish_actions"]
defaultAudience:FBSessionDefaultAudienceFriends
completionHandler:^(FBSession *session, NSError *error) {
NSLog(#"error = %#", error);
NSLog(#"session open = %d", session.isOpen);
NSLog(#"session.permissions = %#", session.permissions);
NSLog(#"session.accessTokenData.declinedPermissions = %#", session.accessTokenData.declinedPermissions);
}];
}
else {
[FBSession
openActiveSessionWithPublishPermissions:#[#"publish_actions"]
defaultAudience:FBSessionDefaultAudienceFriends
allowLoginUI:YES
completionHandler:^(FBSession *session, FBSessionState status, NSError *error) {
NSLog(#"error = %#", error);
NSLog(#"session open = %d", session.isOpen);
NSLog(#"status = %lu", status);
NSLog(#"session.permissions = %#", session.permissions);
NSLog(#"session.accessTokenData.declinedPermissions = %#", session.accessTokenData.declinedPermissions);
}];
}
I'm testing with a user that doesn't have yet publish permissions and never declined it either. On FB Apps Settings on this account, the App Visibility is set to "Friends" and publishing permissions are not even on the settings list as they are for other users/apps.
In both cases of the code, the FB app opens and returns to my app immediately, without asking permissions. Response of declinedPermissions is an array with publish_actions.
My expectation is that FB app will ask the user to approve publishing.
I got reports from multiple users that experienced the same issue - not being able to add publish permissions, but some are able to get the permission.
One thing to add is that I had the same issue before submitting the app for FB approval with users outside of the test group, but when app got approved it started working for those users. Now it seems like the problem persists even when the app is approved, just for random users.
Am I doing anything wrong with the way I'm asking for permissions?
Looks like this worked:
- (BOOL)hasWritePermissions {
if (!FBSession.activeSession.isOpen) return NO;
return [FBSession.activeSession.permissions indexOfObject:#[#"publish_actions"]] != NSNotFound;
}
- (void)requestWritePermissions:(void(^)(BOOL status, NSError *error))callback {
if (self.hasWritePermissions) {
callback(YES, nil);
return;
}
if (FBSession.activeSession.isOpen) {
[FBSession.activeSession
requestNewPublishPermissions:#[#"publish_actions"]
defaultAudience:FBSessionDefaultAudienceFriends
completionHandler:^(FBSession *session, NSError *error) {
NSLog(#"error = %#", error);
NSLog(#"session open = %d", session.isOpen);
NSLog(#"session.permissions = %#", session.permissions);
NSLog(#"session.accessTokenData.declinedPermissions = %#", session.accessTokenData.declinedPermissions);
if (self.hasWritePermissions) {
callback(YES, nil);
}
else {
callback(NO, error);
}
}];
}
else {
[FBSession
openActiveSessionWithPublishPermissions:#[#"publish_actions"]
defaultAudience:FBSessionDefaultAudienceFriends
allowLoginUI:YES
completionHandler:^(FBSession *session, FBSessionState status, NSError *error) {
NSLog(#"error = %#", error);
NSLog(#"session open = %d", session.isOpen);
NSLog(#"status = %u", status);
NSLog(#"session.permissions = %#", session.permissions);
NSLog(#"session.accessTokenData.declinedPermissions = %#", session.accessTokenData.declinedPermissions);
[self requestWritePermissions:callback]; // this time, with an open session
}];
}
}
If there's no session, I run openActiveSessionWithPublishPermissions and then run again requestNewPublishPermissions.
Issue is that openActiveSessionWithPublishPermissions was firing the callback without even going to Facebook app for more permissions (looks like FB bug, will report), but this approach seems to solve it.
Another issue I found is that session.permissions are not always reflecting the permissions on Facebook. The only way I found to ensure I have the latest permissions is to issue an API request:
[FBRequestConnection startWithGraphPath:#"/me/permissions" completionHandler:^(FBRequestConnection *connection, id result, NSError *error) {
and check the result.data array for granted/declined permissions.
I had a similar issue with this method. I ended up opening the session with a full set of permissions (read & write ) and it solved my problem.
-(void)requestPublishPermissionsWithCompletion:(FBHandlerComp)completion{
if (self.session.isOpen && [self.session.permissions containsObject:#"publish_actions"]){
//we have an open session and all neceassarry pemissions
completion(true,nil);
}else{
//something in missing, to account to all diffrent scenarios (missing persmission, expired tokens, changes in user sessting etc..), we reinisilise the session and request permissions
//for publish permissions we need to ask for the whole set( read& publish)
NSMutableArray *permissions = [NSMutableArray arrayWithArray:self.writePersmissions];
[permissions addObjectsFromArray:self.readPersmissions];
self.session = [[FBSession activeSession]initWithAppID:nil permissions:permissions defaultAudience:FBSessionDefaultAudienceFriends urlSchemeSuffix:nil tokenCacheStrategy:nil];
[self openFacebookSessionWithCompleteion:^(BOOL result, NSError *error) {
if (result) {
completion(true,nil);
}else{
if (LOGGING_IS_ON) DebugLog(#"could not get publish permissions- could not open session %#",error);
completion(false,nil);
}
}];
}
}
I am not able to get the permissions for user_birthday and user_hometown.
I tried it with this code before but it only asks for the public profile and ignores others.
[FBSession openActiveSessionWithReadPermissions:#[#"public_profile",#"user_birthday",#"user_hometown"]
allowLoginUI:YES completionHandler:^(FBSession *session, FBSessionState status, NSError *error) {
if (error) {
NBAppDelegate* appDel = (NBAppDelegate*)`[UIApplication sharedApplication].delegate;
[appDel sessionStateChanged:session state:status error:error];
}
if ([session isOpen]) {
[self loginWithFBToken:session name:sender];
}
}];
Then someone suggested to ask for additional permissions after getting the public profile, so i even tried that to no good.
Here is the code for that
- (void)loadFbDetails
{
NSArray *permissionsNeeded = #[#"user_hometown", #"user_birthday"];
// Request the permissions the user currently has
[FBRequestConnection startWithGraphPath:#"/me/permissions"
completionHandler:^(FBRequestConnection *connection, id result, NSError *error) {
if (!error){
// These are the current permissions the user has:
NSDictionary *currentPermissions= [(NSArray *)[result data] objectAtIndex:0];
// We will store here the missing permissions that we will have to request
NSMutableArray *requestPermissions = [[NSMutableArray alloc] initWithArray:#[]];
// Check if all the permissions we need are present in the user's current permissions
// If they are not present add them to the permissions to be requested
for (NSString *permission in permissionsNeeded){
if (![currentPermissions objectForKey:permission]){
[requestPermissions addObject:permission];
}
}
// If we have permissions to request
if ([requestPermissions count] > 0){
// Ask for the missing permissions
[FBSession.activeSession
requestNewReadPermissions:requestPermissions
completionHandler:^(FBSession *session, NSError *error) {
if (!error) {
// Permission granted
NSLog(#"new permissions %#", [FBSession.activeSession permissions]);
// We can request the user information
[self makeRequestForUserData];
} else {
// An error occurred, we need to handle the error
// See: https://developers.facebook.com/docs/ios/errors
}
}];
} else {
// Permissions are present
// We can request the user information
[self makeRequestForUserData];
}
} else {
// An error occurred, we need to handle the error
// See: https://developers.facebook.com/docs/ios/errors
}
}];
}
-(void)makeRequestForUserData
{
[FBRequestConnection startWithGraphPath:#"me?fields=birthday,hometown"
completionHandler:^(FBRequestConnection *connection, id result, NSError *error) {
if (!error) {
// Sucess! Include your code to handle the results here
NSLog(#"user events: %#", result);
} else {
NSLog(#"error: %#" , error);
}
}];
}
All it does is recursively go between my ios app and the fb native app, returning only with the public_profile in the permissions array.
Looks like i am missing something?
It should work if you're using an admin user of the app. Once you want to use the extended permissions with other users, you have to get your app reviewed by Facebook first.
See my answer here: facebook extended permission
Facebook does not allow apps to access that information by default. You have to ask permission to Facebook for you to be able to use that information. Add a video and instructions for a Facebook employee review how you're using birthday and hometown intel.
i have integerated facebook sdk latest, i create App on developer with my acoount ABC ....and use Facebook App id . All is fine if i loging in my Ios app with my ABC account to loging with facebook.it post on my wall successfully .
But if i use any other Account to loging with facebook . i loged in successfully but when i post i got error .
**I am getting this erro**r
Error Domain=com.facebook.sdk Code=5 "The operation couldn’t be completed. (com.facebook.sdk error 5.)" UserInfo=0x22689930 {com.facebook.sdk:HTTPStatusCode=403, com.facebook.sdk:ParsedJSONResponseKey={
body = {
error = {
code = 200;
message = "(#200) The user hasn't authorized the application to perform this action";
type = OAuthException;
};
};
code = 403;
}, com.facebook.sdk:ErrorSessionKey=, expirationDate: 2014-08-15 08:56:01 +0000, refreshDate: 2014-06-16 10:10:43 +0000, attemptedRefreshDate: 0001-12-30 00:00:00 +0000, permissions:(
status,
permission
)>}
For Posting
-(void) post:(NSString *)postString
{
if (FBSession.activeSession.state == FBSessionStateOpen|| FBSession.activeSession.state == FBSessionStateOpenTokenExtended)
{
NSArray *permissionsNeeded = #[#"publish_stream"];
[FBRequestConnection startWithGraphPath:#"/me/permissions"
completionHandler:^(FBRequestConnection *connection, id result, NSError *error) {
if (!error){
NSDictionary *currentPermissions= [(NSArray *)[result data] objectAtIndex:0];
NSMutableArray *requestPermissions = [[NSMutableArray alloc] initWithArray:#[]];
for (NSString *permission in permissionsNeeded){
if (![currentPermissions objectForKey:permission]){
[requestPermissions addObject:permission];
}
}
if ([requestPermissions count] < 1){
[FBSession.activeSession requestNewPublishPermissions:requestPermissions
defaultAudience:FBSessionDefaultAudienceFriends
completionHandler:^(FBSession *session, NSError *error) {
if (!error) {
[self makeRequestToUpdateStatus:postString];
} else {
NSLog(#"%#",[error description]);
}
}];
} else {
[self makeRequestToUpdateStatus:postString];
}
} else {
NSLog(#"%#",[error description]);
}
}];
}
else
{
}
}
For Login
-(void)loginToFacebook
{
NSLog(#"the facebook login called ");
if (!(FBSession.activeSession.state == FBSessionStateOpen || FBSession.activeSession.state == FBSessionStateOpenTokenExtended)){
NSArray *permissions = [[NSArray alloc] initWithObjects:
#"publish_stream",
nil];
[FBSession openActiveSessionWithPublishPermissions:permissions defaultAudience:FBSessionDefaultAudienceEveryone allowLoginUI:YES completionHandler:^(FBSession *session, FBSessionState status, NSError *error) {
dispatch_async( dispatch_get_main_queue(), ^{
[self sessionStateChanged:session
state:status
error:error];
});
}];
}
else
{
}
}
Hm, the message indicates you do not request the correct permissions from the user.
Perhaps you requested more before, and therefore it still works with your ABC account, because you 'authorized' the app already with that account at that time. So Facebook still sees that ABC authorized the app to post on the wall.
Edit: added the instructions below in response to your comments:
You can find a list with permissions you can ask for here. Note that with API v 2.0 if you ask for more than a few basic permissions (and posting on a wall is not such a basic permission) you will need to have Facebook 'approve' your app (unless you started your app before April 2014, in which case you can probably keep using v1.0 and not need approval until April 2015).
De-authorizing your own app can be done by logging in as that user, go to settings (menu top right), choose applications at the left and click the 'x' next to your application.
Steps
https://developers.facebook.com/apps
Select Your App then follow steps.
in **Settings** -> Basic
1. add contact Email
2. Bundle id
3. Url Scheme Suffix (like Your app name)
Then Save
In **Status & Review**
1.Do you want to make this app and all its live features available to the general public?
Set Yes
May be Useful
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 am following the sample codes on Facebook developer's site and I cannot fetch my name for example. I am using this code:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
AppDelegate *appDelegate = [[UIApplication sharedApplication]delegate];
if (!appDelegate.session.isOpen) {
NSLog(#"Session is not open");
// create a fresh session object
appDelegate.session = [[FBSession alloc] init];
// if we don't have a cached token, a call to open here would cause UX for login to
// occur; we don't want that to happen unless the user clicks the login button, and so
// we check here to make sure we have a token before calling open
if (appDelegate.session.state == FBSessionStateCreatedTokenLoaded) {
// even though we had a cached token, we need to login to make the session usable
[appDelegate.session openWithCompletionHandler:^(FBSession *session,
FBSessionState status,
NSError *error) {
// we recurse here, in order to update buttons and labels
}];
}
} else {
NSLog(#"Session is open");
[[FBRequest requestForMe] startWithCompletionHandler:
^(FBRequestConnection *connection, NSDictionary<FBGraphUser> *user, NSError *error) {
if (!error) {
NSLog(#"logged in : %#, id: %#",user.name,user.id);
} else {
NSLog(#"error: %#", error);
}
}];
}
}
so when the session is open, I see this output:
Session is open
error: Error Domain=com.facebook.sdk Code=5 "The operation couldn’t be completed. (com.facebook.sdk error 5.)" UserInfo=0x1fd60620 {com.facebook.sdk:ParsedJSONResponseKey={
body = {
error = {
code = 2500;
message = "An active access token must be used to query information about the current user.";
type = OAuthException;
};
};
code = 400;
}, com.facebook.sdk:HTTPStatusCode=400}
On facebook app page, I have set AppId to 0 since it is not uploaded yet. BundleId is set correctly.
What am I missing or is there any other way to do so?
You should set your appDelegate.session as the active session by calling
[FBSession setActiveSession:appDelegate.session];
when you open it.
This is because FBRequest's requestForMe method uses the active session (as stated in the docs).