Google+ integration iOS - EXC_BAD_ACCESS error on signout - ios

I've done google+ integration in my app and it works perfectly fine. But I have noticed that occasionally I receive an EXC_BAD_ACCESS error during logout. This is my logout function
-(void) logout
{
[[GPPSignIn sharedInstance]signOut];
[[GPPSignIn sharedInstance] disconnect]; // EXC_BAD_ACCESS Error occurs in this line
}
I dont always get this error, I think it may have to do something related with session. I've tried searching for it but haven't found any resolution so far. This error occurs very rarely and I dont know when exactly this happens. When I run the app after this error it works fine and there are no issues. But still its an error and I was wondering if anyone else had the same experience and had found any workaround for this.

The problem seems to be due to calling both signOut and disconnect methods. The disconnect method also performs the signout. The docs say "The token is needed to disconnect so do not call signOut if disconnect is to be called."
If you want to only sign out the user, just call the "signOut" method, for example:
- (void)signOut
{
[[GPPSignIn sharedInstance] signOut];
}
If you want to disconnect the user (revoke your app's API access on behalf of the user), the method also performs sign out:
- (void)disconnect
{
[[GPPSignIn sharedInstance] disconnect];
}
You should also implement the didDisconnectWithError:(NSError *)error method for cleaning up the user details and following Google+'s policies around disconnects.
Read the official Google+ iOS docs for more information.

Related

Parse Log in With Twitter Initial Failure

Currently I have a Twitter login that authenticates the user just fine, receiving all the appropriate information for the user necessary for confirming a complete login.
I then am calling the [PFTwitterUtils logInWithBlock:...] method in order to authenticate the user through Parse and populate a new user in _User.
(I am not using just this method to present the Twitter login dialog box as I could not get it to present itself).
Here is the strange part:
On the first time I launch the app, I sign in with Twitter, and then call the logInWithBlock method and receive the following error:
Something went wrong: The operation couldn’t be completed. (NSURLErrorDomain error -1012.)
The strange part is that this issue does not occur at all if I relaunch the app again. The only difference is that upon relaunch I believe the Twitter Account information that I had used before (via browser not accounts) is saved on the device. When I launch the app again, I have it set so that it reloads the previous session: this time the [PFTwitterUtils logInWithBlock:...] works like a charm, creates a new user, etc., without any issue.
NOTE: I have a valid URL saved as the Callback URL on my Twitter App's settings. Also, I hope it is clear that the setup was done correctly given that it works fine on second log in.
Here is the login code I am using:
// Login with Twitter through Parse
[PFTwitterUtils logInWithBlock:^(PFUser *user, NSError *error) {
if (error != nil) {
// Something went wrong
NSLog(#"Something went wrong: %#", [error localizedDescription]);
breakLogin = YES;
[self invalidateSignInTimer];
return;
}
else if (user.isNew){
userObjectID = user.objectId;
[user saveInBackground];
NSLog(#"New User");
}
else if (!user.isNew) {
userObjectID = user.objectId;
[user saveInBackground];
NSLog(#"Returning User. Welcome Back!");
}
}];
I am running out of patience and ideas on why this is happening. If anyone has any ideas please let me know - thanks!
UPDATE:
I noticed that the reason this seems to be happening is such:
The first time i attempt to login there is no PFUser, whereas the second time there seems to be a saved [PFUser currentUser], which allows the [PFTwitterUtils...] method to log in and create the new user.
Yet I am still not sure how to prevent the failure the first time without manually creating a new PFUser and then logging in with Twitter, then PFTwitterUtils...
UPDATE 2
I have resolved this issue with the answer I have provided below. I am leaving this up as I feel this is something that may help others out there in the future.
So after extraneous research, I seemed to have found a solution.
First I made sure that all of my framework files (SKDs, headers, etc) were up to date by removing all of their references from both the project and the library linking.
Second I made sure that all keys and secrets were remade and updated in my
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
Lastly I made double checked that I properly went through the set up for Twitter authentication through Parse's website.
BUT what I found to be the only solution rested in the Callback URL.
When specifying the Callback URL in your Twitter Application under "Settings", I had to uncheck the Lock Callback URL option, despite the recommendation by Twitter. (seen below)
I was a little unhappy that all of this trouble derived from something so mundane, however I was at least pleased that solution was in fact resolved without too much trouble. Hopefully this answer helps someone out there struggling with a similar issue.

Google SignIn fails when serverClientID specified

I've got a server that interacts with Google Calendar on behalf of user. To do this it should obtain one-time access token from iOS application. I've referred to documentation, but have some issues with sign in.
I have started from "SignIn" example app (pod test Google > Sign In), provided it with my credentials (GoogleServices-Info.plist, bundleId). Then I signed it with my provision and started on iPhone 6, everything works like a charm.
Then I have added
[GIDSignIn sharedInstance].serverClientID = #"<my-server-client-id>";
in ViewController:viewDidLoad. I have unauthorised in app, launched it again. It opened auth screen (youtube.app, 10.31.11670) again, I selected the same account, but this time it launched my app without displaying permissions screen, -signIn:didSignInForUser:withError: method was called, but GIDGoogleUser was nil. Error stated
Error Domain=com.google.GIDSignIn Code=-1 "A potentially recoverable error occured. You may try again." UserInfo=0x17026af80 {NSLocalizedDescription=A potentially recoverable error occured. You may try again.}
I have tried several times, but each time I have received the same result. But if I comment ...serverClientID... it begins to work again.
Then I have launched this app in simulator and it authorised successfully using WebView and I received user.serverAuthCode.
I decided that problem was in YouTube.app, I uninstalled it from device, but the same problem happened with other Google applications.
Could you point me what is wrong with my singIn implementation?
PS
Finally I decided to use workaround and rewrote -canOpenUrl: in UIApplication subclass this way:
- (BOOL)canOpenURL:(NSURL *)url
{
if ([[url scheme] hasPrefix:#"com-google-gidconsent"] || [[url scheme] hasPrefix:#"com.google.gppconsent"]) {
return NO;
}
return [super canOpenURL:url];
}
And now it uses WebView authorisation and I can receive my one-time token. But this approach is crappy of course.

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

iOS app expected behavior after the user removes the previously added authorization from the Facebook app?

I'm successfully posting to Facebook from our Unity iOS game by initializing at game launch then posting message by first checking the session validity and triggering the login if needed.
At first call, I authorize the game from the Facebook app.
Trying to start the process again, I go to the Facebook app prefs and delete the app authorization.
Now when I try to post again from the game, the post message completion handler has no errors but the post does not appear on the user's wall.
What is the process to correct this? Is there a way to check that the game is authorized before posting, and ask for a new authorization if it's not?
Or is the user decision final and they need to reinstall the app to reset everything?
Even though I'm using Prime31's Facebook plugin for Unity, I'm interested in an iOS SDK answer to this question.
Thank you!
You will get an exception, that you need to handle.
- (void)request:(FBRequest *)request didFailWithError:(NSError *)error{
NSLog(#"didFailWithError : %#",[error description]);
NSDictionary* userinfo=[error userInfo];
NSString *type=[[userinfo valueForKey:#"error"]valueForKey:#"type"];
if([type isEqualToString:#"OAuthException"]){
NSLog(#"Exception from oauth let's take new token");
[facebook authorize:_permissions delegate:self];
}
}
Use this delegate function to handle exception.

In which situation are those Facebook IOS FBSessionDelegate methods called?

It's clear to me that these are called upon login if a user grants or denials permission:
- (void)fbDidLogin;
- (void)fbDidNotLogin:(BOOL)cancelled;
But i was wondering when the following FBSessionDelegate methods could be called:
- (void)fbDidExtendToken:(NSString*)accessToken expiresAt:(NSDate*)expiresAt;
- (void)fbDidLogout;
- (void)fbSessionInvalidated;
The documentation says:
//Called after the access token was extended.
- (void)fbDidExtendToken:(NSString*)accessToken expiresAt:(NSDate*)expiresAt;
//Called when the user logged out.
- (void)fbDidLogout;
//Called when the current session has expired.
- (void)fbSessionInvalidated;
Now when would such a thing happen? When i call the following?
[Facebook authorize:nil];
There is no chance i will get a fbDidLogout call back right?
Maybe if a user removes my app from his Facebook account via the Facebook app, would this method be called than? No, because my app doesn't open in that case..
...so in which situation would these be called?
I think i found it myself...
This one:
- (void)fbDidExtendToken:(NSString*)accessToken expiresAt:(NSDate*)expiresAt;
Could be called when you call:
[facebook extendAccessTokenIfNeeded];
This one:
- (void) fbDidLogout;
Gets called when you call
[facebook logout] //(of course..)
The last one:
- (void)fbSessionInvalidated;
Get's called when you try to send a http request to Facebook with an expired session token.
I found it in the Facebook SDK header file Facebook.m
I'll leave the question here for anyone looking for the answer :)

Resources