Cannot send facebook apprequest from iOS because FBSession.activeSession.isOpen gives false - ios

my app can only send app request during the first run that the user logins into facebook. Once the app is restarted, the app request gets stopped because FBSession.activeSession.isOpen gives false.
Although, FBSession.activeSession.isOpen gives false still the app can perform other operations such as posting to the wall, getting friend list etc. Only it cannot send app requests. And still it has a valid access token too.
Any ideas?

You say "FBSession.activeSession.isOpen gives false", but, just to be sure : when do you run this test? When your call to the login request returns, or inside the asynchronous request's callback ?
If it's done outside the request's callback, it may say that the session is not opened yet. Then, the request returns properly, which means that any further call to another FB request succeeds.
Does that help?
If it does not, maybe an overview of your code could.

Ok, next to your comment from the previous answer :
yes, that's what you said already. but WHERE in your code do you check isOpen? To expect a proper value, it should be something like this :
FBSession openActiveSessionWithReadPermissions:_readPerms allowLoginUI:YES completionHandler:^(FBSession *session, FBSessionState status, NSError *error) {
// here is the proper place to check the isOpen boolean, and to go on with your program, including the app request
}];
// not the proper place to check isOpen.
Does that help?

Related

How to get callbacks for Facebook iOS SDK Like action?

Trying to perform the built-in-like using the Facebook iOS SDK. I've found snippets like the one below but how can I get notified of the requests status? I have no way of knowing whether the request actually caused a Like, failed, and for what reasons.
Q: How to get callbacks from FBRequest?
// Trying to perform built-in-like
[FBRequest requestWithGraphPath:#"me/namespace:like"
parameters:#{#"recipe":#"http://myurl.com"}
HTTPMethod:#"POST"];
According to the FBRequest API the requestWithGraphPath method does not make an actual call.
//Returns a newly initialized request object that can be used to make a
//Graph API call for the active session.
requestWithGraphPath:parameters:HTTPMethod:
The call itself can be made with startWithCompletionHandler:.
- (FBRequestConnection*)startWithCompletionHandler:(FBRequestHandler)handler;
Looking at the API for FBRequestConnection, FBRequestHandler is a block that is passed to register for a callback with the results of that request once the connection completes.
In other words, it will be called when the request completes with a success, error, or cancel action.

How is FBSession used

I'm integrating facebook and I still don't see how the FBSession ties everything together.
This is how I think it works.
You need a new FBSession each app launch. (Is this true?). The FBSession also needs to be closed every time the app stops (if this is true, how do we start a new session without asking user to login again?)
As far as the session is concerned, [FBSession activeSession] is a global managed by the facebook sdk? Should we just use this as the default session anytime we want to pull data or check if a session is alive?
Assuming the above logic has worked out and you get the user id (fb id) then we feed that id to a FBImageView and we get a profile pic, but isn't this id changing every launch? So storing it on our server isn't helpful? Should we get the id every launch?
Please let me know what is right or wrong about the above statements, and an explanation of why?
Thank you.
I suggest you to use activeSession of FBSession. This way you don't have to create sessions yourself. Just use [FBSession openActiveSessionWithReadPermissions:...] method of FBSession for activating activeSession, and on successful opening, You could use FBSession.activeSession for your Facebook requests. Good luck!
PS>
In order to restore activeSession you can do:
if (![FBSession.activeSession isOpen]) {
[FBSession openActiveSessionWithReadPermissions:#[#"basic_info"] allowLoginUI:NO completionHandler:^(FBSession *session, FBSessionState status, NSError *error) {
}];
}
which will open the session if it has cached token information without showing login UI.

FBSession requestNewPublishPermissions fails before response

