Facebook iOS SDK integration showing Error in Appdelegate.m - ios

in htttps://developer.facebook.com they have give login with API call Sample, they asked to type following code in my app delegate.m file
// 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:#[#"basic_info"]
allowLoginUI:NO
completionHandler:^(FBSession *session, FBSessionState state, NSError *error) {
// Handler for session state changes
// This method will be called EACH time the session state changes,
// also for intermediate states and NOT just when the session open
[self sessionStateChanged:session state:state error:error];
}];
it is showing me the error like ---- No visible #interface for 'AppDelegate' declares the 'sessionStateChanged:state:error:'
thanks in advance...

According to above link, You have to add this method in your app delegate.. But you can customize this method according to your view by state(state == FBSessionStateOpen... etc)
// 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
// customize your code...
}

Related

facebook ios url types issue

I'm a beginner in the iOS (native) world, I have a strange issue with the Facebook authentication in my demo app.
I've configured the .plist file with the following keys following the tutorial:
FacebbokAppID: <myappid>
FacebookDisplayName: a name
Url types (array)
Item 0 (dictionary)
Url Schemes (Array)
Item 0 (String): fb<myappid>
Where <myappid> is the numerical app id of the registered app on the facebook website.
Now, I perform the login using this code:
- (void) facebookLoginLogout
{
// If the session state is any of the two "open" states when the button is clicked
if (FBSession.activeSession.state == FBSessionStateOpen
|| FBSession.activeSession.state == FBSessionStateOpenTokenExtended) {
// Close the session and remove the access token from the cache
// The session state handler (in the app delegate) will be called automatically
[FBSession.activeSession closeAndClearTokenInformation];
// If the session state is not any of the two "open" states when the button is clicked
} else {
// Open a session showing the user the login UI
// You must ALWAYS ask for basic_info permissions when opening a session
[FBSession openActiveSessionWithReadPermissions:#[#"basic_info", #"friends_online_presence"]
allowLoginUI:YES
completionHandler:
^(FBSession *session, FBSessionState state, NSError *error) {
// Retrieve the app delegate
AppDelegate* 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];
}];
}
}
And I've defined the method to handle state changes:
- (void)sessionStateChanged:(FBSession *)session state:(FBSessionState) state error:(NSError *)error
{
NSLog(#"here?");
[..]
}
The problem is exactly that this method is never called in this situation.
THE STRANGE POINT is that, if I change Url types -> Item 0 -> Url Schemes -> Item 0 value to something different, the method is called!
Any hints? Thanks in advance.

iOS Facebook web share api - how to tell if the user has hit skip

I have a VC with a button hooked up to do a facebook share of some text and an image url.
I use the FB api which opens the FB webview - for the user to login. It then presents the share window with a "Skip" or "Share" button as shown...
I have in my app the following code to take care of the login and button actions ....
For some reason the "Skip" also posts as if the "OK" was hit. I tried cheking thr error code returned using the Error Utility but that does not work (app never gets into that section of code and "CANCELLED OUT" is never logged in NSLog, even when I hit the Skip button)
Any help with this will be most appreciated. Perhaps some way to recheck permissions?
(void)postStatusUpdate:(id)status
{
if (FBSession.activeSession.state != FBSessionStateCreatedTokenLoaded || [FBSession.activeSession.permissions
indexOfObject:#"publish_actions"] == NSNotFound) {
// Permission hasn't been granted, so ask for publish_actions
[FBSessionopenActiveSessionWithPublishPermissions:#[#"publish_actions"]
defaultAudience:FBSessionDefaultAudienceFriends
allowLoginUI:YES
completionHandler:^(FBSession *session, FBSessionState state,
NSError *error) {
[selfsessionStateChanged:session state:state error:error];
if([FBErrorUtilityerrorCategoryForError:error] ==
FBErrorCategoryUserCancelled)
{
NSLog(#"SNFacebookClient: CANCELLED OUT!!");
}
if (FBSession.activeSession.isOpen && !error) {
// Publish the story if permission was granted
[selfpublishStory:status];
}
}];
} else {
// If permissions present, publish the story
[selfpublishStory:status];
}
}
code here
I even tried in lldb to check the permissions array after "Skip" was pressed ...
po [FBSession activeSession].permissions
And find that even when skip is pressed the array contains the entry "publish_actions"
You need to check the session status, if the status is FBSessionStateOpen or FBSessionStateCreatedTokenLoaded, you can fetch user's data.
Otherwise, something wrong happen or user skipped it.
This approach is different of you, check my short comments to you understand the steps.
// Suppose my FBSession is stored in a property called session
#property (nonatomic, strong) FBSession *session;
// The session getter can be implemented like this
- (FBSession *)session
{
if(!_session)
{
_session = [[FBSession alloc] initWithPermissions:readPermissions];
[FBSession setActiveSession:_session];
}
return _session;
}
// Opening a new session
[self.session openWithCompletionHandler:^(FBSession *session, FBSessionState status, NSError *error) {
[self session:session stateChanged:status error:error];
}];
- (void)session:(FBSession *)session stateChanged:(FBSessionState)state error:(NSError *)error
{
switch(state)
{
case FBSessionStateOpen:
{
// Connection accepted
}
break;
case FBSessionStateCreatedTokenLoaded:
{
// Connection restored
}
break;
case FBSessionStateClosed:
// Connection closed
break;
case FBSessionStateClosedLoginFailed:
{
// Connection failed and closed
}
break;
case FBSessionStateCreated:
{
// Session created (not opened yet)
}
break;
case FBSessionStateCreatedOpening:
// Handler it if you need to do something while connection is opening
break;
case FBSessionStateOpenTokenExtended:
// Session token extended
break;
}
}

How to resolve "com.facebook.sdk error 2" under the condition that "allow these apps to use your account" is off for my app

I am working on an iOS app using the latest FB SDK for native log in. When I switch my app off in "allow these apps to use your account" in the settings, an error "com.facebook.sdk error 2" is expected to come.
I am wondering is there any elegant way to solve this error even if "allow these apps to use your account" is off for my app? I have searched for the solution but all the answers are saying that You need to switch that option on. But I think the better way is that if user switches that option off, we can still let him log in, falling back to the fast-app-switch way seamlessly, just like he doesn't log into Facebook on his device at all. How can I do this in the newest FB SDK? Thanks!
====================================Update=========================================
I solve it using a deprecated function openActiveSessionWithPermissions:allowLoginUI:completionHandler
first we need to check whether user switch this option off:
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 switch this option off
}
then in openSession function, using that deprecated function if self.useAccountAllowed is false:
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];}];
not sure whether it is a correct way.
This is how I solved it. On the AppDelegate implementation file, in the applicationDidBecomeActive method, use the regular [FBSession.activeSession handleDidBecomeActive] method, as recommended by the FB SDK documentation. Plus, add a new method that checks the user permissions in Settings (that I called checkPermissionSettings in the example below):
- (void)applicationDidBecomeActive:(UIApplication *)application
{
NSLog(#"applicationDidBecomeActive: in NHOCAppDelegate");
//
// The flow back to your app may be interrupted (for ex: if the user clicks the Home button
// while if authenticating via the Facebook for iOS app).
// If this happens, the Facebook SDK can take care of any cleanup that may include starting a fresh session.
//
[FBSession.activeSession handleDidBecomeActive];
[self checkPermissionSettings];
}
//
// Verify if the user pressed the Home Button, went to Settings and deauthorized the app via "Allow These Apps to Use Your Account..."
// If so, redirect him to the login screen (this happens automagically, see below).
//
- (void)checkPermissionSettings
{
NSLog(#"checkPermissionSettings: in NHOCAppDelegate");
//
// Now 'startForMeWithCompletionHandler' may return 'FBSessionStateClosed' (meaning that the user probably unauthorized the app in Settings).
//
// If that is the case:
//
// - Hide the 'logged' View Controller
// - Remove it (NHOCLoggedVC) from the Notification Center
// - Show the 'login' View Controller
// - And finally add it (NHOCLoginVC) to the Notification Center, closing the loop
//
// Check the console for further info.
//
[FBRequestConnection startForMeWithCompletionHandler:^(FBRequestConnection *connection, id<FBGraphUser> user, NSError *error) {
if (!error) {
//
// Everything went fine... The app is in good shape.
// Notice that 'user.location' requires user_location permission
//
NSLog(#"user.location: %#: ", [user.location objectForKey:#"name"]);
}
}];
}
To make it work as designed, I also use Notification Center. You can check the entire example here:
FB SDK + Storyboards with Publish to Feed
I hope it helps.

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];
}
.......
}

Can I detect the *first* time a user has logged into an app using the facebook sdk?

Using the latest facebook sdk 3.1, I open a session requesting permissions using:
[FBSession openActiveSessionWithReadPermissions:permissions
allowLoginUI:allowLoginUI
completionHandler:^(FBSession *session, FBSessionState state, NSError *error) {
[self sessionStateChanged:session state:state error:error];
}];
My sessionStateChanged method looks like this:
- (void)sessionStateChanged:(FBSession *)session
state:(FBSessionState)state
error:(NSError *)error
{
switch (state) {
case FBSessionStateOpen:
// handle successful login
break;
case FBSessionStateClosed:
case FBSessionStateClosedLoginFailed:
// handle failed login
break;
default:
break;
}
}
Is there any way inside sessionStateChanged to distinguish if this is the first time the user has ever logged in (i.e. they have never before given us permission for this particular app)?
There is no way to know if this is the user's first time authorizing the application or not. Your best option is to track within your own application if they have logged in before.

Resources