After logging in with Facebook SDK. I am able to create a new PFUser but the e-mail address of this user does not save in my Databrowser. How can I get this done?
Action for the button:
- (IBAction)didTapFb:(id)sender {
[activityIndicator startAnimating];
PFUser *user = [PFUser currentUser];
if (![PFFacebookUtils isLinkedWithUser:user]) {
[PFFacebookUtils linkUser:user permissions:nil block:^(BOOL succeeded, NSError *error) {
if (succeeded) {
NSLog(#"Woohoo, user logged in with Facebook!");
}
}];
NSArray *permissionsArray = #[ #"user_about_me", #"user_relationships", #"user_birthday", #"user_location", #"email"];
[PFFacebookUtils logInWithPermissions:permissionsArray block:^(PFUser *user, NSError *error) {
if (!user) {
if (!error) {
NSLog(#"Uh oh. The user cancelled the Facebook login.");
} else {
NSLog(#"Uh oh. An error occurred: %#", error);
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:nil message:#"Error en conexión." delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
}
} else if (user.isNew) {
NSLog(#"User with facebook signed up and logged in!");
[self performSegueWithIdentifier:#"MaintoLook" sender:self];
} else {
NSLog(#"User with facebook logged in!");
[self performSegueWithIdentifier:#"MaintoLook" sender:self];
[activityIndicator stopAnimating];
}
}];
}
}
Related
I am trying to login a user through facebook in my parse.com app. I have all the ids and appdelegate methods in place.
I have created a view in the storyboard and made that a facebook login button and then i have connected it to my .h file as a IBAction.
my code:
- (IBAction)fblogin:(FBSDKLoginButton *)sender {
[PFFacebookUtils logInInBackgroundWithReadPermissions:#[#"public_profile", #"email"] block:^(PFUser *user, NSError *error) {
if (error) {
// NSLog(#"Uh oh. The user cancelled the Facebook login.");
UIAlertView *alertVeiw = [[UIAlertView alloc] initWithTitle:#"Sorry" message:[error.userInfo objectForKey:#"error"] delegate:nil cancelButtonTitle:#"Ok" otherButtonTitles:nil];
[alertVeiw show];
} else if (!user) {
UIAlertView *alertVeiw = [[UIAlertView alloc] initWithTitle:#"Sorry" message:#"You cancelled Login, try again!" delegate:nil cancelButtonTitle:#"Ok" otherButtonTitles:nil];
[alertVeiw show];
}else {
// NSLog(#"User logged in through Facebook!");
// [self dismissViewControllerAnimated:YES completion:NULL];
FBSDKGraphRequest *request = [[FBSDKGraphRequest alloc] initWithGraphPath:#"me" parameters:#{#"fields": #"first_name, last_name, email, public_profile"}];
[request startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error)
{
if (error)
{
UIAlertView *alertVeiw = [[UIAlertView alloc] initWithTitle:#"Sorry" message:[error.userInfo objectForKey:#"error"] delegate:nil cancelButtonTitle:#"Ok" otherButtonTitles:nil];
[alertVeiw show];
} else if ([[error userInfo][#"error"][#"type"] isEqualToString: #"OAuthException"]) { // Since the request failed, we can check if it was due to an invalid session
// NSLog(#"The facebook session was invalidated");
[PFFacebookUtils unlinkUserInBackground:[PFUser currentUser]];
}
else {
NSDictionary *userData = (NSDictionary *)result;
// [self requestFacebookUser:user];
NSString *name = userData[#"name"];
NSString *email = userData[#"email"];
user.username = name;
user.email = email;
[user saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error)
{
if (error)
{
UIAlertView *alertVeiw = [[UIAlertView alloc] initWithTitle:#"Sorry" message:[error.userInfo objectForKey:#"error"] delegate:nil cancelButtonTitle:#"Ok" otherButtonTitles:nil];
[alertVeiw show];
}
else {
// [self dismissViewControllerAnimated:NO completion:nil];
//[self.navigationController popToRootViewControllerAnimated:NO];
[self performSegueWithIdentifier:#"inbox" sender:self];
}
}];
}
}];
}
}];
}
The faccebook web page opens when i press login facebook button then we sign in and then nothing happens.
Please help me implement facebook login step by step correctly.
EDIT:
app delegate:
[PFFacebookUtils initializeFacebookWithApplicationLaunchOptions:launchOptions];
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
return [[FBSDKApplicationDelegate sharedInstance] application:application
openURL:url
sourceApplication:sourceApplication
annotation:annotation];
}
applicationWillEnterForeGround:
[FBSDKAppEvents activateApp];
then:
along with your(SanitLee) answer i have these methods:
- (void)loginViewFetchedUserInfo:(FBSDKLoginManager *)loginView
user:(FBSDKProfile*)user {
}
-(void)loginButton:(FBSDKLoginButton *)loginButton didCompleteWithResult:(FBSDKLoginManagerLoginResult *)result error:(NSError *)error{
// [self performSegueWithIdentifier:#"inbox" sender:self];
}
-(void)loginButtonDidLogOut:(FBSDKLoginButton *)loginButton{
}
-(void)loginButtonClicked{
}
i also get this error on whose view is not in the window hierarchy!
Here's how I did it and it works for me.
Firstly, import this in your m file:
#import <ParseFacebookUtils/PFFacebookUtils.h>//fb login for parse
Then the following codes should do what you want:
- (IBAction)loginButtonTouchHandler:(id)sender {
NSArray *permissionsArray = #[ #"user_about_me", #"user_relationships", #"user_birthday", #"user_location"];
[MBProgressHUD showHUDAddedTo:self.view animated:YES];
[PFFacebookUtils logInWithPermissions:permissionsArray block:^(PFUser *user, NSError *error) {
if (!user) {
NSString *errorMessage = nil;
if (!error) {
NSLog(#"Uh oh. The user cancelled the Facebook login.");
errorMessage = NSLocalizedString(#"Uh oh. The user cancelled the Facebook login.", nil);
} else {
NSLog(#"Uh oh. An error occurred: %#", error);
errorMessage = [error localizedDescription];
}
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(#"Log In Error", nil) message:errorMessage delegate:nil cancelButtonTitle:nil otherButtonTitles:NSLocalizedString(#"Dismiss", nil), nil];
[MBProgressHUD hideHUDForView:self.view animated:YES];
[alert show];
} else {
if (user.isNew) {
NSLog(#"User with facebook signed up and logged in!");
[self _loadData];
} else {
NSLog(#"User with facebook logged in!");
}
[MBProgressHUD hideHUDForView:self.view animated:YES];
[self _presentNextViewControllerAnimated:YES];
}
}];
}
- (void)_presentNextViewControllerAnimated:(BOOL)animated {
PAWWallViewController *wallViewController = [[PAWWallViewController alloc] initWithNibName:nil bundle:nil];
[(UINavigationController *)self.presentingViewController pushViewController:wallViewController animated:NO];
[self.presentingViewController dismissModalViewControllerAnimated:YES];
}
- (void)_loadData {
FBRequest *request = [FBRequest requestForMe];
[request startWithCompletionHandler:^(FBRequestConnection *connection, id result, NSError *error) {
if (!error) {
PFUser *user = [PFUser currentUser];
NSDictionary *userData = (NSDictionary *)result;
NSString *facebookID = userData[#"id"];
NSString *name = userData[#"name"];
NSString *email = userData[#"email"];
NSString *location = userData[#"location"][#"name"];
NSString *gender = userData[#"gender"];
NSString *birthday = userData[#"birthday"];
NSString *relationship = userData[#"relationship_status"];
NSString *facebookLink = [NSString stringWithFormat:#"Facebook.com/%#", facebookID];
NSURL *pictureURL = [NSURL URLWithString:[NSString stringWithFormat:#"https://graph.facebook.com/%#/picture?type=large&return_ssl_resources=1", facebookID]];
NSLog(#"facebookID --> %#", facebookID);
NSLog(#"name --> %#", name);
NSLog(#"email --> %#", email);
//for profile image
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:pictureURL];
// Run network request asynchronously
[NSURLConnection sendAsynchronousRequest:urlRequest queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
if (connectionError == nil && data != nil) {
PFFile *userImageFile = [PFFile fileWithName:#"userImage.jpg" data:data];
if (userImageFile) [user setObject:userImageFile forKey:kPAWParseUserImageKey];
}
[user setObject:facebookID forKey:kPAWParseUsernameKey]; //initially use fb id as username to avoid duplication
[user setObject:name forKey:kPAWParseRealnameKey];
[user setObject:facebookLink forKey:kPAWParseFacebookKey];
[user saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
if (!error) {
if (succeeded) {
NSLog(#"fb user saved successfully");
}
} else {
NSLog(#"fb user saved unsuccessfully");
}
}];
}];
} else if ([[[[error userInfo] objectForKey:#"error"] objectForKey:#"type"]
isEqualToString: #"OAuthException"]) {
NSLog(#"The facebook session was invalidated");
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:NSLocalizedString(#"Log out of Spotpost?", nil) message:nil delegate:self cancelButtonTitle:NSLocalizedString(#"Log out", nil) otherButtonTitles:NSLocalizedString(#"Cancel", nil), nil];
[alertView show];
} else {
NSLog(#"Some other error: %#", error);
}
}];
}
And here is how I did config in app delegate:
#import <ParseFacebookUtils/PFFacebookUtils.h> //fb login for parse
....
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
...
[PFFacebookUtils initializeFacebook]; //fb login for parse
return YES;
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
....
[FBAppCall handleDidBecomeActiveWithSession:[PFFacebookUtils session]]; //fb login for parse
}
- (BOOL)application:(UIApplication *)application
openURL:(NSURL *)url
sourceApplication:(NSString *)sourceApplication
annotation:(id)annotation {
return [FBAppCall handleOpenURL:url
sourceApplication:sourceApplication
withSession:[PFFacebookUtils session]];
}
- (void)applicationWillTerminate:(UIApplication *)application {
[[PFFacebookUtils session] close];
}
I'm using Parse and Facebook for account management in my app. Whenever the user logs in through the facebook button, my code works perfectly because facebook sdk automatically generates a new access token. However, if I use an autologin code which checks whether user has already approved of the app, I have no access token and can't access facebook data for that user. I don't know how to request an access token for a user who has already agreed to use my app.
Loading data:
- (void)_loadData :(BOOL)updateData
{
NSLog(#"entered _loadData");
NSMutableDictionary* userInfoParams = [NSMutableDictionary dictionary];
[userInfoParams setValue:#"id,name,email,gender" forKey:#"fields"];
if([FBSDKAccessToken currentAccessToken])
{
NSLog(#"Expiration date of token: %#", [[FBSDKAccessToken currentAccessToken] expirationDate]);
}
else NSLog(#"No access token");
FBSDKGraphRequest *request = [[FBSDKGraphRequest alloc] initWithGraphPath:#"me" parameters:userInfoParams];
[request startWithCompletionHandler:^(FBSDKGraphRequestConnection* connection, id result, NSError* error)
{
if(!error)
{
...
}
}
}
Auto-login system:
(void)viewDidAppear:(BOOL)animated
{
if ([PFUser currentUser] || [PFFacebookUtils isLinkedWithUser:[PFUser currentUser]])
{
NSLog(#"Yes");
[self _loadData:YES];
[self transitionToLoginSegue:(id)self];
}
else NSLog(#"No");
}
Also, the access tokens I receive when user clicks through the log in button last for 4 weeks, so if there was a way to manually assign an access token then I could do that, however [FBSDKAccessToken currentAccessToken] is not assignable so I can't do that either.
This is my code below,
if ([self check_network])
{
START_LOAD;
FBSDKLoginManager *login = [[FBSDKLoginManager alloc] init];
[login
logInWithReadPermissions: #[#"public_profile",#"email",#"user_friends"]
fromViewController:self
handler:^(FBSDKLoginManagerLoginResult *result, NSError *error) {
if (error) {
STOP_LOAD;
NSLog(#"Process error");
NSLog(#"%#",error);
TOAST_FOR_TRY_AGAIN;
/*
UIAlertView *alert=[[UIAlertView alloc] initWithTitle:#"Please Try Again"
message:nil
delegate:self
cancelButtonTitle:#"Ok"
otherButtonTitles: nil];
[alert show];
*/
} else if (result.isCancelled)
{
STOP_LOAD;
NSLog(#"Cancelled");
} else
{
NSLog(#"Logged in");
NSLog(#"Result=%#",result);
[[[FBSDKGraphRequest alloc] initWithGraphPath:#"me" parameters:#{ #"fields": #"id,first_name,middle_name,last_name,name,picture,email"}]
startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error)
{
NSLog(#"Facebook result=%#",result);
if (!error)
{
[NSUSER setObject:result forKey:#"user_info"];
[NSUSER setObject:[result objectForKey:#"name"] forKey:#"skip_name"];
[NSUSER synchronize];
API_CALL_ALLOC(ls_apicall);
[ls_apicall Login: STRING([result objectForKey:#"id"])];
} else {
STOP_LOAD;
NSLog(#"An error occurred getting friends: %#", [error localizedDescription]);
}
}];
}
}];
}
else
{
TOAST(TOAST_NETWORK_ERROR);
}
In the Parse docs, it says that you can check if a user is linked to a Facebook account, but is there any way to do it vice versa? For example, suppose the user clicks a button to sign in with Facebook, since [PFUser currentUser] is nil (because the user hasn't logged in yet), Parse will create a NEW account for that user since you can't use [PFFacebookUtils isLinkedWithUser: [PFUser currentUser]]. It seems like the only way to link an account is after the user has logged in regularly(i.e. entering their username and password), but that's really inconvenient. What if the user has already created an accounted manually (by filling out a the registration form I provide) and then decides to link their Facebook account? SO is there anyway to check if a Facebook account is linked with a user in general rather than checking it against a specific user?
Ok here is the solution. Basically iterate through every user and see if Facebook account is linked with that. based on that, link or create a new account. Here is code:
PFQuery *userQuery = [PFUser query];
[userQuery findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
NSUInteger count = [objects count];
BOOL linked = NO;
for(NSUInteger i = 0; i < count; i++){
PFUser *checkUser = objects[i];
if([PFFacebookUtils isLinkedWithUser:checkUser]){
linked = YES;
NSLog(#"profile is linked to a user");
break;
}
}
if(linked == YES){
[PFFacebookUtils logInWithPermissions:_permissions block:^(PFUser *user, NSError *error) {
if(!user){
NSLog(#"facebook cancelled");
}
else{
_type = #"twitter";
[self performSegueWithIdentifier:#"showMain" sender:self]; }
}
];
}
else{
CCAlertView *ask = [[CCAlertView alloc]initWithTitle:#"Are you already registered" message:nil];
[ask addButtonWithTitle:#"No" block:^{
[PFFacebookUtils logInWithPermissions:_permissions block:^(PFUser *user, NSError *error) {
if(!user){
NSLog(#"Facebook cancelled");
}
else if(user.isNew){
_type = #"facebook";
[self performSegueWithIdentifier:#"showMain" sender:self]; }
else{
[self performSegueWithIdentifier:#"showMain" sender:self]; }
}];
}];
[ask addButtonWithTitle:#"Yes" block:^{
CCAlertView *log = [[CCAlertView alloc]initWithTitle:#"Enter username and password" message:nil];
[log setAlertViewStyle:UIAlertViewStyleLoginAndPasswordInput];
UITextField *un = [log textFieldAtIndex:0];
UITextField *pw = [log textFieldAtIndex:1];
[log addButtonWithTitle:#"Cancel" block:nil];
[log addButtonWithTitle:#"Enter" block:^{
[PFUser logInWithUsernameInBackground:[un text] password:[pw text] block:^(PFUser *user, NSError *error) {
if(user){
[PFFacebookUtils linkUser:user permissions:_permissions block:^(BOOL succeeded, NSError *error) {
if(succeeded){
NSLog(#"linked");
[self performSegueWithIdentifier:#"showMain" sender:self]; }
else{
NSLog(#"couldnt link");
}
}];
}
else{
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:#"Oops!" message:[error userInfo] delegate:self cancelButtonTitle:nil otherButtonTitles:#"okay", nil];
[alert show];
}
}];
}];
[log show];
}];
[ask show];
}
}];
I'm implementing the Parse / Facebook login for iOS and it's working well - I'm logged in with my own FB user and everything is fine.
But now I want to log in to my iOS application from a different FB user - a tester's account. This is what I did:
Went to my FB application on my iPhone, logged out, and logged in again with my Test account.
Went back to my iOS / Parse application and attempted to Login With Facebook.
The result is that I'm logged in with my own account!
I uninstalled the app, and re-run it from xCode, logged in with Facebook - and I'm back in using my own account again.
No matter what I do, I keep going back to my own account. It looks like Parse, or FB, is cacheing my info somehow. How do I un-cache it to get a fresh start?
This is my login method:
- (void)loginWithFB {
NSArray *permissionsArray = #[ #"user_about_me", #"user_relationships", #"user_birthday", #"user_location"];
// Login PFUser using facebook
[PFFacebookUtils logInWithPermissions:permissionsArray block:^(PFUser *user, NSError *error) {
[_activityIndicator stopAnimating]; // Hide loading indicator
if (!user) {
if (!error) {
NSLog(#"Uh oh. The user cancelled the Facebook login.");
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Log In Error" message:#"Uh oh. The user cancelled the Facebook login." delegate:nil cancelButtonTitle:nil otherButtonTitles:#"Dismiss", nil];
[alert show];
} else {
NSLog(#"Uh oh. An error occurred: %#", error);
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Log In Error" message:[error description] delegate:nil cancelButtonTitle:nil otherButtonTitles:#"Dismiss", nil];
[alert show];
}
} else if (user.isNew) {
NSLog(#"User with facebook signed up and logged in!");
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
appDelegate.window.rootViewController = appDelegate.tabBarController;
[appDelegate.tabBarController setSelectedIndex:3];
[self.navigationController pushViewController:[[MyTrack alloc] init] animated:YES];
} else {
NSLog(#"User with facebook logged in!");
FBRequest *request = [FBRequest requestForMe];
[request startWithCompletionHandler:^(FBRequestConnection *connection, id result, NSError *error) {
if (!error) {
NSString *facebookUsername = [result objectForKey:#"username"];
[PFUser currentUser].username = facebookUsername;
[[PFUser currentUser] saveEventually];
NSLog(#"Welcome Screen I am %#", [[PFUser currentUser] username]);
} else {
NSLog(#"Error getting the FB username %#", [error description]);
}
}];
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
appDelegate.window.rootViewController = appDelegate.tabBarController;
[appDelegate.tabBarController setSelectedIndex:0];
}
}];
[_activityIndicator startAnimating]; // Show loading indicator until login is finished
}
Please try this when you logout
[FBSession.activeSession close];
[FBSession.activeSession closeAndClearTokenInformation];
FBSession.activeSession = nil;
- (IBAction)LoginViaFb:(id)sender {
// Set permissions required from the facebook user account
NSArray *permissionsArray = #[ #"user_email", #"user_relationships", #"user_birthday", #"user_location"];
// Login PFUser using facebook
[PFFacebookUtils logInWithPermissions:permissionsArray block:^(PFUser *user, NSError *error) {
NSLog(#"user=%#",user);
if (!user) {
if (!error) {
NSLog(#"Uh oh. The user cancelled the Facebook login.");
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Log In Error" message:#"Uh oh. The user cancelled the Facebook login." delegate:nil cancelButtonTitle:nil otherButtonTitles:#"Dismiss", nil];
[alert show];
} else {
NSLog(#"Uh oh. An error occurred --- %#", error);
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Log In Error" message:[error description] delegate:nil cancelButtonTitle:nil otherButtonTitles:#"Dismiss", nil];
[alert show];
}
} else if (user.isNew) {
NSLog(#"User with facebook signed up and logged in!");
} else {
NSLog(#"User with facebook logged in!");
}
// If the user is already logged in, display any previously cached values before we get the latest from Facebook.
if ([PFUser currentUser]) {
[self updateProfile];
}
// Send request to Facebook
FBRequest *request = [FBRequest requestForMe];
[request startWithCompletionHandler:^(FBRequestConnection *connection, id result, NSError *error) {
// handle response
if (!error) {
// Parse the data received
NSDictionary *userData = (NSDictionary *)result;
NSLog(#"userData -------- %#",userData);
NSString *facebookID = userData[#"id"];
NSMutableDictionary *userProfile = [NSMutableDictionary dictionaryWithCapacity:7];
if (facebookID) {
userProfile[#"facebookId"] = facebookID;
}
if (userData[#"name"]) {
userProfile[#"name"] = userData[#"name"];
}
if (userData[#"location"][#"name"]) {
userProfile[#"location"] = userData[#"location"][#"name"];
}
if (userData[#"gender"]) {
userProfile[#"gender"] = userData[#"gender"];
}
if (userData[#"birthday"]) {
userProfile[#"birthday"] = userData[#"birthday"];
}
if (userData[#"relationship_status"]) {
userProfile[#"relationship"] = userData[#"relationship_status"];
}
[[PFUser currentUser] setObject:userProfile forKey:#"profile"];
[[PFUser currentUser] saveInBackground];
[self updateProfile];
} else if ([[[[error userInfo] objectForKey:#"error"] objectForKey:#"type"]
isEqualToString: #"OAuthException"]) { // Since the request failed, we can check if it was due to an invalid session
NSLog(#"The facebook session was invalidated");
} else {
NSLog(#"Some other error: %#", error);
}
}];
}];
After writing this code, my log shows:
user=(null)
Uh oh. An error occurred ---
Error Domain=com.facebook.sdk Code=2 "The operation couldn’t be completed. (com.facebook.sdk error 2.)" UserInfo=0xbf6f0c0 {com.facebook.sdk:ErrorLoginFailedReason=com.facebook.sdk:SystemLoginDisallowedWithoutError, com.facebook.sdk:ErrorSessionKey=, expirationDate: (null), refreshDate: (null), attemptedRefreshDate: 0001-12-30 00:00:00 +0000, permissions:(null)>}
Please help, where i am doing mistake? and Thanks in advance.