I have an app, for iOS5 and above, in which I am trying to set up Facebook login. All works fine when there is a Facebook account integrated in the phone. If it is not, it doesn't work. This is even if the Facebook app is installed.
When the app is installed, it opens the app, asks me permission to access the appropriate user data and returns to my app with no result. It the same when it isn't installed. Safari is opened, asks me for authorization, returns, and nothing.
I followed all the steps mentioned in the Facebook Login tutorial. Is this a problem only I am facing?
EDIT: This is the requested code:
I open a session like so:
- (BOOL)openSessionWithAllowLoginUI:(BOOL)allowLoginUI {
NSArray *permissions = [[NSArray alloc] initWithObjects:
#"email",
nil];
return [FBSession openActiveSessionWithReadPermissions:permissions
allowLoginUI:allowLoginUI
completionHandler:^(FBSession *session,
FBSessionState state,
NSError *error) {
[self sessionStateChanged:session
state:state
error:error];
}];
}
And when it returns, I guess this method must be called. but it isn't:
- (void)sessionStateChanged:(FBSession *)session
state:(FBSessionState) state
error:(NSError *)error
{
switch (state) {
case FBSessionStateOpen:
if (!error) {
// We have a valid session
NSLog(#"session opened");
FBRequest *me = [FBRequest requestForMe];
__block NSString *username = nil;
[me startWithCompletionHandler:^(FBRequestConnection *connection,
id result,
NSError *error) {
NSDictionary<FBGraphUser> *my = (NSDictionary<FBGraphUser> *) result;
// NSLog(#"User session found: %#", my.username);
username = my.username;
}];
// /fb_access/:access_token
}
break;
case FBSessionStateClosed:
if (!error) {
// We have a valid session
NSLog(#"User session closed");
}
case FBSessionStateClosedLoginFailed:
NSLog(#"login failed, %#", error);
[FBSession.activeSession closeAndClearTokenInformation];
break;
default:
break;
}
[[NSNotificationCenter defaultCenter]
postNotificationName:FBSessionStateChangedNotification
object:session];
if (error) {
UIAlertView *alertView = [[UIAlertView alloc]
initWithTitle:#"Error"
message:error.localizedDescription
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alertView show];
}
}
Any ideas?
add below key-value pair in your plist.
Add Field (key) FacebookAppID - (value) fbID
Add Field - URL Types (key)
Add 2 Field in URL Types:
(key) URL Identifier - (value) (i.e. YourApplication name)
(key)-URL Schemes
Add Field in URL Schemes (key) - (value) fb(fbID) (e.g. fb557354324264278)
Add following method in to your appdelgate
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
{ // attempt to extract a token from the url return
[FBSession.activeSession handleOpenURL:url];
}
Both answers by iUser and Kalpesh are right. Combining both of them worked for me. Please refer to them. :)
Related
I have an iPad app designed for use in a kiosk environment.
The user flow should be
Take Photo
Choose photo from iPad Album view
Share to Facebook and / or Twitter
Automatically log user out after image has been posted
I have the auto-logout of Twitter working properly, my issue is with the Facebook portion.
I have implemented the Graph API for internal testing, and would love to be able to post a complete story this way, but I don't think there is a way to log out from the Facebook app once the authorization and post is complete.
For a fallback, I can use the Feed Dialog and auto-logout from there, but as far as I can tell, there is no way to upload a local image for sharing to Facebook from there.
My Facebook Sharing code is as follows:
- (IBAction)facebookShare:(id)sender {
/// Package the image inside a dictionary
NSArray* image = #[#{#"url": self.mergeImages, #"user_generated": #"true"}];
// Create an object
id<FBGraphObject> object =
[FBGraphObject openGraphObjectForPostWithType:#"me/feed:photo"
title:#"a photo"
image:self.mergeImages
url:nil
description:nil];
// Create an action
id<FBOpenGraphAction> action = (id<FBOpenGraphAction>)[FBGraphObject graphObject];
// Set image on the action
[action setObject:image forKey:#"image"];
// Link the object to the action
[action setObject:object forKey:#"photo"];
// Hardcode the location based on Facebook Place ID
id<FBGraphPlace> place = (id<FBGraphPlace>)[FBGraphObject graphObject];
[place setId:#"279163865580772"]; // Singley + Mackie
[action setPlace:place];
// Check if the Facebook app is installed and we can present the share dialog
FBOpenGraphActionShareDialogParams *params = [[FBOpenGraphActionShareDialogParams alloc] init];
params.action = action;
params.actionType = #"me/feed:share";
// If the Facebook app is installed and we can present the share dialog
if([FBDialogs canPresentShareDialogWithOpenGraphActionParams:params]) {
// Show the share dialog
[FBDialogs presentShareDialogWithOpenGraphAction:action
actionType:#"photo_overlay:share"
previewPropertyName:#"photo"
handler:^(FBAppCall *call, NSDictionary *results, NSError *error) {
if(error) {
// An error occurred, we need to handle the error
// See: https://developers.facebook.com/docs/ios/errors
// NSLog([NSString stringWithFormat:#"Error publishing story: %#", error.description]);
} else {
// Success
NSLog(#"result %#", results);
}
}];
// If the Facebook app is NOT installed and we can't present the share dialog
} else {
// Put together the Feed dialog parameters
NSMutableDictionary *params = [NSMutableDictionary dictionaryWithObjectsAndKeys:
#"name",
#"caption",
#"description",
#"link",
#"picture",
nil];
// Show the feed dialog
[FBWebDialogs presentFeedDialogModallyWithSession:nil
parameters:params
handler:^(FBWebDialogResult result, NSURL *resultURL, NSError *error) {
if (error) {
// An error occurred, we need to handle the error
// See: https://developers.facebook.com/docs/ios/errors
// NSLog([NSString stringWithFormat:#"Error publishing story: %#", error.description]);
} else {
if (result == FBWebDialogResultDialogNotCompleted) {
// User cancelled.
NSLog(#"User cancelled.");
} else {
// Handle the publish feed callback
NSDictionary *urlParams = [self parseURLParams:[resultURL query]];
if (![urlParams valueForKey:#"post_id"]) {
// User cancelled.
NSLog(#"User cancelled.");
} else {
// User clicked the Share button
NSString *result = [NSString stringWithFormat: #"Posted story, id: %#", [urlParams valueForKey:#"post_id"]];
NSLog(#"result %#", result);
}
}
}
// Auto log the user out
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSLog(#"defaults fbDidLogout ........%#",defaults);
if ([defaults objectForKey:#"FBAccessTokenKey"])
{
[defaults removeObjectForKey:#"FBAccessTokenKey"];
[defaults removeObjectForKey:#"FBExpirationDateKey"];
[defaults synchronize];
}
NSHTTPCookie *cookie;
NSHTTPCookieStorage *storage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
for (cookie in [storage cookies])
{
NSString* domainName = [cookie domain];
NSRange domainRange = [domainName rangeOfString:#"facebook"];
if(domainRange.length > 0)
{
[storage deleteCookie:cookie];
}
}
[FBSession.activeSession closeAndClearTokenInformation];
}];
}
}
// A function for parsing URL parameters.
- (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;
}
I have searched Stack Overflow far and wide for an answer to this, but have found no solutions.
I was finally able to figure this out! Posting the answer here to hopefully benefit others who are in the same situation.
First, add the following to your AppDelegate.m:
-(BOOL) application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
return [FBAppCall handleOpenURL:url sourceApplication:sourceApplication fallbackHandler:^(FBAppCall *call) {
// Facebook SDK * App Linking *
// For simplicity, this sample will ignore the link if the session is already
// open but a more advanced app could support features like user switching.
if (call.accessTokenData) {
if ([FBSession activeSession].isOpen) {
NSLog(#"INFO: Ignoring app link because current session is open.");
}
else {
[self handleAppLink:call.accessTokenData];
}
}
}];
}
// Helper method to wrap logic for handling app links.
- (void)handleAppLink:(FBAccessTokenData *)appLinkToken {
// Initialize a new blank session instance...
FBSession *appLinkSession = [[FBSession alloc] initWithAppID:nil
permissions:nil
defaultAudience:FBSessionDefaultAudienceNone
urlSchemeSuffix:nil
tokenCacheStrategy:[FBSessionTokenCachingStrategy nullCacheInstance] ];
[FBSession setActiveSession:appLinkSession];
// ... and open it from the App Link's Token.
[appLinkSession openFromAccessTokenData:appLinkToken
completionHandler:^(FBSession *session, FBSessionState status, NSError *error) {
// Forward any errors to the FBLoginView delegate.
if (error) {
//[self.loginViewController loginView:nil handleError:error];
}
}];
}
Wherever you are calling the posting action in your app, add this line to your header file:
#property (strong, nonatomic) FBRequestConnection *requestConnection;
And the following to your implementation file:
#synthesize requestConnection;
- (IBAction)facebookShare:(id)sender {
NSArray *permissions = [[NSArray alloc] initWithObjects:
#"publish_actions", #"publish_checkins", nil];
UIImage *img = self.facebookImage;
[FBSession openActiveSessionWithPublishPermissions:permissions
defaultAudience:FBSessionDefaultAudienceEveryone allowLoginUI:YES
completionHandler:^(FBSession *session,FBSessionState s, NSError *error) {
[FBSession setActiveSession:session];
if (!error) {
// Now have the permission
[self processPostingImage:img WithMessage:#"Enter_your_message_here"];
} else {
// Facebook SDK * error handling *
// if the operation is not user cancelled
if (error.fberrorCategory != FBErrorCategoryUserCancelled) {
[self presentAlertForError:error];
}
}
}];
}
-(void)logout {
[FBSession.activeSession closeAndClearTokenInformation];
[FBSession.activeSession close];
[FBSession setActiveSession:nil];
}
- (void)processPostingImage:(UIImage *) img WithMessage:(NSString *)message {
FBRequestConnection *newConnection = [[FBRequestConnection alloc] init];
FBRequestHandler handler =
^(FBRequestConnection *connection, id result, NSError *error) {
// output the results of the request
[self requestCompleted:connection forFbID:#"me" result:result error:error];
};
FBRequest *request=[[FBRequest alloc] initWithSession:FBSession.activeSession graphPath:#"me/photos" parameters:[NSDictionary dictionaryWithObjectsAndKeys:UIImageJPEGRepresentation(img, 0.7),#"source",message,#"message",#"{'value':'EVERYONE'}",#"privacy", nil] HTTPMethod:#"POST"];
[newConnection addRequest:request completionHandler:handler];
[self.requestConnection cancel];
self.requestConnection = newConnection;
[newConnection start];
}
// FBSample logic
// Report any results. Invoked once for each request we make.
- (void)requestCompleted:(FBRequestConnection *)connection
forFbID:fbID
result:(id)result
error:(NSError *)error
{
// not the completion we were looking for...
if (self.requestConnection &&
connection != self.requestConnection)
{
return;
}
// clean this up, for posterity
self.requestConnection = nil;
if (error)
{
}
else
{
[self logout];
};
}
- (void) presentAlertForError:(NSError *)error {
// Facebook SDK * error handling *
// Error handling is an important part of providing a good user experience.
// When fberrorShouldNotifyUser is YES, a fberrorUserMessage can be
// presented as a user-ready message
if (error.fberrorShouldNotifyUser) {
// The SDK has a message for the user, surface it.
[[[UIAlertView alloc] initWithTitle:#"Something Went Wrong"
message:error.fberrorUserMessage
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil] show];
} else {
}
}
Note:
To make this work with auto-logout, you also have to disable Safari on the device. This can be done by going to Settings > General > Restrictions > Allow Safari > Off. Once that is turned off, the Facebook IBAction will popup a UIWebView inside the app itself. When tapped, the current user can enter their Facebook credentials, then the app will post the image, and log the user out so the next user can use the app without having access to the previous user's Facebook details.
My Project is to get Facebook Insights data of my Fanpage on my iPhone App.
I started by installing Facebook SDK for iOS to get Access Code & than using SampleLoginSample Sample Program provided with Facebook iOS SDK.
Its working Perfect & giving same response as in Facebook API Explporer for Query
[self.textNoteOrLink setText:
[NSString stringWithFormat:#"https://graph.facebook.com/[PAGEID]?fields=likes&access_token=%#",appDelegate.session.accessTokenData.accessToken]];
but if i am writing below Query its not giving me response as in Facebook Explorer API
QUERY:
[self.textNoteOrLink setText:
[NSString stringWithFormat:#"https://graph.facebook.com/PAGEID/insights/page_fans?access_token=%#",appDelegate.session.accessTokenData.accessToken]];
RESPONSE:
{"data":[
],"paging":{
"previous":"https:\/\/graph.facebook.com\/PAGEID\/insights\/page_fans?access_token=CAA...snip...h2l&since=1378984583&until=1379243783","next":"https:\/\/graph.facebook.com\/PAGEID\/insights\/page_fans?access_token=CAA...snip...h2l&since=1379502983&until=1379762183"}}
Can anyone help me to get access code with get_insights permission in Facebook iOS SDK?
In SLAppDelegate.h
Under the list of #property, add:
-(BOOL)openSessionWithAllowLoginUI:(BOOL)allowLoginUI;
In SLAppDelegate.m
Under applicationDidBecomeActive, add:
/*
* Opens a Facebook session and optionally shows the login UX.
*/
- (BOOL)openSessionWithAllowLoginUI:(BOOL)allowLoginUI {
NSArray *permissions = [[NSArray alloc] initWithObjects:
#"read_insights",
nil];
return [FBSession openActiveSessionWithReadPermissions:permissions
allowLoginUI:allowLoginUI
completionHandler:^(FBSession *session,
FBSessionState state,
NSError *error) {
[self sessionStateChanged:session
state:state
error:error];
}];
}
And:
/*
* Callback for session changes.
*/
- (void)sessionStateChanged:(FBSession *)session
state:(FBSessionState) state
error:(NSError *)error
{
switch (state) {
case FBSessionStateOpen:
if (!error) {
// We have a valid session
NSLog(#"User session found");
}
break;
case FBSessionStateClosed:
case FBSessionStateClosedLoginFailed:
[FBSession.activeSession closeAndClearTokenInformation];
break;
default:
break;
}
if (error) {
UIAlertView *alertView = [[UIAlertView alloc]
initWithTitle:#"Error"
message:error.localizedDescription
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alertView show];
}
}
In SLViewController.h
At the end of viewDidLoad , add:
[appDelegate openSessionWithAllowLoginUI:NO];
I am logging in into facebook in this way:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[FBSession openActiveSessionWithReadPermissions:nil
allowLoginUI:YES
completionHandler:
^(FBSession *session,
FBSessionState state, NSError *error) {
[self sessionStateChanged:session state:state error:error];
}];
return YES;
}
- (void)sessionStateChanged:(FBSession *)session
state:(FBSessionState) state
error:(NSError *)error
{
switch (state) {
case FBSessionStateOpen:
if (!error) {
// We have a valid session
//NSLog(#"User session found");
// Initiate a Facebook instance
self.facebook = [[Facebook alloc]
initWithAppId:FBSession.activeSession.appID
andDelegate:nil];
// Store the Facebook session information
self.facebook.accessToken = FBSession.activeSession.accessToken;
self.facebook.expirationDate = FBSession.activeSession.expirationDate;
}
break;
case FBSessionStateClosed:
case FBSessionStateClosedLoginFailed:
[FBSession.activeSession closeAndClearTokenInformation];
// Clear out the Facebook instance
self.facebook = nil;
break;
default:
break;
}
if (error) {
UIAlertView *alertView = [[UIAlertView alloc]
initWithTitle:#"Error"
message:error.localizedDescription
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alertView show];
}
}
- (BOOL)application:(UIApplication *)application
openURL:(NSURL *)url
sourceApplication:(NSString *)sourceApplication
annotation:(id)annotation {
// attempt to extract a token from the url
self.openedURL = url;
// attempt to extract a token from the url
return [FBSession.activeSession handleOpenURL:url];
}
...and I get the error: Error: HTTP status code: 400
I have set up the URL scheme in the plist. Why am I getting this?
Check in the App Dashboard. Look at your Basic Settings. Your Sandbox Mode may be set to Enabled. The errors should go away when your app is out of Sandbox mode.
I'm using the FB iOS SDK to get the user's credentials and access token and save them. With the previous version I managed to properly do this, but my solution broke with the upgrade to iOS 6, so I downloaded the new version from Github, and compiled and added the framework to my project according to the instructions.
I properly authenticate my user with FB, but when the browser (the modal view controller presented for auth) is dismissed my user reverts to the initial view of my app instead of the view that the process was launched from.
Right now I have code in my app delegate and my SocialNetworksViewController to do this.
In AppDelegate:
-(BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
return [FBSession.activeSession handleOpenURL:url];
}
- (void)sessionStateChanged:(FBSession *)session
presentingViewController:(UIViewController *)presentingViewController
state:(FBSessionState) state
error:(NSError *)error
{
switch (state) {
case FBSessionStateOpen: {
[presentingViewController dismissModalViewControllerAnimated:YES];
}
break;
case FBSessionStateClosed:
case FBSessionStateClosedLoginFailed:
// Once the user has logged in, we want them to
// be looking at the root view.
[FBSession.activeSession closeAndClearTokenInformation];
break;
default:
break;
}
[[NSNotificationCenter defaultCenter] postNotificationName:FBSessionStateChangedNotification
object:session];
if (error) {
UIAlertView *alertView = [[UIAlertView alloc]
initWithTitle:#"Error"
message:error.localizedDescription
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alertView show];
}
}
- (void)openSessionFromViewController:(UIViewController *)viewController
{
NSArray *permissions = [NSArray arrayWithObjects:#"publish_stream", #"email", #"user_birthday", nil];
[FBSession openActiveSessionWithPermissions:permissions
allowLoginUI:YES
completionHandler:
^(FBSession *session,
FBSessionState state, NSError *error) {
[self sessionStateChanged:session presentingViewController:viewController state:state error:error];
}];
}
In SocialNetworksViewController:
- (IBAction)connectToFacebook:(UIButton *)sender {
if (!self.facebookConnected) {
AppDelegate <UIApplicationDelegate> *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
[appDelegate openSessionFromViewController:self];
}
}
- (void)sessionStateChanged:(NSNotification*)notification {
NSLog(#"%#", FBSession.activeSession.accessToken);
}
- (void)facebookLoginFailed {
}
This is in viewDidLoad as well:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(sessionStateChanged:)
name:FBSessionStateChangedNotification
object:nil];
In the sessionStateChanged method, the NSLog outputs and then I get send to my initial view.
I am using Facebook SDK 3.0 (with Xcode 4.3.2 also and with ARC disabled), I already wrote the codes for login and post a text message on my own Facebook wall (codes above), everything run perfectly :
- (IBAction)loginFacebook:(id)sender {
// Initiate a Facebook instance
Facebook *facebook = [[Facebook alloc] initWithAppId:#"My_App_ID" andDelegate:nil];
// Set the session information for the Facebook instance
facebook.accessToken = self.session.accessToken;
facebook.expirationDate = self.session.expirationDate;
// Put together the dialog parameters
NSMutableDictionary *params = [NSMutableDictionary dictionaryWithObjectsAndKeys:
#"I'm using Emoji-Smileys", #"name",
#"Facebook for iOS", #"caption",
#"Check out the application Emoji-Smileys for iOS to enable emoji keyboard, and make fun messages! There are 460 smileys!", #"description",
#"http://m.facebook.com/apps/hackbookios/", #"link",
#"http://a365.phobos.apple.com/us/r30/Purple/v4/fa/96/4c/fa964c2a-3a48-4f6d-7789-d3105a392a9f/mzl.evuvwyjk.png?downloadKey=1343552764_471c078e9d07fde2b00bd3f1ee1d88a7", #"picture",
nil];
// Invoke the dialog
[facebook dialog:#"feed" andParams:params andDelegate:self];
}
- (FBSession *)createNewSession
{
self.session = [[FBSession alloc] init];
return self.session;
}
- (void)sessionStateChanged:(FBSession *)session
state:(FBSessionState) state
error:(NSError *)error
{
switch (state) {
case FBSessionStateOpen:
if (!error) {
// We have a valid session
NSLog(#"User session found");
}
break;
case FBSessionStateClosed:
case FBSessionStateClosedLoginFailed:
[session closeAndClearTokenInformation];
self.session = nil;
[self createNewSession];
break;
default:
break;
}
if (error) {
UIAlertView *errorAlert = [[UIAlertView alloc]
initWithTitle:#"Error"
message:error.localizedDescription
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[errorAlert show];
}
}
- (void) openSession {
[self.session openWithCompletionHandler:
^(FBSession *session, FBSessionState state, NSError *error) {
[self sessionStateChanged:session state:state error:error];
}];
}
- (BOOL)application:(UIApplication *)application
openURL:(NSURL *)url
sourceApplication:(NSString *)sourceApplication
annotation:(id)annotation
{
return [self.session handleOpenURL:url];
}
Okay, now, I'd like to know how to post an image that I give in my application, no need to use the UIImagePickerViewController, I don't want to select the image. I don't know if I need a publish_stream, read_stream or user_likes permission or other thing.
Thanks in advance for your help.
Cheers.
You can use this code, which helped me:
[FBRequestConnection startForUploadPhoto:myImg.image
completionHandler:^(FBRequestConnection *connection, id result, NSError *error) {
if (!error) {
// is success do something...
} else {
// If some error , do something...
}
}];
myImg is your image which you can replace with:
[UIImage imageNamed:#"image.jpg"]
I bet these tutorials will help you a lot:
http://www.raywenderlich.com/1488/how-to-use-facebooks-new-graph-api-from-your-iphone-app
http://www.raywenderlich.com/1578/how-to-get-a-user-profile-with-facebooks-new-graph-api-from-your-iphone-app
http://www.raywenderlich.com/1626/how-to-post-to-a-users-wall-upload-photos-and-add-a-like-button-from-your-iphone-app
And bookmark this site, it has a lot of great tutorials!)