How to proceed after the Google Authentication in ios App? When i allow the access for my application. The window appear is "Please copy this code,switch to your application and copy it there:".I dont know how to proceed from here.
This is the code i write
SEL finishedSel = #selector(viewController:finishedWithAuth:error:);
viewController = [[GTMOAuth2ViewControllerTouch
controllerWithScope:scope
clientID:clientID
clientSecret:clientSecret
keychainItemName:nil
delegate:self finishedSelector:finishedSel]autorelease];
-(void)viewController:(GTMOAuth2ViewControllerTouch *)viewController
finishedWithAuth:(GTMOAuth2Authentication *)auth
error:(NSError *)error {
if (error != nil) {
// Authentication failed
} else {
// Authentication succeeded
}
}
after getting the authentication
you can use it to get user data, see this code
NSString *urlStr = #"https://www.googleapis.com/oauth2/v1/userinfo?alt=json";
NSURL *url = [NSURL URLWithString:urlStr];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[self.auth authorizeRequest:request
completionHandler:^(NSError *error) {
NSString *output = nil;
if (error) {
output = [error description];
} else {
// Synchronous fetches like this are a really bad idea in Cocoa applications
//
// For a very easy async alternative, we could use GTMHTTPFetcher
NSURLResponse *response = nil;
NSData *data = [NSURLConnection sendSynchronousRequest:request
returningResponse:&response
error:&error];
if (data) {
// API fetch succeeded
output = [[[NSString alloc] initWithData:data
encoding:NSUTF8StringEncoding] autorelease];
NSLog(#"output:%#",output);
} else {
// fetch failed
output = [error description];
}
}
}];
note you need to add this url in scope https://www.googleapis.com/auth/userinfo.profile
check this link gtm-oauth2
and here is a sample code of finishedWithAuth
(void)viewController:(GTMOAuth2ViewControllerTouch *)viewController finishedWithAuth:(GTMOAuth2Authentication *)auth error:(NSError *)error {
if (error != nil) {
// Authentication failed (perhaps the user denied access, or closed the
// window before granting access)
NSLog(#"Authentication error: %#", error);
NSData *responseData = [[error userInfo] objectForKey:#"data"]; // kGTMHTTPFetcherStatusDataKey
if ([responseData length] > 0) {
// show the body of the server's authentication failure response
NSString *str = [[[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding] autorelease];
NSLog(#"%#", str);
}
self.auth = nil;
} else {
// Authentication succeeded
//
// At this point, we either use the authentication object to explicitly
// authorize requests, like
//
// [auth authorizeRequest:myNSURLMutableRequest
// completionHandler:^(NSError *error) {
// if (error == nil) {
// // request here has been authorized
// }
// }];
//
// or store the authentication object into a fetcher or a Google API service
// object like
//
// [fetcher setAuthorizer:auth];
// save the authentication object
self.auth = auth;
}
}
Related
I have sent facebook request. Its working fine, but I am getting request(notification) only in iPhone facebook App, not in Facebook web application. I want both Facebook native app and web application to receive notification. How can I do that?
#pragma Sending Facebook app request
- (NSDictionary*)parseURLParams:(NSString *)query {
NSArray *pairs = [query componentsSeparatedByString:#"&"];
NSMutableDictionary *params = [[NSMutableDictionary alloc] init];
for (NSString *pair in pairs) {
NSArray *kv = [pair componentsSeparatedByString:#"="];
NSString *val =
[[kv objectAtIndex:1]
stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
[params setObject:val forKey:[kv objectAtIndex:0]];
}
return params;
}
- (void)sendRequest {
NSError *error;
NSData *jsonData = [NSJSONSerialization
dataWithJSONObject:#{
#"social_karma": #"5",
#"badge_of_awesomeness": #"1"}
options:0
error:&error];
if (!jsonData) {
NSLog(#"JSON error: %#", error);
return;
}
NSString *giftStr = [[NSString alloc]
initWithData:jsonData
encoding:NSUTF8StringEncoding];
NSMutableDictionary* params = [NSMutableDictionary dictionaryWithObjectsAndKeys:
giftStr, #"data",
nil];
// Display the requests dialog
[FBWebDialogs
presentRequestsDialogModallyWithSession:nil
message:#"Learn how to make your iOS apps social."
title:nil
parameters:params
handler:^(FBWebDialogResult result, NSURL *resultURL, NSError *error) {
if (error) {
// Error launching the dialog or sending the request.
NSLog(#"Error sending request.");
} else {
if (result == FBWebDialogResultDialogNotCompleted) {
// User clicked the "x" icon
NSLog(#"User canceled request.");
} else {
// Handle the send request callback
NSDictionary *urlParams = [self parseURLParams:[resultURL query]];
if (![urlParams valueForKey:#"request"]) {
// User clicked the Cancel button
NSLog(#"User canceled request.");
} else {
// User clicked the Send button
NSString *requestID = [urlParams valueForKey:#"request"];
NSLog(#"Request ID: %#", requestID);
}
}
}
}];
}
- (void)sendRequestClicked {
// Filter and only show friends using iOS
[self requestFriendsUsingDevice:#"iOS"];
}
- (void)sendRequest:(NSArray *) targeted {
NSError *error;
NSData *jsonData = [NSJSONSerialization
dataWithJSONObject:#{
#"social_karma": #"5",
#"badge_of_awesomeness": #"1"}
options:0
error:&error];
if (!jsonData) {
NSLog(#"JSON error: %#", error);
return;
}
NSString *giftStr = [[NSString alloc]
initWithData:jsonData
encoding:NSUTF8StringEncoding];
NSMutableDictionary* params =
[NSMutableDictionary dictionaryWithObjectsAndKeys:giftStr, #"data",
nil];
// Filter and only show targeted friends
if (targeted != nil && [targeted count] > 0) {
NSString *selectIDsStr = [targeted componentsJoinedByString:#","];
[params setObject:selectIDsStr forKey:#"suggestions"];
}
// Display the requests dialog
[FBWebDialogs
presentRequestsDialogModallyWithSession:nil
message:#"Learn how to make your iOS apps social."
title:nil
parameters:params
handler:^(FBWebDialogResult result, NSURL *resultURL, NSError *error) {
if (error) {
// Error launching the dialog or sending request.
NSLog(#"Error sending request.");
} else {
if (result == FBWebDialogResultDialogNotCompleted) {
// User clicked the "x" icon
NSLog(#"User canceled request.");
} else {
// Handle the send request callback
NSDictionary *urlParams = [self parseURLParams:[resultURL query]];
if (![urlParams valueForKey:#"request"]) {
// User clicked the Cancel button
NSLog(#"User canceled request.");
} else {
// User clicked the Send button
NSString *requestID = [urlParams valueForKey:#"request"];
NSLog(#"Request ID: %#", requestID);
}
}
}
}];
}
- (void) requestFriendsUsingDevice:(NSString *)device {
NSMutableArray *deviceFilteredFriends = [[NSMutableArray alloc] init];
[FBRequestConnection startWithGraphPath:#"me/friends"
parameters:[NSDictionary
dictionaryWithObjectsAndKeys:
#"id,devices", #"fields",
nil]
HTTPMethod:nil
completionHandler:^(FBRequestConnection *connection,
id result,
NSError *error) {
if (!error) {
// Get the result
NSArray *resultData = [result objectForKey:#"data"];
// Check we have data
if ([resultData count] > 0) {
// Loop through the friends returned
for (NSDictionary *friendObject in resultData) {
// Check if devices info available
if ([friendObject objectForKey:#"devices"]) {
NSArray *deviceData = [friendObject
objectForKey:#"devices"];
// Loop through list of devices
for (NSDictionary *deviceObject in deviceData) {
// Check if there is a device match
if ([device isEqualToString:
[deviceObject objectForKey:#"os"]]) {
// If there is a match, add it to the list
[deviceFilteredFriends addObject:
[friendObject objectForKey:#"id"]];
break;
}
}
}
}
}
}
// Send request
[self sendRequest:deviceFilteredFriends];
}];
}
You can only get notifications on Facebook web application if your app has a Facebook Canvas app implemented.
The invitable_friends API is only available for games that have a
Facebook Canvas app implementation using version 2.0 of the Graph API.
Check here the full documentation
Canvas is a frame in which to put your app or game directly on
Facebook.com on desktops and laptops.
Details about Canvas
Note: In the documentation you will find "your game", they mean "your game or your app".
I want to code a singleton for facebook integration with iOS 6.
I use Social and Accounts Frameworks.
This my FacebookData.h :
#class FacebookData;
#protocol FacebookDataDelegate <NSObject>
#optional
- (void)FacebookDataDidLoadRequest:(NSDictionary *)result;
- (void)FacebookDataDidFailToLoadRequest:(NSError *)error;
#end
#interface FacebookData : NSObject{
NSString *facebookAppID;
ACAccountStore *facebookAccountStore;
ACAccountType *facebookAccountType;
ACAccount *facebookAccount;
BOOL readPermissionsGranted;
BOOL RequestPermissionsGranted;
}
#property (nonatomic) id delegate;
+ (FacebookData*)sharedFacebookData;
- (void)setAppID:(NSString *)appID;
- (NSString *)currentAppID;
- (void)requestPermissions:(NSArray*)Permissions andLoadRequest:(NSString*)theRequest;
- (void)loadRequest:(NSString*)theRequest;
#end
The most important methods of my FacebookData.m :
- (void)requestPermissions:(NSArray*)Permissions andLoadRequest:(NSString*)theRequest{
if(!readPermissionsGranted){
__block NSArray *facebookPermissions = #[#"read_stream", #"email"];
__block NSDictionary *facebookOptions = #{ ACFacebookAppIdKey : facebookAppID,
ACFacebookAudienceKey : ACFacebookAudienceFriends,
ACFacebookPermissionsKey : facebookPermissions};
[facebookAccountStore requestAccessToAccountsWithType:facebookAccountType options:facebookOptions completion:^(BOOL granted, NSError *error)
{
if (granted) {
readPermissionsGranted = YES;
[self requestPermissions:Permissions andLoadRequest:theRequest];
}
// If permission are not granted to read.
if (!granted)
{
NSLog(#"Read permission error: %#", [error localizedDescription]);
[self.delegate FacebookDataDidFailToLoadRequest:error];
readPermissionsGranted = NO;
if ([[error localizedDescription] isEqualToString:#"The operation couldn’t be completed. (com.apple.accounts error 6.)"])
{
[self performSelectorOnMainThread:#selector(showError) withObject:error waitUntilDone:NO];
}
}
}];
}else{
__block NSArray *facebookPermissions = [NSArray arrayWithArray:Permissions];
__block NSDictionary *facebookOptions = #{ ACFacebookAppIdKey : facebookAppID,
ACFacebookAudienceKey : ACFacebookAudienceFriends,
ACFacebookPermissionsKey : facebookPermissions};
[facebookAccountStore requestAccessToAccountsWithType:facebookAccountType options:facebookOptions completion:^(BOOL granted2, NSError *error)
{
if (granted2)
{
RequestPermissionsGranted = YES;
// Create the facebook account
facebookAccount = [[ACAccount alloc] initWithAccountType:facebookAccountType];
NSArray *arrayOfAccounts = [facebookAccountStore accountsWithAccountType:facebookAccountType];
facebookAccount = [arrayOfAccounts lastObject];
[self loadRequest:theRequest];
NSLog(#"Permission granted");
}
if (!granted2)
{
NSLog(#"Request permission error: %#", [error localizedDescription]);
[self.delegate FacebookDataDidFailToLoadRequest:error];
RequestPermissionsGranted = NO;
}
}];
}
}
- (void)loadRequest:(NSString*)theRequest{
__block NSDictionary *result= [[NSDictionary alloc]init];
// Create the URL to the end point
NSURL *theURL = [NSURL URLWithString:theRequest];
// Create the SLReqeust
SLRequest *slRequest = [SLRequest requestForServiceType:SLServiceTypeFacebook requestMethod:SLRequestMethodGET URL:theURL parameters:nil];
// Set the account
[slRequest setAccount:facebookAccount];
// Perform the request
[slRequest performRequestWithHandler:^(NSData *responseData, NSHTTPURLResponse *urlResponse, NSError *error) {
if (error)
{
// If there is an error we populate the error string with error
__block NSString *errorString = [NSString stringWithFormat:#"%#", [error localizedDescription]];
NSLog(#"Error: %#", errorString);
[self.delegate FacebookDataDidFailToLoadRequest:error];
} else
{
NSLog(#"HTTP Response: %i", [urlResponse statusCode]);
NSDictionary *jsonResponse = [NSJSONSerialization JSONObjectWithData:responseData options:0 error:nil];
result = jsonResponse;
[self.delegate FacebookDataDidLoadRequest:jsonResponse];
}
}];
}
I use this singleton like this :
FacebookData *data = [FacebookData sharedFacebookData];
data.delegate = self;
[data setAppID:APPIDKEY];
[data requestPermissions:#[#"friends_location"] andLoadRequest:#"https://graph.facebook.com/me/friends?fields=id,name,location"];
This request with this permissions fails whereas the same method with permissions :#[#"email"] and request: https://graph.facebook.com/me/friends works perfectly.
This is the error that I can see in the console :
error = {
code = 2500;
message = "An active access token must be used to query information about the current user.";
type = OAuthException;
};
I can't find where the bug is, I don't know how to use tokens with these frameworks.
Thanks for your help !
IMO your LoadRequest URL is not correct
andLoadRequest:#"https://graph.facebook.com/me/friends?fields=id,name,location"];
SLRequest gives an oauth error even though its real problem with the URL. SLRequest doesn't support "?fields=id,name,location" directly in URL. You need to pass them as parameter in SLRequest
See the example below:
NSString* queryString = NULL;
queryString = [NSString stringWithFormat:#"https://graph.facebook.com/me/friends", nil];
NSURL *friendsRequestURL = [NSURL URLWithString:queryString];
SLRequest *friendsRequest = [SLRequest requestForServiceType:SLServiceTypeFacebook
requestMethod:SLRequestMethodGET URL:friendsRequestURL
parameters:#{#"fields":#"id,name,location"}];
PS: I was facing the similar problem last night and cursing the facebook for given wrong error statement. But finally able to solve it at the end. :)
I am trying to build simple prototype where I post some text to my facebook account. I have read the ios 6 facebook integration documentation and came up with following code. Everything seems to work fine until I hit the last block where I create SLRequest object in method postTextToFacebook and try to execute performRequestWithHandler with handler block. Control never does inside the handler block. I am assuming that performRequestWithHandler call is not successful in this case. Any one have done with successfully? Here is code for your reference.
#import <Social/Social.h>
#import "ViewController.h"
#implementation ViewController
#synthesize facebookAccount;
#synthesize accountStore;
#synthesize textToPost;
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
-(IBAction) postToFacebook:(id)sender
{
self.statusLabel.text = #"Logging in ...";
if(self.accountStore == nil)
{
self.accountStore = [[ACAccountStore alloc] init];
}
ACAccountType *facebookAccountType = [self.accountStore enter code hereaccountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierFacebook];
NSMutableDictionary *myOptions = [NSMutableDictionary dictionaryWithObjectsAndKeys:
#"172197712918906", ACFacebookAppIdKey,
[NSArray arrayWithObjects:#"email", #"user_about_me", #"user_likes", nil], ACFacebookPermissionsKey, ACFacebookAudienceFriends, ACFacebookAudienceKey, nil];
[self.accountStore requestAccessToAccountsWithType:facebookAccountType options:myOptions completion:^(BOOL granted, NSError *error){
__block NSString *statusText;
if(granted)
{
NSArray *accounts = [self.accountStore accountsWithAccountType:facebookAccountType];
self.facebookAccount = [accounts lastObject];
[myOptions setObject:[NSArray arrayWithObjects:#"publish_stream", nil] forKey:ACFacebookPermissionsKey];
[self.accountStore requestAccessToAccountsWithType:facebookAccountType options:myOptions completion:^(BOOL granted, NSError *error) {
__block NSString *statusText1;
if(granted && error == nil)
{
NSArray *accounts = [self.accountStore accountsWithAccountType:facebookAccountType];
self.facebookAccount = [accounts lastObject];
[self postTextToFacebook];
statusText1 = #"Text Posted.";
}
else{
statusText1 = #"Publish Failed.";
}
dispatch_async(dispatch_get_main_queue(), ^{
self.statusLabel.text = statusText1;
});
}];
}
else{
statusText = #"Login Failed.";
NSLog(#"Error = %#",error);
}
}];
}
-(void) postTextToFacebook
{
NSDictionary *parameters = #{#"message":self.textToPost.text};
NSURL *feedURL = [NSURL URLWithString:#"https://graphs.facebook.com/me/feed"];
SLRequest *request = [SLRequest requestForServiceType:SLServiceTypeFacebook requestMethod:SLRequestMethodPOST URL:feedURL parameters:parameters];
request.account = self.facebookAccount;
[request performRequestWithHandler:^(NSData *responseData, NSHTTPURLResponse *urlResponse, NSError *error) {
NSLog(#"Facebook request received, status code %d", urlResponse.statusCode);
NSString *response = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
NSLog(#"Response data: %#", response);
//handle errors
if(error == nil)
{
dispatch_async(dispatch_get_main_queue(), ^{
self.statusLabel.text = #"text posted to facebook";
});
}
}];
}
#end
Your url should be
https://graph.facebook.com/me/feed
instead of
https://graphs.facebook.com/me/feed
I was having a same issue and got an NSURLErrorDomain -1003 error on it.
I'm using ShareKit and have verified that the user is logged in to Facebook. I want to get their Facebook user name. Here's what I tried:
SHKFacebook *facebook = [[SHKFacebook alloc] init];
[facebook getAuthValueForKey:#"username"];
The getAuthValueForKey: method isn't returning anything to me. How can I get their Facebook user name?
You can use Facebook Graph API for get username. Add method bellow to FBSession.m class of FBConnect package.
#import "JSON.h"
...........
static NSString *const kGraphAPIURL = #"https://graph.facebook.com/";
static NSString *const kFBGraphAPIUserName = #"name";
...........
// Get user name via Facebook GraphAPI.
- (NSString *)getUserNameByUID:(FBUID)aUID {
NSString *userName_ = nil;
NSURL *serviceUrl = [NSURL URLWithString:[NSString stringWithFormat:#"%#%qi", kGraphAPIURL, aUID]];
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
NSError *error = nil;
NSString *jsonString = [NSString stringWithContentsOfURL:serviceUrl encoding:NSUTF8StringEncoding error:&error];
if (error != nil) {
NSLog(#"######### error: %#", error);
}
if (jsonString) {
// Parse the JSON into an Object and
// serialize its object to NSDictionary
NSDictionary *resultDic = [jsonString JSONValue];
if (resultDic) {
userName_ = [resultDic valueForKey:kFBGraphAPIUserName];
}
}
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
return userName_;
}
I am having a problem passing an NSError object back. The first line of code to access the object (in this case, I inserted an NSLog) causes "EXC_BAD_ACCESS".
Is this because I am not explicitly creating an NSError object, but rather getting one from the NSURLRequest and passing it back? In this particular function (downloadFile:), some errors I want to retrieve from other functions, but I create an NSError on two other occasions in the function.
Any help is appreciated.
Here is the offending code:
-(void)someCode {
NSError *err = nil;
localPool = [[NSAutoreleasePool alloc] init];
if (!iap) {
iap = [[InAppPurchaseController alloc] init];
}
if (![self.iap downloadFile:#"XXXXX.plist" withRemoteDirectory:nil withLocalDelete:YES withContentType:#"text/xml" Error:&err] ) {
//"EXC_BAD_ACCESS" on calling NSLog on the next line?
NSLog(#"Error downloading Plist: %#", [err localizedDescription]);
[self performSelectorOnMainThread:#selector(fetchPlistFailed:) withObject:err waitUntilDone:NO];
[localPool drain], localPool = nil;
return NO;
}
//Removed the remainder of the code for clarity.
[localPool drain], localPool = nil;
return YES;
}
-(BOOL)downloadFile:(NSString *)fileName
withRemoteDirectory:(NSString *)remoteDirectory
withLocalDelete:(BOOL)withLocalDelete
withContentType:(NSString *)contentTypeCheckString
Error:(NSError **)error {
UIApplication *app = [UIApplication sharedApplication];
app.networkActivityIndicatorVisible = YES;
NSError *localError = nil;
NSAutoreleasePool *localPool = [[NSAutoreleasePool alloc] init];
NSString *urlString = [NSString stringWithFormat:#"http://XXXXX/%#", fileName];
NSLog(#"Downloading file: %#", urlString);
NSURL *url = [NSURL URLWithString:urlString];
NSURLRequest *req = [[NSURLRequest alloc] initWithURL:url];
NSHTTPURLResponse *response = nil;
NSData *responseData = [NSURLConnection sendSynchronousRequest:req returningResponse:&response error:&localError];
[req release];
if (response == nil || localError) {
NSLog(#"Error retrieving file:%#", [localError localizedDescription]);
if (error != NULL) {
*error = localError;
//THIS NSLog call works just fine.
NSLog(#"Error copied is:%#", [*error localizedDescription]);
}
[localPool drain], localPool = nil;
app.networkActivityIndicatorVisible = NO;
return NO;
}
//Rest of function omitted for simplicity.
}
I guess your NSError object is autoreleased and put on your localPool. You drained that localPool, thus destroying the NSError.
Do you really need localPool in every method? If not, just remove the localPools.
Also, it looks like you forgot to drain the localPool in someCode. Hopefully you just didn't copy it...
-(void)someCode {
NSError *err = nil;
localPool = [[NSAutoreleasePool alloc] init];
if (!iap) {
iap = [[InAppPurchaseController alloc] init];
}
if (![self.iap downloadFile:#"XXXXX.plist" withRemoteDirectory:nil withLocalDelete:YES withContentType:#"text/xml" Error:&err] ) {
....
[localPool drain], localPool = nil;
return NO;
}
[localPool drain], localPool = nil; // missing
}