Why can't I authenticate to Facebook Chat in my iOS application? - iphone

I have been scouring the internet trying to find a solution to this problem. I understand the basic idea on how it is supposed to work, but I can't get the implementation to work and I can't find any decent examples to help me. So far I have successfully been able to log in a user using the iOS 6 authentication mechanism, but I cannot figure out how to authenticate a user to the Jabber server from there. Here is what I have:
After the user has logged in connect is called
-(void)connect
{
[self setupStream];
NSError *error = nil;
[_xmppStream authenticateWithFacebookAccessToken: FBSession.activeSession.accessTokenData.accessToken error:&error];
NSLog(#"%#", error);
[NSString stringWithFormat:#"%#", self];
}
-(void)newSetupStream
{
_xmppStream = [[XMPPStream alloc] initWithFacebookAppId:#"611051652253156"];
#if !TARGET_IPHONE_SIMULATOR
{
xmppStream.enableBackgroundingOnSocket = YES;
}
#endif
_xmppReconnect = [[XMPPReconnect alloc] init];
_xmppRosterStorage = [[XMPPRosterCoreDataStorage alloc] init];
_xmppRoster = [[XMPPRoster alloc] initWithRosterStorage:_xmppRosterStorage];
_xmppRoster.autoFetchRoster = YES;
_xmppRoster.autoAcceptKnownPresenceSubscriptionRequests = YES;
_xmppvCardStorage = [XMPPvCardCoreDataStorage sharedInstance];
_xmppvCardTempModule = [[XMPPvCardTempModule alloc] initWithvCardStorage:_xmppvCardStorage];
_xmppvCardAvatarModule = [[XMPPvCardAvatarModule alloc] initWithvCardTempModule:_xmppvCardTempModule];
_xmppCapabilitiesStorage = [XMPPCapabilitiesCoreDataStorage sharedInstance];
_xmppCapabilities = [[XMPPCapabilities alloc] initWithCapabilitiesStorage:_xmppCapabilitiesStorage];
_xmppCapabilities.autoFetchHashedCapabilities = YES;
_xmppCapabilities.autoFetchNonHashedCapabilities = NO;
[_xmppReconnect activate:_xmppStream];
[_xmppRoster activate:_xmppStream];
[_xmppvCardTempModule activate:_xmppStream];
[_xmppvCardAvatarModule activate:_xmppStream];
[_xmppCapabilities activate:_xmppStream];
[_xmppStream addDelegate:self delegateQueue:dispatch_get_main_queue()];
[_xmppRoster addDelegate:self delegateQueue:dispatch_get_main_queue()];
}
No matter what I try it always returns the same error: Error Domain=XMPPStreamErrorDomain Code=4 "The server does not support X-FACEBOOK-PLATFORM authentication."
I am not incredibly familiar with either XMPP or the Facebook API so I'm sure there is something simple I am missing, but I have been working on this forever and been unable to make any progress. Any ideas?

I found my answer. In case anyone else runs into this same problem: I never actually told my XMPPStream to connect. I had tried all of the connect methods before, but they never worked. I now realize that I simply did not wait for them to finish connecting. Here is what I ended up changing:
NSError *error;
NSError *err;
[_xmppStream connectWithTimeout:10.00 error:&err];
[_xmppStream authenticateWithFacebookAccessToken: FBSession.activeSession.accessTokenData.accessToken error:&error];
while (error)
{
sleep(1);
[_xmppStream authenticateWithFacebookAccessToken: FBSession.activeSession.accessTokenData.accessToken error:&error];
}
I realize that it's not the most elegant solution, but it works.

make sure you use chat.facebook.com or facebook.com as the host name.
You must also open session with xmpp_login permission.
For me the above host name worked 100% fine

Related

how to fix -[__NSCFString gtm_stringByUnescapingFromURLArgument] in google+ authentication

I am trying to create an application that retrieves the current user's email id, user id, user name from his google+ account. The part of the code is as follows,
- (IBAction)googleSigninBtnTapped:(id)sender
{
[GPPSignInButton class];
[GPPSignIn sharedInstance].clientID =[NSString stringWithFormat:#"MY APP ID"];
GPPSignIn *signIn = [GPPSignIn sharedInstance];
signIn.delegate = self;
signIn.shouldFetchGoogleUserEmail = YES;
signIn.shouldFetchGoogleUserID = YES;
signIn.actions = [NSArray arrayWithObjects:
#"http://schemas.google.com/AddActivity",
#"http://schemas.google.com/BuyActivity",
#"http://schemas.google.com/CheckInActivity",
#"http://schemas.google.com/CommentActivity",
#"http://schemas.google.com/CreateActivity",
#"http://schemas.google.com/ListenActivity",
#"http://schemas.google.com/ReserveActivity",
#"http://schemas.google.com/ReviewActivity",
nil];
[signIn trySilentAuthentication];
}
(void)finishedWithAuth:(GTMOAuth2Authentication *)auth error:(NSError )error
{
if (error)
{
NSLog(#"Status: Authentication error: %#", error);
}
else
{
NSLog(#"Status: Authenticated");
NSLog(#"Email: %#",[GPPSignIn sharedInstance].authentication.userEmail);
GTLServicePlus plusService = [[[GTLServicePlus alloc] init] autorelease];
plusService.retryEnabled = YES;
[plusService setAuthorizer:[GPPSignIn sharedInstance].authentication];
GTLQueryPlus *query = [GTLQueryPlus queryForPeopleGetWithUserId:#"me"];
[plusService executeQuery:query completionHandler:^(GTLServiceTicket *ticket, GTLPlusPerson *person, NSError *error)
{
if (error)
{
GTMLoggerError(#"Error: %#", error);
}
else
{
[person retain];
NSLog(#"%#", person.displayName);
NSLog(#"%#", person.identifier);
}
}];
}
}
But when i am trying to execute my app, it gets crashed, saying that
'-[__NSCFString gtm_stringByUnescapingFromURLArgument]: unrecognized selector sent to instance 0x9e435b0'
Can anybody help me on this...!!!
Thanks In Advance!!!
Yep, you need the -ObjC linker flag in, it's not finding one of the categories from the GoogleOpenSource framework.
See Step 3 in the setup guide: https://developers.google.com/+/mobile/ios/getting-started#step_3_initialize_the_google_client
Basically, in Other Linker Flags, add -ObjC (capitalisation is important, note!). Also make sure you have included both GooglePlus and GoogleOpenSource frameworks in your project.
Add with _objc the other flag called -lc++

Can always login

A colleague and me have stumbled upon bug in both of our codes. We happen to both be working on a login page. I am using the networking library AFNetworking to connect to an outside source, which tells if the user has actually registered. The friend likewise (but without any outside library). (Code is for ios.)
We are both running into the same problem: after making a valid call, everything goes as expected. But if we make another call that is invalid (e.g., wrong username and/or password) I am still able to login.
Why? We are not saving any information.
Here is some code:
BasicAuth * manger = [BasicAuth sharedManager];
manger = nil;
[[BasicAuth sharedManager] setUsername:#"bad_username" andPassword:#"wrong"];
[[BasicAuth sharedManager] getPath:#"/users/tokens"
parameters:nil
success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"operation = %#", [responseObject description]);
NSError *error = nil;
/*
*/
if (error) {
NSLog(#"Error serializing %#", error);
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
if (operation.response.statusCode == 500) {
} else {
NSData *jsonData = [operation.responseString dataUsingEncoding:NSUTF8StringEncoding];
// NSString *errorMessage = [ objectForKey:#"error"];
NSLog(#"We have an issue %#", [error description]);
}
}]; return YES;
If I call this same code but with a correct username/password AND THEN call the above code, then I can still login in and the information I get back is the same as when I sent the "good" request. Also, when I try to make login requests using curl from my laptop I do not run into the same issues, which is making me think that, for some reason, the information being sent is not being updated. But I can't see how or why. Again, this is whether 3rd party library is being used or not.
Thoughts, suggestions?
note: BasicAuth (see above) is a subclass of AFHTTPCLIENT
Your server may be sending some cookie and iOS is store it.
Try to delete the cookies before setting the new username and password.
Here you have a code snippet that deletes all cookies. Keep in mind that in iOS the cookies are application private, so deleting them is not going to affect other apps.
NSHTTPCookieStorage *storage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
NSArray *cookies = [storage cookies];
for (NSHTTPCookie *cookie in cookies)
{
[storage deleteCookie:cookie];
}

Google+ check-in location in ios

I want to implement location check-in feature in ios. My application is using google+ ios sdk. The problem which I am facing is that after I have implemented google+ check-in feature then that post is not being displayed on my google+ account.
The technique which I have tried and implemented is written below.
-(IBAction)checkIn
{
GTMOAuth2Authentication *auth = [GPPSignIn sharedInstance].authentication;
GTLServicePlus* plusService = [[GTLServicePlus alloc] init] ;
plusService.retryEnabled = YES;
[plusService setAuthorizer:auth];
GTLPlusMoment *moment = [[GTLPlusMoment alloc] init];
moment.type = #"http://schemas.google.com/CheckInActivity";
GTLPlusItemScope *target = [[GTLPlusItemScope alloc] init] ;
target.url =#"https://developers.google.com/+/plugins/snippet/examples/place";
moment.target = target;
GTLQueryPlus *query =
[GTLQueryPlus queryForMomentsInsertWithObject:moment
userId:#"me"
collection:kGTLPlusCollectionVault];
[plusService executeQuery:query
completionHandler:^(GTLServiceTicket *ticket,
id object,
NSError *error) {
if (error) {
GTMLoggerError(#"Error: %#", error);
NSString *failure =
[NSString stringWithFormat:#"Status: Error: %#", error];
NSLog(#"%#",failure);
} else {
NSString *result = #"CheckedIn Saved in Google+";
NSLog(#"%#",result);
}
}];
}
Can any one please help me out. Is this the right way of implementing location check-in feature of google+ or is there any other method for it?
The method you're using is writing an "app activity" to Google+, which stores a "moment" in the user's app activity vault. As noted on https://developers.google.com/+/mobile/ios/app-activities these moments are not directly visible on the user's stream, although users may choose to share them to the stream if they wish.
To see the moments that have been shared, you will need to use the desktop app. Your profile has a list of apps that are using the Google+ Sign-In and you can view, share, and delete the activities for each of these apps. The mobile Google+ clients don't let you view the activities yet.

iOS 6 SDK SLRequest returning '400'

Let me make this clear. I am NOT using the Facebook SDK. I'm using iOS SDK's Social.framework, and ACAccountStore to access Facebook accounts, and post with it/them.
I use the same code to post on Twitter. It works 100%. But for some reason regardless of what I do for Facebook integration, I get a "400" error when I try to post.
My method is:
ACAccountStore *account = [[ACAccountStore alloc] init];
ACAccountType *facebookAccountType = [account accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierFacebook];
// Specify App ID and permissions
NSDictionary *options = #{ ACFacebookAppIdKey: #"MY_APP_ID",ACFacebookPermissionsKey: #[#"publish_stream", #"publish_actions"],ACFacebookAudienceKey: ACFacebookAudienceFriends };
[account requestAccessToAccountsWithType:facebookAccountType options:options
completion:^(BOOL granted, NSError *error)
{
if (granted == YES)
{
NSDictionary *parameters = #{#"message": string999};
NSURL *feedURL = [NSURL URLWithString:#"https://graph.facebook.com/me/feed"];
SLRequest *feedRequest = [SLRequest
requestForServiceType:SLServiceTypeFacebook
requestMethod:SLRequestMethodPOST
URL:feedURL
parameters:parameters];
acct.accountType = facebookAccountType;
// Post the request
[feedRequest setAccount:acct];
// Block handler to manage the response
[feedRequest performRequestWithHandler:^(NSData *responseData, NSHTTPURLResponse *urlResponse, NSError *error)
{
if (granted && error == nil) {
} else {
NSLog(#"Facebook response, HTTP response: %i %#", [urlResponse statusCode], [error description]);
[self closeShareMenu];
}
}];
}
}
I don't know where I'm going wrong! It's so annoying! I've set up my app correctly in Facebook Developers and all! Please help -_-'
Following up to the chat session held between #fguchelaar and yours truly yesterday; I was able to ascertain the following solution for this issue.
Add the following in your iOS completion handler:
NSString *temp = [[NSString alloc] initWithData:data encoding: NSUTF8StringEncoding];
NSLog(temp);
//'data' is your 'responseData' (or another object name) that you declare in your completion handler.
This will allow you to see the exact cause of the issue printed to the Debug Console. Now depending on the issue presented, you'll need to grab a Facebook account from the Array of Accounts generated when you call this handler in the iPhone SDK. Not at any prior stage whatsoever, as the Access Token will likely expire and give you this '400' error.
In my case; the error printed was: error:{'400' A valid access token is required… which vastly annoyed me as my prior method to access and check the current Twitter account was working perfectly. And my theory was that it should work just as well for Facebook. Why should the access token be instantaneously revoked if I'm grabbing the account a split second before?
The way I solved my issue (depending on the reason for your error the answer can vary) was to use a for loop to check the newly created array of accounts, with the sole purpose of finding the account there with the same identifier string as the one I saved into NSData/NSKeyedArchiver.
for(ACAccount *a in arrayOfAccounts) {
if([a.identifier isEqualToString:storedAccount.identifier]) {
//set the account to be used
accountToBeUsed = a;
//don't forget to break the For loop once you have your result.
break;
} else {
//This else{} block is not strictly necessary, but here you could set an account if no account was found with a matching identifier.
}
}
For it to work, it's recommended to declare an ACAccount object in your View Controller's .h file, add a #property and #synthesize it, so it can be assigned within the for loop and used after the break; statement.
This effectively solved my whole issue with the '400' error. It was inexplicably frustrating for about six hours of my day, so I hope that my explanation helps anybody who happens to stumble across this issue, and my question here on Stack Overflow :)
Regards,
cocotutch

Game Center inviting friends programmatically

I'm facing difficulty inviting a friend to the match.
GKMatchRequest *request = [[[GKMatchRequest alloc] init] autorelease];
request.minPlayers = 2;
request.maxPlayers = 2;
request.playersToInvite = [NSArray arrayWithObjects: #"G:1102359306",nil ];
// GKMatchmakerViewController *mv = [[GKMatchmakerViewController alloc] initWithMatchRequest:request];
// [self presentModalViewController:mv animated:YES];
[[GKMatchmaker sharedMatchmaker] findMatchForRequest:request withCompletionHandler:^(GKMatch *match, NSError *error) {
if (error) {
NSLog([error description]);
}
else if (match != nil) {NSLog(#"good match");
//self.chatMatch = match;
//self.chatMatch.delegate = self;
//[self chatReady];
}
else {
NSLog(#"other error");
}
}];
The problem is I never receive the invitation notification on second device logged to the account - G:1102359306.
When I use GKMatchmakerViewController (uncomment above 2 lines) and comment GKMatchmaker block I have automatically checked the good friend - G:1102359306 and when I invites him the notification with accept/decline is shown, that's how I know it's correct.
Do you see anything wrong with the code above? I want to use my own UI to handle the multiplayer mode. The strange problem is I also don't see in console any logs good match/other error, and the [error description] is only printed when I call the above code twice - it says that the previous req was canceled.
You cannot programmatically invite a specific set of players to a match. The findMatchForRequest:withCompletionHandler: documentation says this:
The match request’s playersToInvite property is ignored; to invite a specific set of players to the match, you must display a matchmaker view controller.
There is no public API that does what you want.