I STILL NEED AN ANSWER
I have the view controller where facebook login button was added. I have class: FacebookAuth with method:
- (void) performAuth {
[FBSession openActiveSessionWithReadPermissions:nil
allowLoginUI:YES
completionHandler:
^(FBSession *session,
FBSessionState state, NSError *error) {
[self fbSessionStateChanged:session state:state error:error];
}];
}
In my facebook view controller I have the IBAction:
- (IBAction)performFBLogin:(id)sender {
FacebookAuth *fbAuth = [[FacebookAuth alloc] init];
[fbAuth performAuth];
[self.navigationController popToRootViewControllerAnimated:YES];
}
The question is: how to call [self.navigationController popToRootViewControllerAnimated:YES]; after performAuth is performed.
According to the official guide there is a callback in the AppDelegate:
// During the Facebook login flow, your app passes control to the Facebook iOS app or Facebook in a mobile browser.
// After authentication, your app will be called back with the session information.
- (BOOL)application:(UIApplication *)application
openURL:(NSURL *)url
sourceApplication:(NSString *)sourceApplication
annotation:(id)annotation
{
return [FBAppCall handleOpenURL:url sourceApplication:sourceApplication];
}
Thanks in advance.
i'm note sure but Have you try this way,
- (void) performAuth {
[FBSession openActiveSessionWithReadPermissions:nil
allowLoginUI:YES
completionHandler:
^(FBSession *session,
FBSessionState state, NSError *error) {
[self fbSessionStateChanged:session state:state error:error];
[self.navigationController popToRootViewControllerAnimated:YES];
}];
}
Related
I am new to IOS and I created a Facebook custom login and logout buttons for my app using Facebook SDK. Login button works as I expected, but when I clicked my logout button, it gives the login page as I redirected to it. Then, when I try to login again, it doesn't show the Facebook login UI. But when I logged out my Facebook app and try to login to my app, the login UI works well. Here is my logout button.
- (IBAction)btnClicked:(id)sender {
[FBSession.activeSession closeAndClearTokenInformation];
NSLog(#"log out");
LoginUIViewController *loginController1= [[LoginUIViewController alloc] initWithNibName:#"LoginUIViewController" bundle:nil];
[self presentViewController:loginController1 animated:YES completion:nil];
}
Do I need to implement a logout button in my view controller or does FB SDK provides the logout facility it self?
# Vinod Jat,,
I made following changes in my appDelegate..
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.viewController = [[SplashViewController alloc] initWithNibName:#"SplashViewController" bundle:nil];
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
// Whenever a person opens the app, check for a cached session
if (FBSession.activeSession.state == FBSessionStateCreatedTokenLoaded) {
// If there's one, just open the session silently, without showing the user the login UI
[FBSession openActiveSessionWithReadPermissions:#[#"public_profile"]
allowLoginUI:NO
completionHandler:^(FBSession *session, FBSessionState state, NSError *error) {
[self sessionStateChanged:session state:state error:error];
}];
}
return YES;
}
//This method will handle ALL the session state changes in the app
- (void)sessionStateChanged:(FBSession *)session state:(FBSessionState) state error:(NSError *)error
{
// If the session was opened successfully
if (!error && state == FBSessionStateOpen){
NSLog(#"Session opened");
return;
}
if (state == FBSessionStateClosed || state == FBSessionStateClosedLoginFailed){
// If the session is closed
NSLog(#"Session closed");
}
.........
}
**In my loginUIViewController I have added following method..**
- (IBAction)FbloginButton:(id)sender {
NSLog(#"inside login button");
[FBSession openActiveSessionWithReadPermissions:#[#"public_profile"]
allowLoginUI:YES
completionHandler:
^(FBSession *session, FBSessionState state, NSError *error) {
NSLog(#"inside login button2");
// Retrieve the app delegate
TNLAppDelegate* appDelegate = [UIApplication sharedApplication].delegate;
// Call the app delegate's sessionStateChanged:state:error method to handle session state changes
[appDelegate sessionStateChanged:session state:state error:error];
NSLog(#"inside login button3");
}];
//redirect to now playing page
NowPlayingViewController *nowPlaying= [[NowPlayingViewController alloc] initWithNibName:#"NowPlayingViewController" bundle:nil];
[self presentViewController:nowPlaying animated:YES completion:nil];
}
Situation:
Person login in FBApp but not login in System FB account.
What I do:
I ask readPermissions and publishPermissions. After that I send request for person identity (id,name,username,profile_picture_url).
Behaviour:
Everything works fine, facebook ios sdk go to fb app twice (for each request - read and publish) and after that miracle appears.
I request for person identity and see facebook window, which suggest to download fb app for iPhone (fb app've been already on it!) and ask me to login on website. I think that this is a safari login appears.
Code:
/*login here*/
if([_facebookSession state] == FBSessionStateCreated){
[FBSession openActiveSessionWithReadPermissions:readPermissions allowLoginUI:YES completionHandler:^(FBSession *session, FBSessionState status, NSError *error) {
if (error || status == FBSessionStateClosedLoginFailed){
[_facebookSession openWithBehavior:FBSessionLoginBehaviorWithNoFallbackToWebView completionHandler:^(FBSession *session, FBSessionState status, NSError *error) {
if (error || status == FBSessionStateClosedLoginFailed){
LoginFailedBlock(YES);
}
else
if (error == nil && status == FBSessionStateOpen){
_facebookSession = session;
LoginSucessBlock(YES);
}
}];
}else{
dispatch_async(dispatch_get_current_queue(), ^{
[FBSession openActiveSessionWithPublishPermissions:publishPermissions defaultAudience:FBSessionDefaultAudienceFriends allowLoginUI:YES completionHandler:^(FBSession *session, FBSessionState status, NSError *error) {
if (error == nil && status == FBSessionStateOpen){
_facebookSession = session;
LoginSucessBlock(YES);
}
}];
});
}
}];
/*request for person identity*/
/*SOMEWHERE HERE A SAFARI LOGIN WINDOW APPEARS*/
[FBRequestConnection startForMeWithCompletionHandler:^(FBRequestConnection *connection, id<FBGraphUser> result, NSError *error) {
if (error){
ErrorBlock(error);
}
else{
if ([result id] && [result name]){
NSDictionary* resultDictionary = #{#"id":result.id,
#"name":result.name,
#"username":result.username,
#"picture":result.link,
};
AfterLoadUserInfoBlock(YES,resultDictionary);
}
else{
AfterLoadUserInfoBlock(NO,nil);
}
}
}];
in view controller :
self.loginview = [[FBLoginView alloc] init];
self.loginview.frame = CGRectMake(-500, -500, 0, 0);
[self.view addSubview:self.loginview];
self.loginview.delegate = self;
[loginview setReadPermissions:#[#"basic_info",#"email"]];
[loginview setDelegate:self];
-(IBAction)loginWithFB:(id)sender{
for(id object in self.loginview.subviews){
if([[object class] isSubclassOfClass:[UIButton class]]){
UIButton* button = (UIButton*)object;
[button sendActionsForControlEvents:UIControlEventTouchUpInside];
}
}
}
in appdelegate :
- (BOOL)application:(UIApplication *)application
openURL:(NSURL *)url
sourceApplication:(NSString *)sourceApplication
annotation:(id)annotation {
// Call FBAppCall's handleOpenURL:sourceApplication to handle Facebook app responses
BOOL wasHandled = [FBAppCall handleOpenURL:url sourceApplication:sourceApplication];
// You can add your app-specific url handling code here if needed
return wasHandled;
}
then please register your application in developer.facebook.com with your bundle id finally you will get one id and configure in your plist file
I see this question asked in several other posts but nothing seems to work for me. After following the FB login guide I had a working prototype that would allow users to authenticate with FB. However this guide instructs you place all FB OAuth logic directly into the AppDelegate and that is not ideal for me since I will support more than just FB authentication. So what I have done is move the login logic into it's own class. Since then it seems that the FB delegate methods do not get called after a user successfully authenticates with FB and control should be passed back to my application.
I have a modal login view which takes my FacebookAuth class as a delegate. When I attempt to create a session the FB login page appears and I authorize my application. After that no other delegate methods are called. Can anyone provide some hints?
#interface FacebookAuth()
#property (nonatomic, strong) User *sessionUser;
#end
#implementation FacebookAuth
#synthesize sessionIsOpen = _sessionIsOpen;
#synthesize sessionUser = _sessionUser;
-(id)initWithViewDelegate:(id<AuthorizationViewDelegate>)viewDelegate
{
NSAssert(viewDelegate != nil, #"FacebookAuth must be initialized with a view delegate.");
self = [super init];
if (self) {
self.viewDelegate = viewDelegate;
}
return self;
}
-(id)init
{
self = [super init];
if (self) {
self = [self initWithViewDelegate:nil];
}
return self;
}
-(BOOL)sessionIsOpen{
return (FBSession.activeSession.state == FBSessionStateOpen);
}
-(void)requestSessionUserWithSuccess:(void (^)(User *))success Failure:(void (^)(NSError *))error{
if(!self.sessionIsOpen){
error([NSError errorWithDomain:#"Session Closed" code:0 userInfo:nil]);
return;
}
if(self.sessionUser == nil){
[[FBRequest requestForMe] startWithCompletionHandler:
^(FBRequestConnection *connection,
NSDictionary<FBGraphUser> *user,
NSError *err) {
if (!err) {
User *ses_user = [[User alloc]initWithId:user.id first:user.first_name last:user.last_name sessionToken: [[[FBSession activeSession] accessTokenData] accessToken]];
self.sessionUser = ses_user;
success(ses_user);
} else{
error(err);
}
}];
} else{
success(self.sessionUser);
}
}
-(void)openSession
{
[FBSession openActiveSessionWithReadPermissions:nil
allowLoginUI:YES
completionHandler:
^(FBSession *session,
FBSessionState state, NSError *error) {
[self sessionStateChanged:session state:state error:error];
}];
}
-(void)closeSession{
[FBSession.activeSession closeAndClearTokenInformation];
self.sessionUser = nil;
self.sessionIsOpen = NO;
};
-(void)sessionStateChanged:(FBSession *)session
state:(FBSessionState) state
error:(NSError *)error
{
switch (state) {
case FBSessionStateOpen:{
self.sessionIsOpen = YES;
[self.viewDelegate loginSuccess];
}
break;
case FBSessionStateClosed:{
self.sessionIsOpen = NO;
}
break;
case FBSessionStateClosedLoginFailed:{
[FBSession.activeSession closeAndClearTokenInformation];
self.sessionIsOpen = NO;
[self.viewDelegate loginFailure:error];
}
break;
default:
break;
}
}
-(BOOL)application:(UIApplication *)application
openURL:(NSURL *)url
sourceApplication:(NSString *)sourceApplication
annotation:(id)annotation
{
return [FBSession.activeSession handleOpenURL:url];
}
I apologize for the large code snippet but I don't want to leave out anything that may be valuable in assisting.
After calling
-(void)openSession:
The facebook authentication page appears and I authorize the application. After that I was expecting the FB delegate method to be called:
-(BOOL)application:(UIApplication *)application
openURL:(NSURL *)url
sourceApplication:(NSString *)sourceApplication
annotation:(id)annotation
It never is. Do I need to declare this class as a type of FB delegate? I am using the latest Facebook SDK available.
Any help would be great.
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. :)
I'm using facebook sdk 3.0.8 for ios. when i try to login with facebook it works fine but sometimes when i try to login after logging out then app is being crashed.
here is exception message
*** Assertion failure in -[FBSession close], /Users/jacl/src/ship/ios-sdk/src/FBSession.m:342
can you please tell me where i'm going wrong?
Here is code inside AppDelegate
- (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];
}
- (void)applicationWillTerminate:(UIApplication *)application {
[self.session close];
}
#pragma mark Template generated code
// FBSample logic
// It is possible for the user to switch back to your application, from the native Facebook application,
// when the user is part-way through a login; You can check for the FBSessionStateCreatedOpenening
// state in applicationDidBecomeActive, to identify this situation and close the session; a more sophisticated
// application may choose to notify the user that they switched away from the Facebook application without
// completely logging in
- (void)applicationDidBecomeActive:(UIApplication *)application {
/*
Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
*/
// FBSample logic
// this means the user switched back to this app without completing a login in Safari/Facebook App
if (self.session.state == FBSessionStateCreatedOpening) {
// BUG: for the iOS 6 preview we comment this line out to compensate for a race-condition in our
// state transition handling for integrated Facebook Login; production code should close a
// session in the opening state on transition back to the application; this line will again be
// active in the next production rev
//[self.session close]; // so we close our session and start over
}
}
Code Inside View Controller
-(IBAction)connectWithFacebook{
DemoAppDelegate *appDelegate = (TotallyCuteAppDelegate *) [[UIApplication sharedApplication]delegate];
if (!appDelegate.session.isOpen && (appDelegate.session.state != FBSessionStateCreated))
{
appDelegate.session = [[FBSession alloc] init];
}
NSArray *permissions = [[NSArray alloc] initWithObjects:
#"publish_actions",
#"email",
nil];
//app crashes here
[FBSession openActiveSessionWithPermissions:permissions allowLoginUI:YES
completionHandler:^(FBSession *session, FBSessionState status, NSError *error) {
if (session.isOpen)
{
NSLog(#"LoginVC->Session is open");
appDelegate.session=session;
[userDefaults setObject:appDelegate.session.accessToken forKey:#"facebook_token"];
[userDefaults setObject:paramFBId forKey:#"facebook_id"];
}
else
{
NSLog(#"LoginVC->Session is not open");
}
}//end completionHandler
];
}
-(IBAction)logout:(id)sender{
DemoAppDelegate *appDelegate = (TotallyCuteAppDelegate *) [[UIApplication sharedApplication]delegate];
if (appDelegate.session.isOpen) {
[appDelegate.session closeAndClearTokenInformation];
[[NSUserDefaults userDefaults] removeObjectForKey:#"facebook_id"];
[[NSUserDefaults userDefaults] removeObjectForKey:#"facebook_token"];
}
}
Edit:
removed the following code and now it works fine
if (!appDelegate.session.isOpen && (appDelegate.session.state != FBSessionStateCreated))
{
appDelegate.session = [[FBSession alloc] init];
}
here is updated code
-(IBAction)connectWithFacebook{
if ([InternetChecker isConnected])
{
DemoAppDelegate *appDelegate = (TotallyCuteAppDelegate *) [[UIApplication sharedApplication]delegate];
/* Removed following if block
if (!appDelegate.session.isOpen && (appDelegate.session.state != FBSessionStateCreated))
{
appDelegate.session = [[FBSession alloc] init];
}
*/
NSArray *permissions = [[NSArray alloc] initWithObjects:
#"publish_actions",
#"email",
nil];
[FBSession openActiveSessionWithPermissions:permissions allowLoginUI:YES
completionHandler:^(FBSession *session, FBSessionState status, NSError *error) {
if (session.isOpen)
{
NSLog(#"LoginVC->Session is open");
appDelegate.session=session;
[userDefaults setObject:appDelegate.session.accessToken forKey:#"facebook_token"];
[userDefaults setObject:paramFBId forKey:#"facebook_id"];
}
else
{
NSLog(#"LoginVC->Session is not open);
}
}//end completionHandler
];
}
}
Looking at FBSession.m, the assertion in close is as follows:
NSAssert(self.affinitizedThread == [NSThread currentThread], #"FBSession: should only be used from a single thread");
Are you calling -close from a thread other than the one you created the session on?
Looking into this further. You're misusing the API. You are creating
appDelegate.session = [[FBSession alloc] init];
but then you are calling
[FBSession openActiveSessionWithPermissions ...
which creates an entirely new session. Meaning you never opened appDelegate.session, and therefore you should not try to close it. What you should be doing instead is the following:
[FBSession openActiveSessionWithPermissions ...
appDelegate.session = [FBSession activeSession];
Another option is to just do:
appDelegate.session = [[FBSession alloc] init];
[appDelegate.session openWithCompletionHandler: ...
You should perform your code on the main thread
dispatch_async(dispatch_get_main_queue(), ^{
[FBSession openActiveSessionWithPermissions:permissions
allowLoginUI:YES
completionHandler:^(FBSession *session,
FBSessionState status,
NSError *error) {
// do something
}];
});