facebook ios api - How to send a synchronous graph request - ios

In ios 6 using facebook ios sdk 3.5 how can I send a graph request so it's synchornious? Or atleast how can I synchronize the response method?
I'm using the following method:
+(void)hasUserGrantedPermissions:(NSArray*)permissions
andBlock:(void (^)(bool))repeatBlock{
[[FBRequest requestForGraphPath:#"/me/permissions"]
startWithCompletionHandler:^(FBRequestConnection *connection, FBGraphObject* result, NSError *error) {
if([[result valueForKey:#"data"] count] <1){
repeatBlock(false);
}
FBGraphObject* grantedPerms = [[result valueForKey:#"data"] objectAtIndex:0];
for(NSString* requestedPerm in permissions){
if (! [grantedPerms valueForKey:requestedPerm]){
repeatBlock(true);
}
}
}];
}
How can I alter the method or request in such a way that it becomes synchronous?
Thank you

Related

How to get Friends list from Facebook iOS sdk

I am using iOS sdk v3.18.1, I want to get all my Facebook friends.I can get the friends count but, data is nil.
Here is my code
[FBRequestConnection startWithGraphPath:#"me/friends" parameters:nil HTTPMethod:#"GET" completionHandler:^(FBRequestConnection *connection, id result, NSError *error) {
NSLog(#"result %#",result);
}];
Out put
{
data = (
);
summary = {
"total_count" = 840;
};
}
https://developers.facebook.com/docs/apps/changelog
Since v2.0 you cannot get the full friend list anymore, you only get the friends who authorized your App too.
See my answer in this thread too: how to get a list of all user friends (not only who use the app)?
// declare an array in header file which will hold the list of all friends -
NSMutableArray * m_allFriends;
// alloc and initialize the array only once
m_allFriends = [[NSMutableArray alloc] init];
With FB SDK 3.0 and API Version above 2.0 you need to call below function (graph api with me/friends)to get list of FB Friends which uses the same app.
// get friends which use the app
-(void) getMineFriends
{
[FBRequestConnection startWithGraphPath:#"me/friends"
parameters:nil
HTTPMethod:#"GET"
completionHandler:^(
FBRequestConnection *connection,
id result,
NSError *error
) {
NSLog(#"me/friends result=%#",result);
NSLog(#"me/friends error = %#", error.description);
NSArray *friendList = [result objectForKey:#"data"];
[m_allFriends addObjectsFromArray: friendList];
}];
}
Note : 1) The default limit for the number of friends returned by above query is 25. 2)If the next link comes in result, that means there are some more friends which you will be fetching in next query and so on. 3)Alternatively you can change the limit (reduce the limit, exceed the limit from 25) and pass that in param.
////////////////////////////////////////////////////////////////////////
For non app friends -
// m_invitableFriends - global array which will hold the list of invitable friends
Also to get non app friends you need to use (/me/invitable_friends) as below -
- (void) getAllInvitableFriends
{
NSMutableArray *tempFriendsList = [[NSMutableArray alloc] init];
NSDictionary *limitParam = [NSDictionary dictionaryWithObjectsAndKeys:#"100", #"limit", nil];
[self getAllInvitableFriendsFromFB:limitParam addInList:tempFriendsList];
}
- (void) getAllInvitableFriendsFromFB:(NSDictionary*)parameters
addInList:(NSMutableArray *)tempFriendsList
{
[FBRequestConnection startWithGraphPath:#"/me/invitable_friends"
parameters:parameters
HTTPMethod:#"GET"
completionHandler:^(
FBRequestConnection *connection,
id result,
NSError *error
) {
NSLog(#"error=%#",error);
NSLog(#"result=%#",result);
NSArray *friendArray = [result objectForKey:#"data"];
[tempFriendsList addObjectsFromArray:friendArray];
NSDictionary *paging = [result objectForKey:#"paging"];
NSString *next = nil;
next = [paging objectForKey:#"next"];
if(next != nil)
{
NSDictionary *cursor = [paging objectForKey:#"cursors"];
NSString *after = [cursor objectForKey:#"after"];
//NSString *before = [cursor objectForKey:#"before"];
NSDictionary *limitParam = [NSDictionary dictionaryWithObjectsAndKeys:
#"100", #"limit", after, #"after"
, nil
];
[self getAllInvitableFriendsFromFB:limitParam addInList:tempFriendsList];
}
else
{
[self replaceGlobalListWithRecentData:tempFriendsList];
}
}];
}
- (void) replaceGlobalListWithRecentData:(NSMutableArray *)tempFriendsList
{
// replace global from received list
[m_invitableFriends removeAllObjects];
[m_invitableFriends addObjectsFromArray:tempFriendsList];
//NSLog(#"friendsList = %d", [m_invitableFriends count]);
[tempFriendsList release];
}
For Inviting non app friend -
you will get invite tokens with the list of friends returned by me/invitable_friends graph api. You can use these invite tokens with FBWebDialogs to send invite to friends as below
- (void) openFacebookFeedDialogForFriend:(NSString *)userInviteTokens {
NSMutableDictionary *params = [NSMutableDictionary dictionaryWithObjectsAndKeys:
userInviteTokens, #"to",
nil, #"object_id",
#"send", #"action_type",
actionLinksStr, #"actions",
nil];
[FBWebDialogs
presentRequestsDialogModallyWithSession:nil
message:#"Hi friend, I am playing game. Come and play this awesome game with me."
title:nil
parameters:params
handler:^(
FBWebDialogResult result,
NSURL *url,
NSError *error)
{
if (error) {
// Error launching the dialog or sending the request.
NSLog(#"Error sending request : %#", error.description);
}
else
{
if (result == FBWebDialogResultDialogNotCompleted)
{
// User clicked the "x" icon
NSLog(#"User canceled request.");
NSLog(#"Friend post dialog not complete, error: %#", error.description);
}
else
{
NSDictionary *resultParams = [g_mainApp->m_appDelegate parseURLParams:[url query]];
if (![resultParams valueForKey:#"request"])
{
// User clicked the Cancel button
NSLog(#"User canceled request.");
}
else
{
NSString *requestID = [resultParams valueForKey:#"request"];
// here you will get the fb id of the friend you invited,
// you can use this id to reward the sender when receiver accepts the request
NSLog(#"Feed post ID: %#", requestID);
NSLog(#"Friend post dialog complete: %#", url);
}
}
}
}];
}
Since, V2.0 of the Graph API, You will only be able to get the list of the friends who are connected with your app. In v2.0 of the Graph API, calling /me/friends returns the person's friends who use the app. Yes it is possible to get the count but accessing the friend list is not possible.
All the release of Facebook SDK after the month of April denies this functionality of getting the whole list of friends.
REFER : SO QUESTION:Facebook graph API returns empty .... FACEBOOK USER GUIDE
This has been confirmed by FACEBOOK.

Facebook Notification API

Has anyone implemented facebook Notification API in iOS??
I have used it in android its working but for iOS its giving OAuthException.
Its in Beta could be a bug in Notification API??
I am using facebook SDK for iOS v 3.18.
Code
NSString *notification_Id = [NSString stringWithFormat:#"/%#/notifications", friend];
NSString *app_token = #"APP_ID|APP_SECRET";
NSDictionary *dict_notification = #{#"href": url,
#"template": #"You have been invited to Choozr Poll by",
#"access_token" : app_token};
/* make the API call */
[FBRequestConnection startWithGraphPath:notification_Id
parameters:dict_notification
HTTPMethod:#"POST"
completionHandler:^(
FBRequestConnection *connection,
id result,
NSError *error
) {
/* handle the result */
if (error) {
NSLog(#"error: %#", error);
}
NSLog(#"%#",result);
}];
Response from facebook
{ > error = { > code = 15; > message = "(#15) This method must be called with an app access_token."; > type = OAuthException; > }
You need to implement the Facebook notification API on your server side code, not the client.

How to get the list of Facebook friends who have not installed the app?

I'm developing a social networking app. I've integrated Facebook SDK 3.14 in my iOS App. Now, I want to get the list of all my Facebook friends so I can invite those friends who are not using the app and send friend requests to those friends who have already installed the app.
I can get the list of friends who already use my apps using "/me/friends".
[FBRequestConnection startWithGraphPath:#"/me/friends"
parameters:nil
HTTPMethod:#"GET"
completionHandler:^(FBRequestConnection *connection, id result, NSError *error) {
NSLog(#"All == %#", result);
}];
It gives friends' Facebook ids (ex. id = 654330727444458) in response so that I can send friend requests to them.
To get the list of all Facebook friends who have not downloaded the app and if I want to invite those, I need to get all friends using "me/taggable_friends" (Please correct me if I'm wrong).
[FBRequestConnection startWithGraphPath:#"/me/taggable_friends"
parameters:nil
HTTPMethod:#"GET"
completionHandler:^(FBRequestConnection *connection, id result, NSError *error) {
NSlog("%#", result);
}];
In the taggable_friends response I'm getting friend's id as id = "AaLYBzZzHdzCmlytqyMAjO0OLDZIOs74Urn93ikeRmmTB3vX_Xl81OYUt4XnoWG0BDLuX67umVkheVdDjzyvm0fcqMqu84GgM9JnNHc-1B63eg" which is friend's token id and it's not unique. I couldn't use it instead, have to use Facebook Id of friend to invite them. Unfortunately, I couldn't get it in the taggable friend response.
This is only possible on the Facebook API v1 which stops working next April or so. Even now only existing Facebook apps will allow you to use V1 so if you don't have an old enough app you are not able to do this. In V2 you can only get friends who have also signed in to the same app but the user id's are unique to the application to prevent exactly this. I guess Facebook reasons that by doing this is stops people spamming their friends via apps so much :/
As #joelrb says you can create a canvas app for a game and use invitable_friends but FB will vet your "game" so you can't really cheat.
See https://developers.facebook.com/docs/apps/changelog/ for more info.
TLDR; post to wall is all you can do. Tough. Sorry.
Use the installed field of a user. Like so:
NSMutableArray *notYetUsers = [NSMutableArray array];
FBRequest *fbRequest = [FBRequest requestForGraphPath:#"me/friends?fields=installed"];
[fbRequest startWithCompletionHandler:^(FBRequestConnection *connection, id result, NSError *error) {
NSAssert(!error, error.localizedDescription);
NSArray *friends = [(NSDictionary *)result objectForKey:#"data"];
for (NSDictionary<FBGraphUser> *user in friends) {
if ([user[#"installed"] isEqual:#(NO)])
[notYetUsers addObject:user];
}
}];
notYetUsers would contain all friends who have not installed the app yet.
- (void)getFBFriendsWithCompletion:(void (^)(NSError *, id))callback
{
NSString *query = #"select uid, name, is_app_user "
#"from user "
#"where uid in (select uid2 from friend where uid1=me() )";
NSDictionary *queryParam =
[NSDictionary dictionaryWithObjectsAndKeys:query, #"q", nil];
// Make the API request that uses FQL
[FBRequestConnection startWithGraphPath:#"/fql"
parameters:queryParam
HTTPMethod:#"GET"
completionHandler:^(FBRequestConnection *connection,
id result,
NSError *error) {
if (callback)
callback(error, result);
}];
}
- (void)foo
{
[self getFBFriendsWithCompletion:^(NSError *error, id result) {
if (!error)
{
NSMutableArray *friendsUsingApp = [NSMutableArray array];
NSMutableArray *friendsNotUsingApp = [NSMutableArray array];
for (NSDictionary *data in result[#"data"]) {
if ([data[#"is_app_user"] boolValue] == NO) {
[friendsNotUsingApp addObject:data];
} else {
[friendsUsingApp addObject:data];
}
}
// Do something with friendsUsingApp and friendsNotUsingApp
}
}];
}
taggable_friends refers to a list of friends that can be tagged or mentioned in stories published to Facebook. The result you got is just a tagging token which can only be used in order to tag a friend, and for no other purpose.
Although this refers to a game app, it's easier I think if you use the invitable_friends API. But it requires a Facebook Canvas app implementation. You may just provide a notice in your Canvas for users to just use the mobile app instead, etc.
This is the tutorial that uses invitable_friends API: https://developers.facebook.com/docs/games/mobile/ios-tutorial/
And, the invitable_friends API details:
https://developers.facebook.com/docs/games/invitable-friends/v2.0
You can try this to get the IDs of Friends app users:
NSMutableArray *appFriendUsers = [[NSMutableArray alloc] init];
[[FBRequest requestForGraphPath:#"me/friends?fields=installed"]
startWithCompletionHandler:
^(FBRequestConnection *connection,
NSDictionary *result,
NSError *error) {
//if result, no errors
if (!error && result)
{
//result dictionary in key "data"
NSArray *allFriendsList = [result objectForKey:#"data"];
if ([allFriendsList count] > 0)
{
// Loop
for (NSDictionary *aFriendData in allFriendsList) {
// Friend installed app?
if ([aFriendData objectForKey:#"installed"]) {
[appFriendUsers addObject: [aFriendData objectForKey:#"id"]];
break;
}
}
}
}
}];

Facebook iOS SDK 3.6 startWithGraphPath completion block not executed

I've integrated with Facebook so that I can, among other things, post statuses to my feed. I based some of my code off of the publish to feed developer tutorial. When running the following Graph API request from my iOS application the completion block of the request is never called and no error appears in the XCode debug log.
[FBRequestConnection
startWithGraphPath:#"me/feed"
parameters:params
HTTPMethod:#"POST"
completionHandler:^(FBRequestConnection *connection, id result, NSError *error) {
if (error) {
DLog(#"error: domain = %#, code = %d", error.domain, error.code);
} else {
DLog(#"Posted action, id: %#", result[#"id"]);
}
}];
I have two convenience functions that perform checks against the current activeSession before executing this request. They look like this:
+ (BOOL)facebookSessionIsOpen {
return (FBSession.activeSession.isOpen);
}
+ (BOOL)facebookSessionHasPublishPermissions {
if ([FBSession.activeSession.permissions indexOfObject:#"publish_actions"] == NSNotFound ||
[FBSession.activeSession.permissions indexOfObject:#"publish_stream"] == NSNotFound ||
[FBSession.activeSession.permissions indexOfObject:#"manage_friendlists"] == NSNotFound) {
return NO;
} else {
return YES;
}
}
Both of these functions return YES indicating an active session with the necessary publishing permission. What's more confusing is that I can pull the user's profile without issue after performing the same checks successfully (granted publishing permissions are not required to pull the profile) using the following code:
[FBRequestConnection
startWithGraphPath:#"me"
parameters:[NSDictionary dictionaryWithObject:#"picture,id,birthday,email,location,hometown" forKey:#"fields"]
HTTPMethod:#"GET"
completionHandler:^(FBRequestConnection *connection, id result, NSError *error) {
NSDictionary* resultDict = (NSDictionary*)result;
NSString* emailAddress = resultDict[#"email"];
NSString* location = resultDict[#"location"][#"name"];
NSString* birthday = resultDict[#"birthday"];
NSString* homeTown = resultDict[#"hometown"][#"name"];
...
}];
Any suggestions on how to debug this issue?
Turns out the issue was a threading one. The Facebook iOS SDK doesn't seem to like to execute a FBRequest on a different thread from the one that you called openActiveSessionWithReadPermissions on and promptly deadlocks. It turns out I was running the postStatus request in a separate thread like so:
dispatch_queue_t some_queue = dispatch_queue_create("some.queue.name", NULL);
dispatch_async(some_queue, ^{
[FacebookHelper postStatusToFacebookUserWall:newStatus withImage:imageData];
}];
Make sure your openActiveSessionWithReadPermissions and any FBRequest permutations all happen on the same thread, or you'll likely run into these silent failures.

Posting image with caption with Facebook IOS SDK 3.1 and Graph API

I'm new to facebook SDK.
Last time I used facebook IOS SDK 3.0 and posting image through graph API. It is working but now it's not. I upgraded to 3.1 but still, it always return HTTP ERROR 200. Is there anyone can help me?
this is the code
- (void) facebookPostPhoto:(UIImage *)photo withMessage:(NSString *)msg withOkAction:(SEL)okAction andNGAction:(SEL)ngAction withTarget:(id)target {
ok = okAction;
ng = ngAction;
curView = target;
NSMutableDictionary *params;
params = [NSMutableDictionary dictionaryWithObjectsAndKeys:
UIImageJPEGRepresentation(photo, 90), #"source",
msg, #"message",
nil];
if ([FBSession.activeSession.permissions indexOfObject:FacebookPermission_3] == NSNotFound) {
NSLog(#"permission not found");
// No permissions found in session, ask for it
[FBSession.activeSession reauthorizeWithPublishPermissions:[NSArray arrayWithObjects:FacebookPermission_1, FacebookPermission_3, nil] defaultAudience:FBSessionDefaultAudienceFriends completionHandler:^(FBSession *session, NSError *error)
{
// If permissions granted, publish the story
if (!error) [self initPostFacebookWithParams:params];
}];
} else {
[self initPostFacebookWithParams:params];
} }
- (void)initPostFacebookWithParams:(NSMutableDictionary *)params {
[FBRequestConnection startWithGraphPath:#"me/photos" parameters:params HTTPMethod:#"POST" completionHandler:^(FBRequestConnection *connection, id result, NSError *error) {
NSLog(#"ERROR : %#", error.localizedDescription);
if (!error) {
NSLog(#"Facebook Post Success..");
if (ok && curView) {
[curView performSelector:ok];
}
} else {
NSLog(#"Facebook Post Failed..");
if (ng && curView) {
[curView performSelector:ng withObject:error];
}
}
}]; }
I appreciate your fast response and help! Thank You!!
I think it's either facebook upload's server is down or there is a new policy about image size. When I down sized the image to 320x320 it returns no error, sometimes error too by the way.
So for those who see this question, try to resize your image to smaller size.

Resources