FBConnect is not opening facebook login screen - iphone

I am using follwing function to open FBConnect login screen but unfortunate it is not appearing on screen, whenever I am clicking on Login button after animating of Spinner blank screen is coming.
if(appDelegate.session == nil) {
appDelegate.session = [FBSession sessionForApplication:API_KEY secret:SECRET_KEY delegate:self];
}
if(loginButton == nil) {
self.loginButton = [[[FBLoginButton alloc] init] autorelease];
loginButton.frame = CGRectMake(0, 0, 100, 50);
[self.view addSubview:loginButton];
}
I have given right value of API_KEY and SECRET_KEY from developer account. Please look attached image.

Use FBConnect only if it uses Facebook GraphApi, else other api's wont be working.
Why are you using old FB Sdk, use the new iOS SDK 3.0, it very simple to use. Also FB has provided lots of sample app. Get the new sdk here.
And also new Graph Api's doesn't require secret key.

Related

Facebook SDK FBLoginView getting EXC_BAD_ACCESS

I'm following the HelloFacebookSample project bundled with the Facebook SDK 3.5. I've virtually copied and pasted everything into my own app, even the stuff from the AppDelegate, yet for some reason clicking the Login button freezes my app. Just for the record, everything authenticates correctly when connecting to the integrated framework in iOS 6, which is done through the FB SDK anyway. It's only when I try to log in using the web, i.e. hit the FBLoginView website opens, get authenticated, return to app. Here is the code in the samepl project, and I'll compare it to mine:
FBLoginView *loginview = [[FBLoginView alloc] init];
loginview.frame = CGRectOffset(loginview.frame, 5, 5);
loginview.delegate = self;
[self.view addSubview:loginview];
[loginview sizeToFit];
Mine is a little different:
loginview = [[FBLoginView alloc] init];
loginview.delegate = self;
[self.facebookCell addSubview:loginview];
[loginview sizeToFit];
As for the delegate methods, I've implemented them all verbatim. Why does the app crash? There is no valid reason for a crash when all the code is pretty much identical between my app and the sample app. The debugger doesn't help much even with Zombie Objects on. The actual error is: Thread 1: EXC_BAD_ACCESS (code=2, address=somethingoranother) Anyone got any ideas as to why this is happening?
Regards,
Mike
UPDATE: It appears that the crash happens because something is recurring infinitely on a loop. Seems like over 100,000 processes were put on the main thread by the FB SDK! How?!
UPDATE 2: I'm beginning to think the error is here, even though I copied this straight from the sample AppDelegate.
- (BOOL)application:(UIApplication *)application
openURL:(NSURL *)url
sourceApplication:(NSString *)sourceApplication
annotation:(id)annotation {
// attempt to extract a token from the url
return [FBAppCall handleOpenURL:url
sourceApplication:sourceApplication
fallbackHandler:^(FBAppCall *call) {
NSLog(#"In fallback handler");
}];
}
Does this help at all?
I'm having whats seems to be the exact problem, but I have my application sandbox mode already disabled. This app has been working perfectly before, but I just upgraded the SDK and now this happens.
If I have a facebook account configured in iOs, it will work ok, but if not, It will crash.
One thing worth mentioning is if I remove the url scheme, so the app can't go to the web browser or the facebook app, It will user a web view to log in and this works too
EDIT: As far as I'm able to tell, my problem relies in not having access to my application settings in facebook.
The facebook SDK does an [FBUtility fetchAppSettings:callback:] call, more specifically, it does an
https://graph.facebook.com/267496536695242?fields=supports_attribution,supports_implicit_sdk_logging,suppress_native_ios_gdp,name,
which in the case of my app fails with:
{
"error": {
"message": "Unsupported get request.",
"type": "GraphMethodException",
"code": 100
}
}
In comparision, any of the examples apps, for example this one, SessionLoginSample
https://graph.facebook.com/380615018626574?fields=supports_attribution,supports_implicit_sdk_logging,suppress_native_ios_gdp,name
returns correctly this:
{
"supports_attribution": true,
"supports_implicit_sdk_logging": true,
"suppress_native_ios_gdp": 0,
"name": "SessionLoginSample",
"id": "380615018626574"
}
Because the SDK expects something it keeps making the same request and gets stuck in a loop until the simulator crashes.
To confirm this, I've manually inserted the expected parameters in the callback, modifyng the facebook sdk, and now everything work perfectly.
It's worth mentioning that I upgraded the SDK from 2.0 which was deprecated, and there was a few parameters in the settings page that were outdated (no client token set, authorization as native/Desktop instead Web, without having the app secret key in the app) but I've already set them alright..
EDIT 2:
This is the method from Facebook SDK (in FBUtility.m) that I've modified. I only added the "bad stuff" if clause.
+ (void)fetchAppSettings:(NSString *)appID
callback:(void (^)(FBFetchedAppSettings *, NSError *))callback {
if (!g_fetchedAppSettingsError && !g_fetchedAppSettings) {
NSString *pingPath = [NSString stringWithFormat:#"%#?fields=supports_attribution,supports_implicit_sdk_logging,suppress_native_ios_gdp,name", appID, nil];
FBRequest *pingRequest = [[[FBRequest alloc] initWithSession:nil graphPath:pingPath] autorelease];
if ([pingRequest startWithCompletionHandler:^(FBRequestConnection *connection, id result, NSError *error) {
// Bad stuff
if (error) {
error = nil;
result = [NSDictionary dictionaryWithObjectsAndKeys:#"true", #"supports_attribution",
#"true", #"supports_implicit_sdk_logging",
#"0", #"suppress_native_ios_gdp",
#"Your_App_Display_Name", #"name", nil];
}
if (error) {
g_fetchedAppSettingsError = error;
[g_fetchedAppSettingsError retain];
} else {
g_fetchedAppSettings = [[[FBFetchedAppSettings alloc] init] retain];
if ([result respondsToSelector:#selector(objectForKey:)]) {
g_fetchedAppSettings.serverAppName = [result objectForKey:#"name"];
g_fetchedAppSettings.supportsAttribution = [[result objectForKey:#"supports_attribution"] boolValue];
g_fetchedAppSettings.supportsImplicitSdkLogging = [[result objectForKey:#"supports_implicit_sdk_logging"] boolValue];
g_fetchedAppSettings.suppressNativeGdp = [[result objectForKey:#"suppress_native_ios_gdp"] boolValue];
}
}
[FBUtility callTheFetchAppSettingsCallback:callback];
}
]
);
} else {
[FBUtility callTheFetchAppSettingsCallback:callback];
}
}
Someone found the answer on another thread. In the Facebook Developer centre, the app was set to Sandboxing mode which is what caused this error. Seems it wasn't a problem with the code after all.
Facebook has fixed a server error that was causing this for a lot of developers. However, the server fix only makes the infinite loop problem less likely to happen. It is still there. I created a new bug to track the infinite loop problem.
https://developers.facebook.com/bugs/446010282155033
It's a memory access error, because the loginView is in a __block space.
Just move your controller ( the loginView delegate ) in this zone and it should work.
FBLoginView *loginview = [[FBLoginView alloc] init];
static id staticDelegateInstance = self;
loginview.frame = CGRectOffset(loginview.frame, 5, 5);
loginview.delegate = staticDelegateInstance;
[self.view addSubview:loginview];
[loginview sizeToFit];

How can I get UIWebView to open Facebook login page in response to the OAuth request on iOS 5 and iOS 6?

We have:
(1) Facebook API-based web application with Facebook OAuth functionality (“the FB web app”)
(2) UIWebView-based browser on iPad (“the Browser”)
Our objective is to open the Facebook Login page to sign in to the FB web app (1) inside the UIWebView-based Browser (2) on iPad.
There is a somewhat similar issue here:
http://facebook.stackoverflow.com/questions/11337285/no-longer-able-to-login-to-ios-app-via-oauth-the-page-requested-was-not-found
However, the issue of that question happens after the user enters login and password into the Facebook form. Our problem is that we cannot get the Facebook login form displayed in the first place. Changing the app type to from “Web” to “Native/Desktop”, as suggested in that question, did not help.
Steps:
1. Open our web page (simple HTML page) with this UIWebView Browser
2. Click on “FB web app” launch button on this page
3. OnClick JavaScript tries to initiate OAuth, which should open the login screen of Facebook to sign in to the FB web app
Current outcome (issue):
On iOS 5.+ and iOS 6.+ devices
- Our web page stays unchanged
- Facebook login page is NOT shown (our web page is still displayed)
On iOS 4.3 (works as expected):
- the Facebook login page is opened in the same UIWebView object of the Browser (replaces our web page)
Expected outcome:
- Facebook login page is displayed, and the user can enter Facebook login & password
- Works on iOS 5.+ and iOS 6.+ if launched in Safari browser on iPad. Facebook login page is opened in a separate tab (in contrast, there are no separate tabs in UIWebView)
Question: How can I get UIWebView to open Facebook login page in response to the OAuth request on iOS 5+ and iOS 6+?
More technical details:
We log different NSURLRequest fields from within
-(BOOL)webView(UIWebView*)webView shouldStartLoadWithRequest(NSURLREquest*)request navigationType:…
And we notice some difference in logs for “correct” and “incorrect” behaviors. Here how execution flows look for me:
Firstly, I press “FB Web App” launch button to initiate OAuth, then some cases go
iOS 4.3, “correct”
request to www.facebook.com/dialog/oauth?...
request to fbwebapp.com
request to m.facebook.com/login.php?....
--here facebook login appears
iOS 5.0, “incorrect1”
request to www.facebook.com/dialog/oauth?...
request to fbwebapp.com
request to m.facebook.com/login.php?...
Then it may be
--a lot of m.facebook.com/login.php?...with next… in parameters
followed by sqlite error
--right now I see “Sorry, something went wrong” page from facebook (it’s a first time at all I encounter it)
iOS 6.0 “incorrect2”
request to www.facebook.com/dialog/oauth?...
request to fbwebapp.com
-(void)webView:(UIWebView*)webView didFailLoadWithError:(NSError*)error is invoked with error code -999
You can see that behavior definitely depends on iOS version. But common case is that error happens on the step of obtaining m.facebook.com/login.php.. URL. But that’s all that we can detect.
We’re banging our heads against that wall for the whole day looking for solutions. Hopelessly.
Can you help us get the Facebook Login page opened in the UIWebView in response to OAuth?
just use : this code
if (![FBSDKAccessToken currentAccessToken])
{
FBSDKLoginManager *manager = [[FBSDKLoginManager alloc]init];
manager.loginBehavior = FBSDKLoginBehaviorWeb;
[manager logInWithReadPermissions:#[#"public_profile", #"email", #"user_friends"] handler:
^(FBSDKLoginManagerLoginResult *result, NSError *error) {
NSLog(#"result.token: %#",result.token.tokenString);
NSLog(#"%#",result.token.userID);
NSLog(#"%hhd",result.isCancelled);
}];
}
// here manager.loginBehavior = FBSDKLoginBehaviorWeb; is all you need to open facebook in UIWebview
Did it!
It kinda of a hack, but the js facebook sdk login on UiWebView at iOS 6 finally works.
How it could be done? It is a pure JS + Facebook JS SDK + UIWebView Delegate handling functions solution.
JS - First step)
a login button (to connect with facebook) calls this function example, that will trigger Face JS login/oauth dialogs:
function loginWithFacebookClick(){
FB.login(function(response){
//normal browsers callback
});
}
JS - Second step)
add a authResponseChange listener every time user loads the webpage ( after FB.init() ) to catch user's connected status:
FB.Event.subscribe('auth.authResponse.Change', function(response){
//UIWebView login 'callback' handler
var auth = response.authResponse;
if(auth.status == 'connected'){
//user is connected with facebook! just log him at your webapp
}
});
AND with app's UIWebView delegate functions you can handler facebook oauth responses
Objective C - Third step)
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
NSString *url = [[request URL] absoluteString];
//when user status == connected (has a access_token at facebook oauth response)
if([url hasPrefix:#"https://m.facebook.com/dialog/oauth"] && [url rangeOfString:#"access_token="].location != NSNotFound)
{
[self backToLastPage];
return NO;
}
return YES;
}
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
NSString *url = [[webView.request URL] absoluteString];
if([url hasPrefix:#"https://m.facebook.com/dialog/oauth"])
{
NSString *bodyHTML = [webView stringByEvaluatingJavaScriptFromString:#"document.body.innerHTML"];
//Facebook oauth response dead end: is a blank body and a head with a script that does
//nothing. But if you got back to your last page, the handler of authResponseChange
//will catch a connected status if user did his login and auth app
if([bodyHTML isEqualToString:#""])
{
[self backToLastPage];
}
}
}
So, when 'redirect' user to the last loaded page, the second step is going to handler user action at facebook login dialogs.
If I got too fast with this answer, please ask me!
Hope it helps.
In case anyone is googling, here's what worked for me:
-(BOOL) webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)inType {
if ([request.URL.absoluteString containsString:#"m.facebook.com"]) {
if ([request.URL.absoluteString rangeOfString:#"back"].location == 0) {
[self.popUp removeFromSuperview];
self.popUp = nil;
return NO;
}
if (self.popUp) {
return YES;
}
UIWebView *wv = [self popUpWebView];
[wv loadRequest:request];
return NO;
}
return YES;
}
- (UIWebView *) popUpWebView {
toolbar height
UIWebView *webView = [[UIWebView alloc]
initWithFrame:CGRectMake(0, 0, (float)self.view.bounds.size.width,
(float)self.view.bounds.size.height)];
webView.scalesPageToFit = YES;
webView.delegate = self;
// Add to windows array and make active window
self.popUp = webView;
[self.view addSubview:webView];
return webView;
}
- (void)webViewDidFinishLoad:(UIWebView *)webView {
if (self.popUp) {
NSError *error = nil;
NSString *jsFromFile = #"window.close=function(){window.location.assign('back://' + window.location);};";
__unused NSString *jsOverrides = [webView
stringByEvaluatingJavaScriptFromString:jsFromFile];
JSContext *openerContext = [self.webView
valueForKeyPath:#"documentView.webView.mainFrame.javaScriptContext"];
JSContext *popupContext = [webView
valueForKeyPath:#"documentView.webView.mainFrame.javaScriptContext"];
popupContext[#"window"][#"opener"] = openerContext[#"window"];
}
//this is the secret sauce
if (webView == self.popUp
&& [webView.request.URL.absoluteString containsString:#"m.facebook.com"]
&& [[webView stringByEvaluatingJavaScriptFromString:#"document.body.innerHTML"] isEqualToString:#""]) {
[webView stringByEvaluatingJavaScriptFromString:#"eval(document.getElementsByTagName('script')[0].text)"];
}
}
I snagged a bunch of this implementation from here.
Depending on your web implementation, there will likely be one extra step. The Facebook script actually executes a window.close() then a window.open() then a window.close(). For me this was causing problems because on the web side, after this login is complete, my window (i.e. for the webView that I want the user to log in to) was getting a window.close() call, coming from the Facebook SDK. I'm assuming this is because the Facebook SDK expects that window.open() call to open a new window that it will close.
Since we didn't override the functionality of window.open(), calling window.open() won't do anything, and the Facebook SDK will attempt to close your window. This could cause all kind of problems, but for me since I'm using Parse, window.localStorage was set to null so I was getting all kinds of errors.
If something like this is happening for you, you have two options to fix it:
If you have control of the web code, and your down for a small hack, throw this in window.close=function(){}
If you don't have control of the web code, you can either add an override to window.close for the main webView like we did for the popUp webView, or override the window.open function to open another popUp (which is described in more detail here)
Use the FBDialog class to prompt the user to login. This uses a webview inside of the app, therefore on successful login the user will be logged in inside of any UIWebView:
NSString *kRedirectURL = #"fbconnect://success";
NSString *kSDK = #"ios" ;
NSString *kLogin = #"oauth";
NSString *kDialogBaseURL = #"https://m.facebook.com/dialog/";
NSMutableDictionary* params = [NSMutableDictionary dictionaryWithObjectsAndKeys:
AE_FACEBOOK_APPID, #"client_id",
#"user_agent", #"type",
kRedirectURL, #"redirect_uri",
#"touch", #"display",
kSDK, #"sdk",
nil];
NSString *loginDialogURL = [kDialogBaseURL stringByAppendingString:kLogin];
FBLoginDialog* loginDialog = [[FBLoginDialog alloc] initWithURL:loginDialogURL
loginParams:params
delegate:self];
[loginDialog show];
Then make your class adhere to the FBDialogDelegate protocol, and add this function to your class:
-(void)fbDialogLogin: (NSString *)token expirationDate:(NSDate *)expirationDate{
// Store the token and expiration date into the FB SDK
self.facebook.accessToken = token;
self.facebook.expirationDate = expirationDate;
// Then persist these so the SDK picks them up on next load
NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:self.facebook.accessToken forKey:ACCESS_TOKEN_KEY];
[defaults setObject:self.facebook.expirationDate forKey:EXPIRATION_DATE_KEY];
[defaults synchronize];
}
HTH!
How to facebook login in UIWebView.
Objective-c
Use taylorstine's answer.
He saved my day. Thank you taylorstine
But I'm using Swift 3. so I just converted code below from taylorstine's answer.
Swift 3.
func webView(_ webView: UIWebView, shouldStartLoadWith request: URLRequest, navigationType: UIWebViewNavigationType) -> Bool {
if let _ = request.url?.absoluteString.range(of: "m.facebook.com" ) {
if let _ = request.url?.absoluteString.range(of: "back"){
self.popUp?.removeFromSuperview()
self.popUp = nil
return false
}
if let _ = self.popUp {
return true
}
let wv = popUpWebView()
wv.loadRequest(request)
return false
}
return true
}
func popUpWebView() -> UIWebView {
let webView = UIWebView(frame: self.view.frame)
webView.delegate = self
self.popUp = webView
self.view.addSubview(webView)
return webView
}
func webViewDidFinishLoad(_ webView: UIWebView) {
if let _ = self.popUp {
let jsFromFile = "window.close=function(){window.location.assign('back://' + window.location);};"
let _ = webView.stringByEvaluatingJavaScript(from: jsFromFile)
let openerContext = self.webView.value(forKeyPath: "documentView.webView.mainFrame.javaScriptContext") as! JSContext
let popupContext = webView.value(forKeyPath: "documentView.webView.mainFrame.javaScriptContext") as! JSContext
popupContext.setObject("opener", forKeyedSubscript: "window" as (NSCopying & NSObjectProtocol)!)
popupContext.setObject(openerContext.objectForKeyedSubscript("window"), forKeyedSubscript: "opener" as (NSCopying & NSObjectProtocol)!)
}
if webView == self.popUp
&& (webView.request?.url?.absoluteString.range(of:"m.facebook.com") != nil)
&& webView.stringByEvaluatingJavaScript(from: "document.body.innerHTML") == "" {
webView.stringByEvaluatingJavaScript(from: "eval(document.getElementsByTagName('script')[0].text)")
}
}

ShareKit - SHKFacebook: Is there a way to get the authorization_token ?

I was wondering if there was a way to get access to the authorization_token returned by the oauth process during a Facebook login in SHKFacebook?
I already have the facebook_access_token. What I'm trying to get access to is the authorization_token returned during the first half of the oauth2 login.
Thanks!
Facebook:
if ([[NSUserDefaults standardUserDefaults] objectForKey:#"FBUserId"]) {
// user login facebook
}
Twitter:
SHKTwitter *checkTwitterLoging = [[SHKTwitter alloc] init];
if ([checkTwitterLoging isAuthorized]) {
// user loving twitter
}
[checkTwitterLoging release];

Limit providers while integrating Gigya in iPhone?

I am integrating Gigya in my iphone app. Now it provides 17 providers for access, I want to limit it to just 9 providers. How can I do that?
Has any one integrated it for iPhone? It loads a web view which displays 17 providers in a grouped table format, see here.
To set Facebook and Twitter you can use following code.
GSDictionary *pParams5 = [[GSDictionary new] autorelease];
[pParams5 putStringValue:#"facebook,twitter" forKey:#"enabledProviders"];
[gsAPI showAddConnectionsUI:pParams5 delegate:self context:nil];
GSAPI *gsAPI // declare this
gsAPI = [[GSAPI alloc] initWithAPIKey:<API-KEY> viewController:self]; // i kept this in viewDidload
// add this code to have facebook and twitter on provider list
GSDictionary *pParams5 = [[GSDictionary new] autorelease];
[pParams5 putStringValue:#"facebook,twitter" forKey:#"enabledProviders"];
[gsAPI showAddConnectionsUI:pParams5 delegate:self context:nil];
//this method called when login fails
-(void)gsLoginUIDidFail:(int)errorCode errorMessage:(NSString*)errorMessage context:(id)context{ }
// this method called on successful login
- (void) gsLoginUIDidLogin:(NSString*)provider user:(GSDictionary*)user context:(id)context {}
Check whether you have valid API

FBConnect won't display Publish to Wall after login

I have an app that I want to be able to connect to Facebook and post to the user's wall. I have the following code:
- (void)viewDidLoad {
static NSString* kApiKey = #"PRIVATE";
static NSString* kApiSecret = #"PRIVATE";
_session = [[FBSession sessionForApplication:kApiKey secret:kApiSecret delegate:self] retain];
// Load a previous session from disk if available. Note this will call session:didLogin if a valid session exists.
[_session resume];
// Set these values from your application page on http://www.facebook.com/developers
// Keep in mind that this method is not as secure as using the sessionForApplication:getSessionProxy:delegate method!
// These values are from a dummy facebook app I made called MyGrades - feel free to play around!
[super viewDidLoad];
}
- (IBAction)postGradesTapped:(id)sender {
_posting = YES;
// If we're not logged in, log in first...
if (![_session isConnected]) {
self.loginDialog = nil;
_loginDialog = [[FBLoginDialog alloc] init];
[_loginDialog show];
}
// If we have a session and a name, post to the wall!
else if (_facebookName != nil) {
[self postToWall];
}
// Otherwise, we don't have a name yet, just wait for that to come through.
}
The problem I have is that when the user clicks the button associated with the IBAction it will pop up the login dialog, but then the window disappears without ever pulling up the Publish Story to Wall dialog. How do I get it to login and then pull up the Publish Story to Wall?
I think you may need to use FBPermissionDialog to ask for "post to wall" permission first (I'm not sure what the exact string is; it might be in the examples).
Also note that "FBSession" is the old "iPhone" SDK (last updated in April); there's a newer "iOS" SDK at http://github.com/facebook/facebook-ios-sdk
I once encountered this behavior when my Security Key was wrong (in the new API you don't need it, but if you're based on old API it still requires it).
Make sure you use "App Id" and "App Secret" from the Facebook app control page. (And not "API Key")
Good luck!