Check iOS device facebook permissions for my app - ios

I want to check whether permission is given to my app for facebook access in iOS settings so that I can use different flag with openWithBehaviour function of facebook for facebook social login.
1)
FBSessionLoginBehaviorWithNoFallbackToWebView i.e
[session openWithBehavior:FBSessionLoginBehaviorWithNoFallbackToWebView
completionHandler:^(FBSession *session,
FBSessionState status,
NSError *error) {
// Respond to session state changes,
// ex: updating the view
[_self sessionStateChanged:session state:status error:error];
}];
if permission is not given for my app in iOS settings for facebook and
2)
FBSessionLoginBehaviorUseSystemAccountIfPresent i.e
[session openWithBehavior:FBSessionLoginBehaviorUseSystemAccountIfPresent
completionHandler:^(FBSession *session,
FBSessionState status,
NSError *error) {
// Respond to session state changes,
// ex: updating the view
[_self sessionStateChanged:session state:status error:error];
}];
So is it possible to check whether my app is denied permission by the user in settings? Any help, suggestion is deeply appreciated.
(I want this because on iOS 6 devices if user has denied permission for my app in iOS facebook settings then facebook login fall back is interrupted).

Why don't you access [FBSession activeSession] before making the call? There is
#property (readonly, copy) NSArray *permissions;
and
#property (readonly) FBSessionState state;
to do checks before making any call for log in on the Facebook SDK. NSArray permissions contains NSStrings so you can easily detect what your session is allowed to do.

