Facebook ios sdk 3 crash when try to use FBSessionLoginBehaviorForcingWebView - ios

I am using facebook sdk 3 with ios 5. I want to ask login window each time to user. Expect different users use app. I tried below code. It show login in a popover view inside app not with safari. But after I login or close window app crash.
NSArray *permissions = [NSArray arrayWithObjects:#"publish_actions", #"user_photos", nil];
FBSessionLoginBehavior behavior = FBSessionLoginBehaviorForcingWebView;
FBSessionTokenCachingStrategy *tokenCachingStrategy = [[FBSessionTokenCachingStrategy alloc]
initWithUserDefaultTokenInformationKeyName:#"FBTest"];
FBSession *session = [[FBSession alloc] initWithAppID:#"Appid"
permissions:permissions
urlSchemeSuffix:nil
tokenCacheStrategy:tokenCachingStrategy];
[session openWithBehavior:behavior
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) {
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Error"
message:error.localizedDescription
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alertView show];
}
NSLog(#"SUCEEES");
[self sessionStateChanged:session state:session.state error:error];
}];

FBLoginView *loginview = [[FBLoginView alloc] init];
loginview.frame = CGRectOffset(loginview.frame, 5, 5);
loginview.delegate = self;
[self.view addSubview:loginview];
[loginview sizeToFit];
This will ask for the login window each time

Related

How do I check if Touch ID is enrolled but disabled on iPhone?