I'm trying to get post permissions from a user using the Facebook SDK on iOS.
I'm calling the code below in a method that is called if the app does not have the required publishing permissions to post to the users facebook wall.
// No permissions found in session, ask for it
[FBSession.activeSession requestNewPublishPermissions: [NSArray arrayWithObject:#"publish_actions"]
defaultAudience: FBSessionDefaultAudienceEveryone
completionHandler: ^(FBSession *session, NSError *error)
{
if( !error )
{
// Do something
}
}];
The first time I call this code it takes the user to the permissions page, and before it even switches to safari on the device the block gets called and this error message is returned
Error Domain=com.facebook.sdk Code=2 "The operation couldn’t be completed. (com.facebook.sdk error 2.)" UserInfo=0xc426410 {com.facebook.sdk:ErrorLoginFailedReason=com.facebook.sdk:ErrorReauthorizeFailedReasonUserCancelled,
The app then continues on to show the permissions page in safari where the user selects ok. Then it returns to the app. Permissions have not been set at this point even tho the user was presented with the permissions page and accepted.
When trying to post a second time it takes the user to the permissions page in safari and the requestNewPublishPermissions method doesn't fail instantly. The user selects ok and then everything works as expected.
So it is only on the very first time calling requestNewPublishPermissions that it fails instantly returning the error ErrorReauthorizeFailedReasonUserCancelled.
This happens in the simulator and on the device.
Any idea what might be causing this?
I found the solution to this problem on the answer to this question Facebook iOS 3.1 sdk login with publish permission callbacks
dispatch_async(dispatch_get_current_queue(), ^{
[self openSessionForPublishPermissions];
});
Where opensessionforpublishpermissions is the method that contains the requestNewPublishPermissions method.
"The reason is that the call to reauthorize.. needs to be after the event loop of which openActiveSession.. is called."
I assume this is a bug in the Facebook SDK, it doesn't make sense for this to be normal behaviour and I haven't seen any of the Facebook docs comment on this being the expected behaviour.
I had the similar issue, and the answer, provided by Tiddly worked for me. For some time.
Later I ran across the same issue. I don't know why, may be it was concerned with SDK or iOS updates, may be run loop of the app became more complicated. So I inspected FB SDK source and figured out that this issue occurs when you ask publish permissions just after read permissions, like this:
// Open with read permissions
[FBSession openActiveSessionWithReadPermissions: readPermissions
allowLoginUI: YES
completionHandler: ^
(FBSession *session, FBSessionState status, NSError *error)
{
// Ask for publish permissions (This is incorrect!)
[FBSession.activeSession requestNewPublishPermissions:publishPermissions
defaultAudience:FBSessionDefaultAudienceFriends
completionHandler:
^(FBSession *session, NSError *error)
{
// ...
}];
}];
When your app switches to Safari or FacebookApp and back,
-application: openURL: sourceApplication: annotation:
is called. CompletionHandler of
+openActiveSessionWithReadPermissions:
called immediately after this, before
applicationDidBecomeActive:. And after you start reauthorisation
applicationDidBecomeActive: is finally called. So, FB SDK think that user has returned back to the app, without giving permissions and reauthorisation fails with that "com.facebook.sdk error 2." error.
Sometimes dispatch_async() works well. But the robust solution, is to wait for active session to handle App Did Become Active event. And then request additional publish permissions. Here is an example of how to achieve this:
- (void)applicationDidBecomeActive:(UIApplication *)application
{
[FBAppCall handleDidBecomeActive];
if (self.shouldReauthorise) {
[self requestPublishPermissions];
self.shouldReauthorise = NO;
}
}

Signing in with Facebook - FBSession questions

I've been trying to integrate Facebook and came across some issues and questions.
1.
I have implemented the following method in viewDidLoad:
[FBSession openActiveSessionWithReadPermissions:nil allowLoginUI:NO completionHandler:^(FBSession *session, FBSessionState status, NSError *error) {
[self sessionStateChanged:session state:status error:error];
}];
When there's a token cached, the block is executed as expected.
But, when there isn't a token cached, the block isn't executed at all.
Is this a normal behaviour? If so, when is the block executed?
2.
I've been said that access tokens are expired at some point.
Should I be worried about what to do when a token is expired, or Facebook handles it automatically?
3.
What FBSession actually means?
As I understand - the FBSession manages the token and the user authentication,
Yet, I don't understand what does it mean to "open a session" or what the FBSessionStates represent.
When is the FBSession created? Right when the app loads?
4.
I've found that graph that should explain the FBSessionsStates:
After reading the graph, I still don't understand the flow - when are FBSessionStateCreated & FBSessionStateCreatedTokenLoaded the current state of the session?
As you can see, I have many questions about the whole process.
I've tried to organize the questions in a way that other people seeing this in the future, won't be having the struggles I'm having.
Thank you.

Wrong Twitter result after unsuccessful send attempt

When using TWTweetComposeViewController in IOS5 to compose and send a Tweet, if the Tweet is a duplicate, an error alert is shown saying that the Tweet is duplicate and cannot be sent, but the TWTweetComposeViewControllerCompletionHandler still gets a result value of TWTweetComposeViewControllerResultDone rather than TWTweetComposeViewControllerResultCancelled.
(This may happen in other cases as well, not just for duplicate tweets - I didn't check).
This makes it impossible to show a confirmation message to the user after a successful send, because the handler gets the same "Done" result whether the send was successful or not.
Is there another way to check whether the send was actually successful?
The documentation for TWTweetComposeViewController's completionHandler states the following:
The handler has a single parameter that indicates whether the user finished or cancelled composing the tweet.
The completionhandler tells you whether the user actually finished or cancelled composing the tweet herself, regardless of the result of actually posting the tweet.
Update
I've looked a bit further into this and it seems like the TWTweetComposeViewController is one of those convenience classes that take away most of the work for the developer in exchange for not letting the developer handle anything by himself. In this case, the developer has no way of handling the errors that occur when sending the tweet and has to rely on the iOS provided alert dialogs to inform the user instead.
You can hack around this by using Saleh's method, though I don't consider that safe enough to use in an actual app. See the comments in his answer.
Another method is by implementing your own view controller which handles tweet composition and sending. You can do this by following the procedure in the following stackoverflow answer.
Check for the alert message, if the alert message is shown you'll be able to know that the error occurred. I think that the alert message gets added in the window. You can check the count of window's subviews, if they get increased when delegate function is called, you'll know that the error occurred.
Isn't it only a view controller? The result of the view controller is fine as it states what happened with the view controller ( it is done running ).
With what are you sending your tweet? That library most likely has some stuff implemented you can use to determine whether your tweet was sent successfully or not.
[postRequest performRequestWithHandler:^(NSData *responseData, NSHTTPURLResponse *urlResponse, NSError *error)
{
if([urlResponse statusCode]==200)
{
//Tweet tweeted successfully....
}
}
this might help you .
In respponse if url response code is 200 you can say text is tweeted....

Resources