I'm using die Facebook SDK 3.1.1 to implement FB Connect in my iOS application. This works fine in the simple case with either the new FB integration (logged in on iOS) or falling back to the normal authorization via web view (I do not have the native Facebook application installed in both cases).
The problem occurs when I switch the account on iOS level. Logging out and logging in with a different FB user account.
To log in/authorize I perform:
[FBSession openActiveSessionWithReadPermissions:nil allowLoginUI:allowLoginUI
completionHandler:^(FBSession *session, FBSessionState state, NSError *error) {
[self sessionStateChanged:session state:state error:error];
}];
If then get a FBSessionStateClosedLoginFailed every time even though I perform a closeAndClearTokenInformation when that state is reached:
- (void)sessionStateChanged:(FBSession *)session
state:(FBSessionState) state
error:(NSError *)error
{
NSLog(#"Session State Changed: %u", [[FBSession activeSession] state]);
switch (state) {
case FBSessionStateOpen:
break;
case FBSessionStateClosed:
case FBSessionStateClosedLoginFailed:
NSLog(#"FBSessionStateClosedLoginFailed ERROR: %#", [error description]);
[[FBSession activeSession] closeAndClearTokenInformation];
break;
default:
break;
}
However, I receive the same state on every retry. My log says the following:
FBSDKLog: FBSession **INVALID** transition from FBSessionStateCreated to FBSessionStateClosed
FBSDKLog: FBSession transition from FBSessionStateCreated to FBSessionStateCreatedOpening
FBSDKLog: FBSession transition from FBSessionStateCreatedOpening to FBSessionStateClosedLoginFailed Session State Changed: 257
FBSessionStateClosedLoginFailed TOKEN: (null)
FBSessionStateClosedLoginFailed ERROR: Error Domain=com.facebook.sdk Code=2 "The operation couldn’t be completed. (com.facebook.sdk error 2.)" UserInfo=0xb24cc20 {com.facebook.sdk:ErrorLoginFailedReason=com.facebook.sdk:ErrorLoginFailedReason}
Can anyone reproduce this or has any idea where the problem might lie?
Another answer gives a way to manually resync the device with the server. I defined a method called fbRsync to call this code. Make sure to #import <Accounts/Accounts.h> in your implementation file and then define this method:
-(void)fbResync
{
ACAccountStore *accountStore;
ACAccountType *accountTypeFB;
if ((accountStore = [[ACAccountStore alloc] init]) && (accountTypeFB = [accountStore accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierFacebook] ) ){
NSArray *fbAccounts = [accountStore accountsWithAccountType:accountTypeFB];
id account;
if (fbAccounts && [fbAccounts count] > 0 && (account = [fbAccounts objectAtIndex:0])){
[accountStore renewCredentialsForAccount:account completion:^(ACAccountCredentialRenewResult renewResult, NSError *error) {
//we don't actually need to inspect renewResult or error.
if (error){
}
}];
}
}
I then call fbResync if openActiveSessionWithReadPermissions yields an error:
[FBSession openActiveSessionWithReadPermissions:permissions
allowLoginUI:YES
completionHandler:^(FBSession *session, FBSessionState state, NSError *error) {
if(error)
{
NSLog(#"Session error");
[self fbResync];
[NSThread sleepForTimeInterval:0.5]; //half a second
[FBSession openActiveSessionWithReadPermissions:permissions
allowLoginUI:YES
completionHandler:^(FBSession *session, FBSessionState state, NSError *error) {
[self sessionStateChanged:session state:state error:error];
}];
}
else
[self sessionStateChanged:session state:state error:error];
}];
The half a second delay is likely unnecessary, but it currently gives me piece of mind.
This seems to solve the problem for me. I can now switch between Facebook accounts and am able to log in. Yay!
I had the same problem. Check that your FB App is enabled in Settings -> Facebook.
Mine was disabled (even though I don't remember disabling it) and once I enabled it, it was fixed.
In my test process, I've added and removed my FB App several times from my FB Account, which is linked with my iPhone. It may explain why, magically, my app was disabled.
In ios 6 with fb sdk 3.1.1. Please pass permissions param as "nil or email" in "[FBSessio openActiveSessionWithReadPermissions..." method. Here my code it was works great.
#define IOS_NEWER_OR_EQUAL_TO_6 ( [ [ [ UIDevice currentDevice ] systemVersion ] floatValue ] >= 6.0 )
-(void)showFBLogin
{
[FBSession.activeSession closeAndClearTokenInformation];
NSArray *permissions = [NSArray arrayWithObjects:#"email, publish_actions, publish_stream", nil];
#ifdef IOS_NEWER_OR_EQUAL_TO_6
permissions = nil; or NSArray *permissions = [NSArray arrayWithObjects:#"email",nil];
#endif
NSLog(#"\npermissions = %#", permissions);
[FBSession openActiveSessionWithReadPermissions:permissions
allowLoginUI:YES
completionHandler:
^(FBSession *session,
FBSessionState state, NSError *error) {
NSLog(#"\nfb sdk error = %#", error);
switch (state) {
case FBSessionStateOpen:
[[FBRequest requestForMe] startWithCompletionHandler:
^(FBRequestConnection *connection, NSDictionary<FBGraphUser> *user, NSError *error) {
if (!error) {
//success
}
}];
break;
case FBSessionStateClosed:
//need to handle
break;
case FBSessionStateClosedLoginFailed:
//need to handle
break;
default:
break;
}
}];
}
I have the same problem on 3.1.3 FB SDK with iOS7.1. And I find a solution here. Hope it help!!
I have tried all answers here.
#loganathan nil permissions, #ill_always_be_a_warriors fbResync.
All of those don't work for me.
But I found it will works well when I launch the same code in iPhone 7.1 simulator
(without SSO"Single Sign On")
The same code works well on old version iOS FB SDK(not sure which version, but not 3.13)
(but no SSO will show when try to login)
So, I try to re-write a sample problem. I found several different here.
1. https://developers.facebook.com/docs/ios/getting-started Add new FacebookDisplayName
2. I modify my BundleID for iTune connect but I am not update it back to Faceboook App Dev
After modify those setting, it works on my iOS app with SSO feature.
Hope it help!!
Did you Try the RenewSystemCredential Methods? Take a look at this post:
Facebook iOS SDK extendAccessToken not Working - fbDidExtendToken not being called
I got the same error. But i used #ill_always_be_a_warriors method: -(void)fbResync but not work for me.
I finally found it's my permissions issue, i removed offline_access permission, it works, hope it helps some one.
Related
I am currently working on a hybrid application (Ionic) and have a problem with detecting iBeacons on iOS (currently developing on 9.2). I'm using cordova-plugin-estimote (https://github.com/evothings/phonegap-estimotebeacons) to detect beacons, followed their documentation and everything works fine on Android, but not on iOS. The beacons are simply not detected. There is no error, it just doesn't find anything.
Fun fact: When I downloaded the original estimote app on iPhone, it also did not detect any iBeacons until I logged in. After that, it started detecting them normally. Why is this happening?
Relevant part of my AngularJS code based on plugin documentation:
$scope.init = function() {
bluetoothSerial.isEnabled(scanBeacons, errorBluetooth);
}
function scanBeacons() {
startScanning();
updateList = $interval(updateView, 5000);
}
function startScanning() {
console.log("requesting permissions");
estimote.beacons.requestAlwaysAuthorization(successAuth, errorAuth);
}
function successAuth(){
console.log("success auth, starting scan");
estimote.beacons.startRangingBeaconsInRegion(
{},
onMonitoringSuccess,
onError);
}
function errorAuth(){
console.log("error auth");
popupService.showPopup("Authorization error", "Location services required to perform scanning");
}
function onMonitoringSuccess(regionState) {
console.log("monitoring success: "+JSON.stringify(regionState));
var successHandler = function (response) {
$scope.downloadedlist = response;
$scope.offline = false;
};
var errorHandler = function (response) {
$scope.beaconList = regionState.beacons;
};
eventService.getBeaconList(regionState.beacons, storageService.getEventId())
.then(successHandler)
.catch(errorHandler);
}
function onError(response) {
console.log("monitoring error: "+JSON.stringify(response));
popupService.showPopup('popup.error.title', 'popup.error.server');
}
As you can see, I have some console.log statements (it has to be done this way) and I'm getting "requesting permissions", instantly followed by "success auth, starting scan". It's weird because authorization popup is displayed but the code does not wait for the user input, it just automatically fires success handler (successAuth) function and that's it. No more logs, which means no monitoring success, no error, it just doesn't find any beacons.
Any help appreciated. Thanks.
Finally found the solution. The problem was here:
estimote.beacons.startRangingBeaconsInRegion(
{},
onMonitoringSuccess,
onError);
Turns out Android allows for {} parameter (which means look for all regions) in the following function but iOS doesn't. After specifying a region, my application successfuly finds the beacons.
Example:
function successAuth(){
console.log("success auth, starting scan");
var region = { uuid: 'YOUR_UUID_HERE' }
estimote.beacons.startRangingBeaconsInRegion(
region,
onMonitoringSuccess,
onError);
}
Estimote Developer quote:
iOS only allows scanning for beacons the UUID of which you know. All Estimote Beacons ship with our default UUID, "B9407F30-F5F8-466E-AFF9-25556B57FE6D", and these are the beacons you can see on the radar even when not logged in. If you change this UUID to something else, then you need to stay logged in so that Estimote app can know what the UUIDs of your beacons are, and scan for them in addition to the default UUID.
Source: https://forums.estimote.com/t/beacons-not-detected-using-estimote-ios-app/1580/5
This also explains why Estimote App started detecting iBeacons after logging in.
I am trying to use FBPlacePickerViewController and it doesn't seem to load any data.
Here is my code:
FBPlacePickerViewController *picker = (FBPlacePickerViewController*)segue.destinationViewController;
picker.navigationController.navigationBarHidden = YES;
picker.delegate = self;
picker.radiusInMeters = 1000;
picker.resultsLimit = 30;
if([TonerAppDelegate instance].lastLocation != nil){
picker.locationCoordinate = [TonerAppDelegate instance].lastLocation.coordinate;
[picker loadData];
}
[TonerAppDelegate instance].lastLocationUpdateFunction = ^{
picker.locationCoordinate = [TonerAppDelegate instance].lastLocation.coordinate;
[picker loadData];
};
It is an embed segue (iOS 6). I verify that the picker is a valid object. The [picker loadData] method does get called, and the coordinate data is perfectly valid. I am not getting any exceptions or warnings. I've allowed my app to access to my location in iOS and I double-verified that in Settings. My iPod is connected to the Internet and the connection works perfectly. All the other apps can use location services without any problem. So, there probably is a problem with my implementation of the place picker. I've also implemented the -(void)placePickerViewControllerDataDidChange:(FBPlacePickerViewController *)placePicker and -(BOOL)placePickerViewController:(FBPlacePickerViewController *)placePicker shouldIncludePlace:(id<FBGraphPlace>) methods of the delegate, and they aren't getting called either. What am I doing wrong?
Thanks,
Can.
Found the answer: I wasn't creating the Facebook session before displaying the place picker. I totally forgot about the session. It'd be nice to see Facebook add an assertion check in loadData method of the picker for an existing Facebook session. I've created the session, and THEN tried my code, and it works perfectly now.
I had some code to post to a friend's facebook wall that upon the deprecation of this via Open Graph I changed to use the deprecated headers and Facebook dialog to include the user in the posting. That has been working for weeks, but seems to have stopped working (worked fine Tuesday, failed Wednesday) in production application (i.e. no code change or re-build.)
I've spent hours trying all sort of things (running on main thread, asserting sessions are live, re-writting to SDK 3.2, uninstalling app/re-installing, completely changing the dialog type and post contents) to restore the ability but whatever I do the dialog immediately dismisses. [Note: There are no developer alerts on our app, and I believe that none of the app settings have changed.]
Here is the code. The facebookManager "performConnectedAction" is from the Facebook sample to ensure an active session (and I assert it w/o problem.) :
NSMutableDictionary *wallPost = [NSMutableDictionary dictionary];
// Content populating not show (and I've tried various simplifications)
// Who to...
[wallPost setObject:_selectedUser.id forKey:kFB_FIELD_TO];
[facebookManager performConnectedAction:^{
FBSession *facebookSession = facebookManager.facebookSession;
Assert( facebookSession.isOpen, #"Need an open Facebook session.");
[FBWebDialogs presentFeedDialogModallyWithSession:facebookSession parameters:wallPost handler:^(FBWebDialogResult result, NSURL *resultURL,NSError *error) {
if ( !!error ) {
[self logEventWithFormat:#"Failed to invite on Facebook [%#]", error];
}
}];
}];
Basically ... not only does the dialog flash up/down, but no callback is given (no error or result provided.) All other parts of the Facebook application continue to operate (our graph calls, our Facebook Friends dialog, and so on.)
I'd appreciate any thoughts on ways to investigate this further. I have filed a bug report:
http://developers.facebook.com/bugs/165456656937602?browse=search_5130e2d7663dd6543665811
I had the same issue and fixed it by delaying the method call like this. My method is fbWallPost
[self performSelector:#selector(fbWallPost) withObject:nil afterDelay:0.5];
In Restkit versions before v0.20.0 it used to be a simple enough to check for service unavailability and show appropriate responses.
objectManager.client.serviceUnavailableAlertEnabled = YES;
How can we achieve the same in latest RestKit?
Figured it out myself.
Since RKClient is no more in the latest RestKit it has been replaced by the AFHTTPClient from AFNetworking. The wrapper for reachability in AFNetworking is simple enough to use.
Firstly add the SystemConfiguration.framework to your project.
Then add #import <SystemConfiguration/SystemConfiguration.h> to your .pch file.
Finally register a callback block whenever the network reachability changes.
[objectManager.HTTPClient setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
if (status == AFNetworkReachabilityStatusNotReachable) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"No network connection"
message:#"You must be connected to the internet to use this app."
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
}
}];
This also works when the app is started when no internet connection is present.
With Facebook iOS SDK 3.1.1, I'm performing login using this call -
NSArray *permissions = [[NSArray alloc] initWithObjects: #"email", #"user_birthday", #"user_location", nil];
#try {
return [FBSession openActiveSessionWithReadPermissions:permissions
allowLoginUI:allowLoginUI
completionHandler:^(FBSession *session,
FBSessionState state,
NSError *error) {
[self sessionStateChanged:session
state:state
error:error];
}];
}
#catch { ... }
There are rare cases when this method throws NSInvalidArgumentException with message Access options are not permitted for this account type. The options argument must be nil., this is thrown from [ACAccountStore requestAccessToAccountsWithType:options:completion:].
Checking the Apple's docs of ACAccountStore, I see this comment for that method:
"Certain account types (such as Facebook) require an options dictionary. This method will throw an NSInvalidArgumentException if the options dictionary is not provided for such account types. Conversely, if the account type does not require an options dictionary, the options parameter must be nil."
Apple require this to be nil except for Facebook, but this method IS called from Facebook, so Maybe this is a bug - either at Facebook or at iOS 6.0/.1, but I couldn't find anything on the web about this issue.
Any ideas?
I found a work around for this bug. Note that the bug is described here as well: https://developers.facebook.com/bugs/139251032898548
The Facebook SDK does not do a null check for return value of accountTypeWithAccountTypeIdentifier. See https://github.com/facebook/facebook-ios-sdk/blob/master/src/FBSystemAccountStoreAdapter.m?source=c#L176
To work around the problem, you can do the following check before attempting facebook lgoin:
if ([[[ACAccountStore alloc]init] accountTypeWithAccountTypeIdentifier:#"com.apple.facebook"] == nil) {
NSLog(#"Cannot proceed, not facebook account type identifier");
return;
}