I solved this:
[accountStore requestAccessToAccountsWithType:facebookAccountType
options:options completion:^(BOOL granted, NSError *e) {
if (granted) {
NSlog(#"Permission granted");
// everything is fine i.e, facebook account is created in iOS device settings and permission is given to your app to use facebook information.
//call facebook login using openWithReadPermissions function of facebook SDK or openWithBehaviour with FBSessionLoginBehaviorWithUseSystemAccountIfPresent
}
else
{
NSLog(#"Permission rejected");
NSLog(#"Facebook error details: %#",e);
if ([e code] == ACErrorAccountNotFound) {
//This means user has not created facebook account in ios settings.
}
else if ([e code]== 7 || e==nil){
//This means user has denied permission for your app in iOS device facebook settings. So if user tries for social login using facebook then you can call openWithBehaviour facebook SDK function with FBSessionLoginBehaviorWithNoFallbackToWebView to manually give fall facebook fallback.
}
}
}];

Related

iOS Facebook Connect functionality

In the below design we need to connect to facebook from the app itself by entering the username and password in the app textfields. This is similar to the default facebook connect functionality by Apple in iOS6 and iOS7 Settings. So, please suggest how can I approach this design. Thank you guys. :)
http://i.stack.imgur.com/4tJr4.png
Facebook doesn't suggest to use your own views for getting facebook username and passwords for a user. The safest way is to let facebook sdk handle the login flow.
All you need to call is openActiveSessionWithReadPermissions: allowLoginUI: completionHandler: after you have successfully integrated the facebook iOS sdk. Publish permissions are always requested in the next step.
NSArray *permissions = [[NSArray alloc] initWithObjects:
#"email",nil];
_isUserAuthenticated = [FBSession openActiveSessionWithReadPermissions:permissions
allowLoginUI:allowUI
completionHandler:^(FBSession *session,
FBSessionState state,
NSError *error) {
if (error) {
NSLog(#"FACEBOOOK OPEN ACTIVE SESSION ERROR:%#",error);
//[self handleAuthError:error];
}
[self sessionStateChanged:session
state:state
error:error];
}];
_isUserAuthenticated is a bool for keeping track of the result.

iOS app is not shown in the "Allow these apps to Use your Account" list using FB SDK v3.5

I am using FB ios SDK v3.5 for my app. For log in part, I don't use FBLoginView to log in, instead, I use a UIButton and invoke [FBSession openActiveSessionWithReadPermission] in the handler of that UIButton.
In FB SDK v3.2.1, I use the following code to handle different log in scenarios, it works fine:
self.useAccountAllowed = true;
ACAccountStore *accountStore;
ACAccountType *accountTypeFB;
if ((accountStore = [[ACAccountStore alloc] init]) &&
(accountTypeFB = [accountStore accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierFacebook] ) ){
NSArray *fbAccounts = [accountStore accountsWithAccountType:accountTypeFB];
id account;
if (!fbAccounts)
{
//do not log into FB on the device
}
else if ([fbAccounts count] == 0) {
[FBSession.activeSession closeAndClearTokenInformation];
self.useAccountAllowed = false; //User does not allow the app to use the account
}
else if ([fbAccounts count]>0 && (account=[fbAccounts objectAtIndex:0])) {
[accountStore renewCredentialsForAccount:account completion:^(ACAccountCredentialRenewResult renewResult, NSError *error) { //User allowes the app to use the account
//we don't actually need to inspect renewResult or error.
if (error){
}
}];
}
}
then in the handler function of the UIButton:
if (self.useAccountAllowed) {
[FBSession openActiveSessionWithReadPermissions:nil allowLoginUI:YES completionHandler:^(FBSession* session, FBSessionState status, NSError* error){
[self sessionStateChanged:session state:status error:error];}];
}
else {
NSArray* lPermission = FBSession.activeSession.permissions;
[FBSession openActiveSessionWithPermissions:lPermission allowLoginUI:YES completionHandler:^(FBSession* session, FBSessionState status, NSError* error){
[self sessionStateChanged:session state:status error:error];}];
which means that if User does not allow the app to use the account, we just use fast-switch way through Safari to login; otherwise we use the native login.
But in SDK v3.5, still the same code, but sometimes when the app is executed and logged into facebook, the app is not in the "Allow these apps to Use your Account" list, so this code cannot distinguish these two cases: 1.the app is not in the list; 2. user disallows the app to use this account. so the app fails to log in natively.
Notice that this problem exists randomly. sometimes I hard code to invoke openActiveSessionWithPermissions directly, this problem is gone. but I am not sure it is the reason.
I just wonder in FB SDK v3.5, do I need to explicitly invoke some SDK function that is related to iOS settings?

How to detect if user have an iOS integrated Facebook account setup before request session?

It seems to me, thath at the very first session opening request, the iOS integrated Facebook, and the old "app switching" authorization works in a different way.
The first needs to open the session with read permissions only, then ask for publish permission at publish time.
The old one needs to request for every permission at the first time, so app will be able to post later on (otherwise not).
So I split the session opening logic in my facebook connect method:
-(void)connectWithSuccess:(EPPZSuccessBlock) successBlock
fail:(EPPZFailBlock) failBlock
{
if (FBSession.activeSession.isOpen)
{
if (successBlock) successBlock();
[self socialServiceDidConnect:self];
}
else
{
//This is what I need to decide somehow.
BOOL userHaveIntegrataedFacebookAccountSetup = NO;
if (userHaveIntegrataedFacebookAccountSetup)
{
//Request for a session with read permissions only, otherwise iOS integrated Facebook will throw me an exception.
[FBSession openActiveSessionWithReadPermissions:[NSArray arrayWithObject:#"user_about_me"]
allowLoginUI:YES
completionHandler:^(FBSession *session, FBSessionState status, NSError *error)
{ [self handleOpenSessionResponseWithSession:session status:status error:error success:successBlock fail:failBlock]; }];
}
else
{
//Request for session with every (incuding publish) permissions, otherwise non integrated Facebook won't let the app to post later.
[FBSession openActiveSessionWithPublishPermissions:self.publishPermissions
defaultAudience:FBSessionDefaultAudienceEveryone
allowLoginUI:YES
completionHandler:^(FBSession *session, FBSessionState status, NSError *error)
{ [self handleOpenSessionResponseWithSession:session status:status error:error success:successBlock fail:failBlock]; }];
}
}
}
But I need some kind of easy detection of which one to use, so the question goes: How to detect if user have an iOS integrated Facebook account setup before request session?
As far as I know, the proper way to find this out is to use
[SLComposeViewController isAvailableForServiceType:SLServiceTypeFacebook]
Note that this is iOS 6 and later only! Part of Social.framework.
Just as anton said.
//Facebook setup on users device.
BOOL haveIntegratedFacebookAtAll = ([SLComposeViewController class] != nil);
BOOL userHaveIntegratedFacebookAccountSetup = haveIntegratedFacebookAtAll && ([SLComposeViewController isAvailableForServiceType:SLServiceTypeFacebook]);

FacebookSDK presents login UI twice

Using iOS 6 with the FacebookSDK splits the requests for read and publish permissions into two separate calls. I'm not sure why there's any benefit to this, but it seems to require presenting the user with the Facebook UI twice the first time thru.
In my app, I don't request anything from Facebook until a user chooses to use Facebook, in which case they are first presented with the UI to get read permissions, then again to get publish permissions. Control switches from my app to facebook (for read) back to my app and then immediately back to facebook (for publish) then back to my app.
This is an awful user experience, especially since the facebook screen with the "Okay" looks the same to the user. (Why am I pressing Okay twice?)
My code, in a nutshell is:
Check for a valid FBSession.activeSession
if not open call FBSession openActiveSessionWithReadPermissions
if successful call FBSession.activeSession reauthorizeWithPublishPermissions
then publish post
The code works, but the user experience is lousy. Am I missing something?
My understanding is that iOS 6 is requiring the double login for their ACAccountStore support, so the Facebook login tutorial implies that you should do this for all cases. Switching the app twice is a bad user experience and I think I have come up with a work around.
Firstly, for older iOS's (e.g iOS 5.0) can you just use openActiveSessionWithPublishPermissions: and do the read and publish permissions in one swoop. Secondly, this same call works if the user has never logged into Facebook from the Device Settings. Therefore, the following code seems to work like this:
If user has logged into Facebook from Device Settings: One dialog for
read and one dialog for publish.
Else if user has Facebook app installed:
switch to FB app once, and get 2 prompts in a row.
Otherwise: switch
to Safari once, and get 2 prompts in a row
I tested this code on an iOS6 and iOS5 device, using Facebook SDK 3.2.1
- (BOOL)hasFacebookInDeviceSettings
{
ACAccountStore *accountStore = [[ACAccountStore alloc] init];
ACAccountType *accountTypeFB = [accountStore accountTypeWithAccountTypeIdentifier:#"com.apple.facebook"];
BOOL hasFacebookBuiltinAccount = (accountTypeFB != nil);
return hasFacebookBuiltinAccount;
}
- (BOOL)hasLoggedInToFacebookInDeviceSettings
{
if (![self hasFacebookInDeviceSettings]) {
return NO;
}
BOOL result = [SLComposeViewController isAvailableForServiceType:SLServiceTypeFacebook];
return result;
}
- (void)openFacebookSessionWithAllowLoginUI:(BOOL)allowLoginUI
{
if (![self hasLoggedInToFacebookInDeviceSettings]) {
// Simpler if we don't have the built in account
[FBSession openActiveSessionWithPublishPermissions:#[#"publish_actions"]
defaultAudience:FBSessionDefaultAudienceFriends
allowLoginUI:allowLoginUI
completionHandler:^(FBSession *session,
FBSessionState state,
NSError *error) {
[self facebookSessionStateChanged:session
state:state
error:error];
}];
}
else if (!FBSession.activeSession.isOpen) {
__block BOOL recursion = NO;
[FBSession openActiveSessionWithReadPermissions:nil
allowLoginUI:allowLoginUI
completionHandler:^(FBSession *session,
FBSessionState state,
NSError *error) {
if (recursion) {
return;
}
recursion = YES;
if (error || !FBSession.activeSession.isOpen) {
[self facebookSessionStateChanged:session
state:state
error:error];
}
else {
assert(FBSession.activeSession.isOpen);
if ([FBSession.activeSession.permissions indexOfObject:#"publish_actions"] == NSNotFound) {
[FBSession.activeSession requestNewPublishPermissions:#[#"publish_actions"]
defaultAudience:FBSessionDefaultAudienceFriends
completionHandler:^(FBSession *session,
NSError *error) {
[self facebookSessionStateChanged:session
state:FBSession.activeSession.state
error:error];
}];
}
}
}];
}
}
hasFacebookInDeviceSettings tells you if this device even supports Facebook from the settings (i.e. this is iOS6+).
hasLoggedInToFacebookInDeviceSettings tells you if the user has signed into to Facebook from the iOS6 Facebook device settings.
You'll need to create your own facebookSessionStateChanged: and other code, as described in the login tutorial

Facebook SDK 3.1 for iOS, completion handler is never called when logging in through app switching

I'm developing an app that has to post some info to facebook. When I call
[[FBSession activeSession] openWithCompletionHandler:^(FBSession *session, FBSessionState status, NSError *error) {
[self publishFacebookStory];
}];
or
[FBSession openActiveSessionWithPublishPermissions:publishPermissions defaultAudience:FBSessionDefaultAudienceEveryone allowLoginUI:YES completionHandler:^(FBSession *session, FBSessionState status, NSError *error) {
if (!error) {
[self publishFacebookStory];
}
}];
the app switches to safari, I get a message saying that the app has already been authorised. I press okay and it switches back to my app but the completion handlers are never called and I still dont have a valid access token at this point.
Any ideas? Any help is appreciated.
Thanks.
The issue is how your app knows how to post upon your app delegate's invocation of applicationDidBecomeActive. If you go through the Facebook Publish to Feed, it will also refer you back to Facebook login which shows you the appropriate changes to applicationDidBecomeActive.
Bottom line, you have to decouple the opening of the session with the publishing on your Facebook feed (either by opening the session before you present the user the option of posting to their feed or by keeping track of what the user wanted to post before the authorization is initiated and then using that to publish the information upon applicationDidBecomeActive).
Are you handling the url in your appdelegate?
-(BOOL) application:(UIApplication*)application handleOpenURL:(NSURL*)URL {
NSString *url = URL.absoluteString;
if ([url hasPrefix:#"YOUR_FB_URL_PREFIX"]) {
[FBSession.activeSession handleOpenURL:URL];
}
.......
}

Resources