I'm using the following logic to check if touchID is available on iPhone and based on the returned value, I direct the user to enroll in touchID or navigate them to setup a PIN. It works fine in the happy path, but if I have even one fingerprint enrolled but have disabled touchID option from iPhone system settings, then it still returns true and navigates user to setup touchID. If I remove all fingerprints, then it works as expected by returning false and navigating to PIN screen.
- (BOOL) isTouchIDAvailable {
LAContext *myContext = [[LAContext alloc] init];
NSError *authError = nil;
if (![myContext canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&authError]) {
NSLog(#"Touch ID checking error: %#", [authError localizedDescription]);
return NO;
}
return YES;
}
I've referred to some questions on stack and apple dev docs
Not sure what I'm missing? Appreciate any help. Thanks in advance :)
let context = LAContext()
var error: NSError?
if #available(iOS 9.0, *) {
if context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error) {
//this is for success
}else{
//error.description for type error LAError.biometryLockout, .biometryNotEnrolled and other errors
}
}
it's not possible. if you have TouchID, you have touchID. But if you want, you can disabled with programaticly. Look at the below code snippet to check touchID is aviable or not.
LAContext *myContext = [[LAContext alloc] init];
NSError *authError = nil;
NSString *myLocalizedReasonString = [NSString stringWithFormat:#"Login With your fingerprint with : %#",username];
if ([myContext canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&authError]) {
[myContext evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics
localizedReason:myLocalizedReasonString
reply:^(BOOL success, NSError *error) {
if (success) {
dispatch_async(dispatch_get_main_queue(), ^{
// [self performSegueWithIdentifier:#"Success" sender:nil];
[self loginWithFingerprint];
});
} else {
dispatch_async(dispatch_get_main_queue(), ^{
/*
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Error"
message:error.description
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:nil, nil];
[alertView show];
*/
// Rather than show a UIAlert here, use the error to determine if you should push to a keypad for PIN entry.
});
}
}];
} else {
dispatch_async(dispatch_get_main_queue(), ^{
/*
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Error"
message:authError.description
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:nil, nil];
[alertView show];
*/
// Rather than show a UIAlert here, use the error to determine if you should push to a keypad for PIN entry.
});
}

TouchID : How to get touch id authentication attempts?

I need to implement touch ID and have to show alert to user for authentication attempts left. Below code Im using.
reply block not getting called after one wrong authentication attempt. Its getting called after 3 continues wrong authentication attempt. Is there any way to get count of wrong authentication attempts..?
LAContext *myContext = [[LAContext alloc] init];
NSError *authError = nil;
NSString *myLocalizedReasonString = #"Touch ID Test to show Touch ID working in a custom app";
if ([myContext canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&authError]) {
[myContext evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics
localizedReason:myLocalizedReasonString
reply:^(BOOL success, NSError *error) {
if (success) {
dispatch_async(dispatch_get_main_queue(), ^{
[self performSegueWithIdentifier:#"Success" sender:nil];
});
} else {
dispatch_async(dispatch_get_main_queue(), ^{
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Error"
message:error.description
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:nil, nil];
[alertView show];
NSLog(#"Switch to fall back authentication - ie, display a keypad or password entry box");
});
}
}];
} else {
dispatch_async(dispatch_get_main_queue(), ^{
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Error"
message:authError.description
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:nil, nil];
[alertView show];
});
}
I went through the documentation, it is not possible to show alert in each failed attempt. Just refer the documentation
LocalAuthentication in iOS. You can show alerts at different error cases. After 3rd failed attempt LAError.authenticationFailed will be called and after 5th failed attempt LAError.touchIDLockout will be called. You can display the alerts here. For more info refer Apple LAError documentation.

Is user_photos needed?

Please excuse the elementary question but I am pretty confused on requesting Facebook permissions for my app. My app allows users to select photos then login to their facebook page and those photos are posted on their timeline. I am requesting manage_pages, publish_pages, and publish_actions. In my developer account I added two testers who are friends of mine and we thoroughly tested the process. Everything works perfectly. But when I created a Test User (the one where facebook creates a generic account) my app doesn't post photos to their wall. I granted the test user the same permissions. I am now wondering if I need to call user_photos as another requested permission. I don't think I do since I am not requesting access to the users photos or albums. I am simply posting photos to their timeline which I thought is what publish_pages and publish_actions does. Can you look at the code and see if you can find what I am doing wrong?
- (IBAction)facebookButtonClicked1:(id)sender
{
if ([self.selectedImages count] > 0)
{
FBSDKLoginManager *login = [[FBSDKLoginManager alloc] init];
login.loginBehavior = FBSDKLoginBehaviorWeb;
[login logInWithPublishPermissions:#[#"publish_actions"]
fromViewController:self
handler:^(FBSDKLoginManagerLoginResult *result, NSError *error) {
if (error) {
NSLog(#"Process error");
} else if (result.isCancelled) {
NSLog(#"Cancelled");
} else {
NSLog(#"Logged in");
[self shareSegmentWithFacebookComposer];
}
}];
}
else
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"No Photos" message:#"You have not selected any photo." delegate:self cancelButtonTitle:#"OK" otherButtonTitles: nil];
[alert show];
}
}
-(void)shareSegmentWithFacebookComposer{
if ([[FBSDKAccessToken currentAccessToken] hasGranted:#"publish_actions"]) {
[self publishFBPost]; //publish
} else {
NSLog(#"no publish permissions");
}
}
-(void) publishFBPost{
NSMutableArray* photos = [[NSMutableArray alloc] init];
for (NSString* imageFile in self.selectedImages) {
UIImage *image = [UIImage imageWithContentsOfFile:[dataPath stringByAppendingPathComponent:imageFile]];
FBSDKSharePhoto *photo = [[FBSDKSharePhoto alloc] init];
photo.image = image;
photo.userGenerated = YES;
[photos addObject:photo];
}
FBSDKSharePhotoContent *content = [[FBSDKSharePhotoContent alloc] init];
content.photos = [photos copy];
[FBSDKShareDialog showFromViewController:self
withContent:content
delegate:nil];
[FBSDKShareAPI shareWithContent:content delegate:nil];
viewThanks.hidden = NO;
[NSTimer scheduledTimerWithTimeInterval:4.5 target:self selector:#selector(start) userInfo:nil repeats:NO];
FBSDKShareDialog *shareDialog = [FBSDKShareDialog new];
[shareDialog setMode:FBSDKShareDialogModeAutomatic];
[shareDialog setShareContent:content];
[shareDialog show];
}
There were publish_stream permission to upload photos but in the latest SDK publish_actions have replaced publish_actions so you only need publish_actions. And if you want to see the user's photos then you need the user_photos permission.

How do you improve the speed of LoginAuthentication?

I'm working on adding the LocalAuthentication framework to allow users to authenticate with a fingerprint on comparable devices. Everything works properly, but when a user is authenticated with their finger print it takes between 10-15 seconds for the proper segue to be performed, is this typical, or is there something wrong with the way I'm authenticating a user?
Code:
-(void)viewDidLoad { [super viewDidLoad]; [self.view setBackgroundColor:[NPSColor NPSBackgroundColor]];
UIBarButtonItem *anotherButton = [[UIBarButtonItem alloc] initWithTitle:#"Register" style:UIBarButtonItemStylePlain target:self action:#selector(onRegisterTapped)]; self.navigationItem.rightBarButtonItem = anotherButton;
LAContext *context = [[LAContext alloc] init];
NSError *error = nil; if ([context canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&error]) { [context evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics localizedReason:#"Login?" reply:BOOL success, NSError *error {
if (error) {
}
if (success) {
[self performSegueWithIdentifier:#"loginSeg" sender:self];
} else {
}
}];
} else {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Error"
message:#"Your device cannot authenticate using TouchID."
delegate:nil
cancelButtonTitle:#"Ok"
otherButtonTitles:nil];
[alert show];
} }
So it may be that performing a segue has to do with a view action which should mainly be performed on the main thread. I'm not too sure but it could very well be the evaluatePolicy method is performed on a background thread. If this is the case, you would want to throw your performSegue on the main thread.
To do so, use this:
dispatch_async(dispatch_get_main_queue(), ^{
[self performSegueWithIdentifier:#"loginSeg" sender:self];
});

Redirect to Settings Screen for Twitter Login

In Twitter ,if User has Logged In in the Twitter Account in Settings Screen It will allow to post.Or Else it will display a Alert as "No Twitter Accounts" with 2 Options "Settings" and "Cancel". If Cancel is Tapped it will close alert and reject post to twitter. And if Settings is Tapped it is not redirecting to Settings Screen.
Also i used
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:#"prefs:root=TWITTER"]];
But No Luck. As far as i checked all are saying as from iOS 5.1 it wont work.But i see some apps still redirecting to settings screen in iOS7. Is it possible to redirect in iOS7.
Thanks in Advance.
You can use below code in your login button's action:
if ([TWTweetComposeViewController canSendTweet])
{
//yes user is logged in
accountStore = [[ACAccountStore alloc] init];
ACAccountType *accountType = [accountStore accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierTwitter];
// Request access from the user to use their Twitter accounts.
[accountStore requestAccessToAccountsWithType:accountType withCompletionHandler:^(BOOL granted, NSError *error)
{
// Did user allow us access?
if (granted == YES)
{
// Populate array with all available Twitter accounts
NSArray *arrayOfAccounts = [accountStore accountsWithAccountType:accountType];
ACAccount *acct = [arrayOfAccounts objectAtIndex:0];
// Set the cell text to the username of the twitter account
NSString *userID = [[acct valueForKey:#"properties"] valueForKey:#"user_id"];
TwitterIdStr = [[NSString alloc] initWithString:userID];
FbIdStr = [[NSString alloc] init];
NSLog(#"%#",userID);
NSString *networkCheck = [[NSUserDefaults standardUserDefaults] valueForKey:#"isNetWorkAvailable"];
if ([networkCheck isEqualToString:#"NotConnected"])
{
// not connected
dispatch_async(dispatch_get_main_queue(), ^{
// Display/dismiss your alert
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"No network connection" message:#"You must be connected to the internet to proceed." delegate:nil cancelButtonTitle:#"OK"otherButtonTitles:nil];
[alert show];
});
} else
{
fNameStr = [[NSString alloc] init];
lNameStr = [[NSString alloc] init];
emailStr = [[NSString alloc] init];
[self startProgressViewAgain];
}
}
}];
}
else
{
//show tweeet login prompt to user to login
TWTweetComposeViewController *viewController = [[TWTweetComposeViewController alloc] init];
//hide the tweet screen
viewController.view.hidden = YES;
//fire tweetComposeView to show "No Twitter Accounts" alert view on iOS5.1
viewController.completionHandler = ^(TWTweetComposeViewControllerResult result) {
if (result == TWTweetComposeViewControllerResultCancelled) {
[self dismissModalViewControllerAnimated:NO];
}
};
[self presentModalViewController:viewController animated:NO];
//hide the keyboard
[viewController.view endEditing:YES];
}

Resources