IOS Facebook SDK can't get User info after log in - objective-c

Alright, I am having a devil of a time with getting some basic user info from the Facebook IOS SDK (3.1.1). Having done FB development with other platforms I am pretty convinced my issue has to do with the FB app's set up than with my code. BTW, I am in iTunes and have set an iTunes ID for iPhone. I have also carefully checked and quadruple checked the bundle ID in the App set up against my bundle ID.
Right now I can authenticate with a test user and get all the detail, etc. It works great. When I log in as a real user like myself (and I am a developer on the project) I get an Auth token, but calls to get the user fail, and I'm not sure what I have done wrong (if it works for a test user it should work for everyone).
All I need to get from the user, BTW is their First name, Last name, FB User ID, and email address (optional, but requested).
Currently after authenticating using the I'm using the games tutorial. Once I am logged in I do the following (although I have done a bunch of other things with the same result):
- (void)fbDidLogin
{
// removed the setup for the class level Facebook var that I am currently not using
// get information about the currently logged in user
NSString *fql = #"select uid, first_name, last_name, email from user where uid = me()";
NSDictionary *queryParam = [NSDictionary dictionaryWithObjectsAndKeys:fql, #"q", nil];
[FBRequestConnection startWithGraphPath:#"/fql"
parameters:queryParam
HTTPMethod: #"GET"
completionHandler:^(FBRequestConnection *connection,
id result,
NSError *error) {
[self meRequestResult:result WithError:error];
}];
}
The meRequestResult routine starts like this:
- (void)meRequestResult:(id)result WithError:(NSError *)error
{
if ([result isKindOfClass:[NSDictionary class]])
{
NSDictionary *dictionary;
if([result objectForKey:#"data"])
dictionary = (NSDictionary *)[(NSArray *)[result objectForKey:#"data"] objectAtIndex:0];
else
dictionary = (NSDictionary *)result;
[fbUserData release];
fbUserData = [dictionary retain];
NSString *facebookId = [dictionary objectForKey:#"id"];
if(!facebookId)
facebookId = [dictionary objectForKey:#"uid"];
// and more follows that is not pertinent
When I turn on request logging in the FB IOS SDK. I see the same things and can not find any description anywhere what these mean.
Here's the last 10 or so lines from the log:
2012-12-03 11:52:12.394 mTender[6572:1cd03] Reachability Flag Status: -R -----l- networkStatusForFlags
2012-12-03 11:52:12.395 mTender[6572:1cd03] The internet is working via WIFI.
2012-12-03 11:52:12.396 mTender[6572:1cd03] Reachability Flag Status: -R ------- networkStatusForFlags
2012-12-03 11:52:12.396 mTender[6572:1cd03] A gateway to the host server is working via WIFI.
2012-12-03 11:52:35.093 mTender[6572:1cd03] FBSDKLog: Request <#1111>:
URL: https://graph.facebook.com//fql?sdk=ios&access_token=ACCESS_TOKEN_REMOVED&q=select%20uid%2C%20first_name%2C%20last_name%2C%20email%20%20from%20user%20where%20uid%20%3D%20me%28%29&migration_bundle=fbsdk%3A20121003&format=json
Method: GET
UserAgent: FBiOSSDK.3.1.1
MIME: multipart/form-data; boundary=3i2ndDfv2rTHiSisAbouNdArYfORhtTPEefj3q2f
2012-12-03 11:52:37.194 mTender[6572:1cd03] Error: HTTP status code: 500
2012-12-03 11:52:37.196 mTender[6572:1cd03] FBSDKLog: Response <#1111> <Error>:
The operation couldn’t be completed. (com.facebook.sdk error 5.)
Hopefully someone can figure this out. It's the last step of this project..

I am doing something very similar to you. I am using facebook for login so that I don't have to worry about storing passwords and what not.
I followed this set of instructions.. The facebook site seems to be horrid the way its layed out with out of date stuff all over the place.
You can use native facebook or web based user authentication (the SDK will manage all that) so it will work on older versions of iOS and when not signed in to native facebook.
You will set a handler which will give you a "NSDictionary *user" with all the stuff that you need. No need to use the graph api on the iphone client.

i think you have to see alternate way because the REST API has been deprecated. To make FQL queries you have to use the Graph API call.
http://developers.facebook.com/docs/reference/rest/fql.query/

OK, I'm going to close this out.
I reverted to an SDK back in November of 2011. It didn't seem to be working at first, and then it just started working. I suspect a bug on Facebook's end was causing this. I haven't updated to the latest again to try, but this is my only guess as to what happened.
If you've done any lengthy Facebook development you know that sometimes their bugs really make things difficult. That said, no idea if this is the actual answer since I really didn't make any coding changes from the original code.
I know that I purposefully left the bundle ID out of the FB App Setup..

Related

Philips Hue API: Remove application/username from bridge in order to start over

I'm using the HueSDK_iOS and everything seems to work fine.
I have one simple question for which I cannot seem to find a simple answer.
I want to test my app's functionality whenever a new user installs it.
I cannot find a proper way to de-authenticate my app from the bridge, so it will ask again to search for bridges etc and I can start over, to test everything.
I /did/ use :
cache = [PHBridgeResourcesReader readBridgeResourcesCache];
PHBridgeConfiguration *config = [cache bridgeConfiguration];
PHBridgeSendAPI *sendAPI = [[PHBridgeSendAPI alloc] init];
[sendAPI removeWhitelistEntryWithUsername:[config username] completionHandler:^(NSArray *errors) {
...
}];
and in the first time, it returns no errors, but I still am authenticated and can use the API , control lights etc, no notification arrives for disconnection or noLocalConnection.
If I run it again, I get an error: error = {\n address = \"/config/whitelist/_a_user_name\";\n description = \"resource, /config/whitelist/_a_user_name, not available\";\n type = 3;\n
(where a "_a_user_name" is the automatically generated username)
but I still keep being authenticated to the bridge.
So it seems it does delete the username from the whitelist, but still everything works as if I was authenticated.
So the question is simple: How do I remove my app from the bridge so I can start over and test all the steps? (Pushlinking etc)
It appears it is a bug in the bridge software as I was informed by Philips API support. They asked me to wait for an update.
According to this it can only be done through https://account.meethue.com/apps starting with API version 1.31.0.

NSURLConnection timing out on iOS8

I have been working on an application involving client-server communication. Everything was working fine until iOS 7.1. Now that Xcode 6 GM Seed in launched, I tried to build and run the project on iOS8 simulator. However, all NSURLConnections seem to time out now. I can not get any response from the server. This works on iOS 7 simulator and Xcode 6.
I tried using the NSURLSession hoping that would resolve the issue. But it hasnt.
Any help will be highly appreciated!! If anyone else has faced this issue, please let me know if you have any workaround to this.
UPDATE:
This is the code I have used:
NSString *authStr = [NSString stringWithFormat:#"%#:%#", username, password];
NSData *authData = [authStr dataUsingEncoding:NSUTF8StringEncoding];
NSString *authValue = [NSString stringWithFormat: #"Basic %#",[authData base64EncodedStringWithOptions:0]];
[inURLRequest setValue:authValue forHTTPHeaderField:#"Authorization"];
Please note that the inURLRequest is already iniatlized with the desired URL.
After this just use the inURLRequest to fire the transaction as usual. For eg., in case of NSURLSession, create a download task using this request object and call resume API on it.
Well, I have found a fix for this issue.
The app had basic authentication in place for each REST webservice. This means that we used to get an authentication challenge for each webservice where we sent the credentials back with the challenge.
I changed this to send the credentials in the request header (in encrypted format) as a header field.
I am not sure how this was working in iOS 7 and not in iOS 8. But this seems to have fixed my problem :).
If you are streaming data to the NSURLConnection make sure you write new data exactly once when the stream event hasSpaceAvail has arrived - I found I had connection issues when I had wrong handling of the hasSpaceAvail event.
do not write more than once in response to the event
do not write zero times (or else you won't get another hasSpaceAvail event)

NSString's stringWithContentsOfURL uses browser cookies?

I'm working on an objective-c project that downloads webpages from a community website and parses the results. The download code looks like this:
NSError* error = nil;
NSString* text = [NSString stringWithContentsOfURL:fileUrl encoding:NSASCIIStringEncoding error:&error];
if(text) {
return text;
}
else {
NSLog(#"Error = %#", error);
return nil;
}
The odd thing is that when I download from the site I see resulting content that I would only see if logged into the site (which, in my browser, I am).
Does that method (NSString stringWithContentsOfURL:encoding:error) use browser cookies when executing the request? If so, is it Safari specifically that it's integrated with? The default browser? I can't seem to find documentation describing the behavior that I'm seeing. I'm ok with the behavior (in fact, it's preferable), but I only want to depend on it if I fully understand what's going on.
Thanks for your time.
Cookies are automatically handled and stored in an app's NSHTTPCookieStorage shared instance. Call the cookies method and check to see if your cookie is there. If it is, then that confirms your suspicion.
EDIT: I highly suspect you are using a UIWebView in your app and logging in from there. In that case, then yes, cookies are stored in your app's NSHTTPCookieStorage shared instance and will be used with further URL requests.

Can't reauthenticate with different NSURLCredentials (old deleted ones are used)

i've been searching stackoverflow, google, apple and other places. The tips provided look promising, i implemented them but alltogether don't seem to work or get enforced.
Problem: I have an NSURLConnection with specific credentials. I then have a logout where I clear the credentials, the protectionspace, i remove all cached responses and delete all cookies in the sharedHTTPCookieStorage but when calling my authenticated request again a few seconds later even with wrong credentials I still am using the old (deleted) credentials
Here are some code extracts, where credentials are removed
NSDictionary *credentialsDict = [[NSURLCredentialStorage sharedCredentialStorage] allCredentials];
if ([credentialsDict count] > 0) {
// the credentialsDict has NSURLProtectionSpace objs as keys and dicts of userName => NSURLCredential
NSEnumerator *protectionSpaceEnumerator = [credentialsDict keyEnumerator];
id urlProtectionSpace;
// iterate over all NSURLProtectionSpaces
while (urlProtectionSpace = [protectionSpaceEnumerator nextObject]) {
NSEnumerator *userNameEnumerator = [[credentialsDict objectForKey:urlProtectionSpace] keyEnumerator];
id userName;
// iterate over all usernames for this protectionspace, which are the keys for the actual NSURLCredentials
while (userName = [userNameEnumerator nextObject]) {
NSURLCredential *cred = [[credentialsDict objectForKey:urlProtectionSpace] objectForKey:userName];
WriteLog(#"Method: switchView removing credential %#",[cred user]);
[[NSURLCredentialStorage sharedCredentialStorage] removeCredential:cred forProtectionSpace:urlProtectionSpace];
}
}
}
I then remove all cached responses
NSURLCache *sharedCache = [NSURLCache sharedURLCache];
[sharedCache removeAllCachedResponses];
I then delete all cookies
NSHTTPCookieStorage *cookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
NSArray *cookies = [cookieStorage cookies];
for (NSHTTPCookie *cookie in cookies) {
[cookieStorage deleteCookie:cookie];
NSLog(#"deleted cookie");
}
I also tried using no cookies and other policies
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:theURL cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:60.0];
[request setHTTPShouldHandleCookies:NO];
if(self.currentCookies != nil){
[request setAllHTTPHeaderFields:
[NSHTTPCookie requestHeaderFieldsWithCookies:nil]];
}
theConnection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
I also tried this hint here on specifically storing the cookies and passing them again. http://www.hanspinckaers.com/multiple-nsurlrequests-with-different-cookies. There's another blog on the web suggesting to add a "#" to each URL in order to enforce reauthentication, which works but just does not solve the issue because I need to count on session's credentials and the ability to use totally different credentials.
Is this a bug or known issue and how do I really solve this...
Put bluntly: What am I exactly doing wrong here?
This is really bugging me and keeping me from continuing my work.
I would greatly appreciate any input!
Thanks alot!
Unfortunately, there does not seem to be a solution to this problem.
You can use NSURLCredentialPersistenceNone or the # trick or you can define the 'connectionShouldUseCredentialStorage' delegate method to return NO. If you do that every time and your app never persists the credentials for a session, that will force the challenge to occur on every request.
For apps that are only performing minimal requests or that end up using a session cookie for authentication, that might work OK.
For apps that are sending a large number of requests, these solutions all result in a 401 response for every single request and that extra challenge-response can add up in terms of data and performance.
It would be nice if you could persist the credential storage for the session until you needed to log out and then switch to one of the work-arounds, but that is not possible.
As soon as you store the credentials once for a session, they get cached for the entire TLS session. That results in a need to wait about 10 minutes until that session goes away.
You can read more about this issue at: http://developer.apple.com/library/ios/qa/qa1727/_index.html
That document mentions a limited work-around that involves appending a '.' to the end of the server name. I have been unable to get that working, however.
Other than that, these are the solutions I can think of:
1) Always use the NSURLCredentialPersistenceNone & connectionShouldUseCredentialStorage workaround that should generate the 401s. Add the Basic authentication header to the request, yourself. This should prevent the extra 401's while also bypassing the credential storage. The code for adding that authorization looks something like this:
NSString *s ;
NSString *authStr ;
s = [NSString stringWithFormat:#"%#:%#",user,password] ;
s = [YourBase64Encoder base64EncodingForData:[NSData dataWithBytes:[s UTF8String] length:strlen([s UTF8String])]];
authStr = [NSString stringWithFormat:#"Basic %#",s] ;
[request setValue:authStr forHTTPHeaderField:#"Authorization"] ;
I don't know how this would be implemented for other authentication methods, but I presume it is possible.
2) Inform the user of the issue and ask them to restart the app
3) Implement your own low-level sockets based http retrieval mechanism that bypasses CFNetwork completely. Good luck with that :>)
I just ran into this issue with AFNetworking. I'm working with a backend that requires Authorization to be passed in the header. However, when the user logs out of the app and attempts to log back in (even with different creds) I was getting an error from the server. My solution was to clear out my apps cookies when clearing the authheader in logout.
- (void)clearAuthorizationHeader {
[self.manager.requestSerializer clearAuthorizationHeader];
NSHTTPCookieStorage *storage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
for (NSHTTPCookie *cookie in [storage cookies]) {
[storage deleteCookie:cookie];
}
}
I've run into this issue too. Clearing NSURLCredentialStorage seems to partially work, but it seems like I have to wait a few seconds after this for it to take effect. Doing another HTTP request without waiting results in the old Authorization header being used.
I was able to fix it by passing NSURLCredentialPersistenceNone while initializing my NSURLCredential:
NSURLCredential* credentials = [[NSURLCredential alloc] initWithUser:username password:password persistence:NSURLCredentialPersistenceNone];
note: this will cause 401 Challenges on every HTTP request you make with this NSURLCredential. However this isn't an issue if you get back some cookies that keep you authenticated.
For what it's worth, I'm having the same problem.
I think it's a timing issue. When using the simulator, if I wait 5-10 seconds before trying to log in again, login fails as expected. Also, when I use an actual phone, I can rarely get the problem to occur - which might be a function of the phone being slower, or might be a bug in the simulator.
I know it's an old topic. However the only thing, that works for me was to use different urls for different certificates.
It worked in my application, since I have only 2 certificates (one general in application resources and one custom downloaded from internet after the user verification process). In my case there are no cookies, and no credentials to clear so none of the solutions I found on stackoverflow worked.
I was facing the same problem, now it works.
Using NSURLConnection this issue can be fixed easily by adding a random number to the end of the URL:
So, search for your URLRequest and append the random number to URLRequest
NSInteger randomNumber = arc4random() % 999;
NSString *requestURL = [NSString stringWithFormat:#"%#?cache=%ld",yourURL,(long)randomNumber];
NSURL *URLRequest = [NSURL URLWithString:requestURL];
And make sure you have a random number at the end of all URLs you are calling.

failed to create oob message?

Hi I'm trying to build a simple chat client between two ipod touches Just as a start to learning Bonjour.
I connect the two devices fine and everything seems like it should work. I can send the data with no problems (no error) , but When I should then receive the data and I dont. When I look in the log, I see "GCKSessionEvent_IncomingOOBPacket: failed to create oob message" I've tried
Googling ever piece of that message looking for some answer but there are literally 0 results. I was hoping someone here might have an answer.
thanks
KC
Response to comment:
The three calls are
-(IBAction)SendMessage
{
NSData* aData = [[NSData alloc] initWithData:[typeText.text dataUsingEncoding: NSUTF8StringEncoding]];
NSUTF8StringEncoding];
[self sendDataToPeers:aData];
}
-(void)sendDataToPeers:(NSData*)data
{
NSError* err;
BOOL didSend = [self.mySession sendDataToAllPeers:data withDataMode:GKSendDataReliable error:&err];
}
-(void) receiveData:(NSData*)data fromPeer:(NSString*)peer inSession:(GKSession*)session context:(void*)context
{
NSString* text = [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]autorelease];
self.displayText.text = text;
}
I am also doing iphone to iphone with Wifi and GKSession. After aborted sessions (aka debugging or crash) Bonjour (or GKsessions) seem to get confused and this same scenario happens to me. With OS 3.x there was no message, just the hang. With OS 4.x I get the message "GCKSessionEvent_IncomingOOBPacket...". I have no idea what this means, but restarting the GKsession or reconnecting or sometimes just waiting solve the problem. I suspect might be a buffer full on outbound data due to messed up peers/receivers.
Kendrick, assuming you are using the 4.0 SDK, then you may be SOL on this. GKSession has a number of show-stopper bugs in the 4.0 SDK (crashes, errors, slowness) that were introduced recently. This message is due to one of them. I know because I was about to submit my GameKit app when they released 4.0 and now I'm waiting for 4.1 so I can submit it. The 4.1 Beta does fix a number of these issues, but it still doesn't work the way it worked on 3.1.3, sadly.