Facebook Graph API v2.0 + – / me / friends返回空,或者只有朋友也使用我的应用程序

我正在尝试使用Graph API v2.0获取我的朋友姓名和ID,但是数据返回为空:

{ "data": [ ] } 

当我使用v1.0时,一切正常,请求如下:

 FBRequest* friendsRequest = [FBRequest requestForMyFriends]; [friendsRequest startWithCompletionHandler: ^(FBRequestConnection *connection, NSDictionary* result, NSError *error) { NSArray* friends = [result objectForKey:@"data"]; NSLog(@"Found: %i friends", friends.count); for (NSDictionary<FBGraphUser>* friend in friends) { NSLog(@"I have a friend named %@ with id %@", friend.name, friend.id); } }]; 

但现在我不能交到朋友

在Graph API的v2.0中,调用/me/friends返回也使用该应用程序的人的朋友。

另外,在v2.0中,您必须向每个用户请求user_friends权限。 每个login中默认不再包含user_friends 。 每个用户必须授予user_friends权限才能出现在/me/friends的回复中。 有关更多详细信息,请参阅Facebook升级指南 ,或查看下面的摘要。

如果您想访问非应用程序使用的朋友列表,有两种select:

  1. 如果您想让自己的人在使用您的应用发布到Facebook的故事中标记好友 ,则可以使用/me/taggable_friends API。 使用此端点需要Facebook进行审查,并且只能用于您呈现朋友列表的情况,以便让用户在post中标记它们。

  2. 如果您的应用程序是游戏而您的游戏支持Facebook Canvas ,则可以使用/me/invitable_friends端点来呈现自定义邀请对话框 ,然后将此API返回的令牌传递到标准的请求对话框。

在其他情况下,应用程序不再能够检索用户朋友的完整列表(只有那些使用user_friends权限特别授权您的应用程序的user_friends )。 这已被Facebook确认为“按devise”。

对于需要允许朋友邀请朋友使用应用程序的应用程序,您仍然可以使用Web上的发送对话框或iOS和Android 上的新消息对话框 。

更新:Facebook已经发布了这些变化的常见问题: https : //developers.facebook.com/docs/apps/faq ,其中解释了为了邀请朋友等开发人员可用的所有选项。

虽然西蒙·克罗斯的答案被接受和正确,但我认为我会用一个例子(android)来强化一下需要做的事情。 我会尽可能保持一般,专注于这个问题。 就我个人而言,我最终将数据存储在数据库中,所以加载过程很顺利,但是需要一个CursorAdapter和ContentProvider,这里有点超出范围。

我来到这里,然后想,现在呢?!

问题

就像user3594351 ,我注意到朋友数据是空白的。 我通过使用FriendPickerFragment发现了这一点。 三个月前的工作,已经不起作用了。 即使Facebook的例子打破了。 所以我的问题是“如何手动创buildFriendPickerFragment?

什么没有奏效

西蒙·克罗斯Simon Cross )的选项1不够强大,无法邀请朋友join该应用。 西蒙·克罗斯还推荐了“请求”对话框,但一次只允许5个请求。 在任何给定的Facebooklogin会话期间,请求对话框也显示相同的朋友。 没有用。

什么工作(摘要)

选项#2有一些辛苦的工作。 你必须确保你履行Facebook的新规则:1)你是一个游戏2)你有一个canvas应用程序(networking存在)3)你的应用程序是在Facebook注册。 所有在Facebook开发者网站上完成设置。

为了在我的应用程序中手动模拟朋友select器,我做了以下操作:

  1. 创build一个显示两个片段的选项卡活动。 每个片段显示一个列表。 一个可用朋友(/我/朋友)的片段,另一个可用朋友(/我/ invitable_friends)。 使用相同的片段代码来呈现两个选项卡。
  2. 创build一个将从Facebook获取好友数据的AsyncTask。 一旦这些数据被加载,就把它抛到适配器上,这个适配器会把值显示到屏幕上。

细节

asynchronous任务

 private class DownloadFacebookFriendsTask extends AsyncTask<FacebookFriend.Type, Boolean, Boolean> { private final String TAG = DownloadFacebookFriendsTask.class.getSimpleName(); GraphObject graphObject; ArrayList<FacebookFriend> myList = new ArrayList<FacebookFriend>(); @Override protected Boolean doInBackground(FacebookFriend.Type... pickType) { // //Determine Type // String facebookRequest; if (pickType[0] == FacebookFriend.Type.AVAILABLE) { facebookRequest = "/me/friends"; } else { facebookRequest = "/me/invitable_friends"; } // //Launch Facebook request and WAIT. // new Request( Session.getActiveSession(), facebookRequest, null, HttpMethod.GET, new Request.Callback() { public void onCompleted(Response response) { FacebookRequestError error = response.getError(); if (error != null && response != null) { Log.e(TAG, error.toString()); } else { graphObject = response.getGraphObject(); } } } ).executeAndWait(); // //Process Facebook response // // if (graphObject == null) { return false; } int numberOfRecords = 0; JSONArray dataArray = (JSONArray) graphObject.getProperty("data"); if (dataArray.length() > 0) { // Ensure the user has at least one friend ... for (int i = 0; i < dataArray.length(); i++) { JSONObject jsonObject = dataArray.optJSONObject(i); FacebookFriend facebookFriend = new FacebookFriend(jsonObject, pickType[0]); if (facebookFriend.isValid()) { numberOfRecords++; myList.add(facebookFriend); } } } //make sure there are records to process if (numberOfRecords > 0){ return true; } else { return false; } } @Override protected void onProgressUpdate(Boolean... booleans) { //no need to update this, wait until the whole thread finishes. } @Override protected void onPostExecute(Boolean result) { if (result) { /* User the array "myList" to create the adapter which will control showing items in the list. */ } else { Log.i(TAG, "Facebook Thread unable to Get/Parse friend data. Type = " + pickType); } } } 

我创build的FacebookFriend类

 public class FacebookFriend { String facebookId; String name; String pictureUrl; boolean invitable; boolean available; boolean isValid; public enum Type {AVAILABLE, INVITABLE}; public FacebookFriend(JSONObject jsonObject, Type type) { // //Parse the Facebook Data from the JSON object. // try { if (type == Type.INVITABLE) { //parse /me/invitable_friend this.facebookId = jsonObject.getString("id"); this.name = jsonObject.getString("name"); //Handle the picture data. JSONObject pictureJsonObject = jsonObject.getJSONObject("picture").getJSONObject("data"); boolean isSilhouette = pictureJsonObject.getBoolean("is_silhouette"); if (!isSilhouette) { this.pictureUrl = pictureJsonObject.getString("url"); } else { this.pictureUrl = ""; } this.invitable = true; } else { //parse /me/friends this.facebookId = jsonObject.getString("id"); this.name = jsonObject.getString("name"); this.available = true; this.pictureUrl = ""; } isValid = true; } catch (JSONException e) { Log.w("#", "Warnings - unable to process FB JSON: " + e.getLocalizedMessage()); } } } 

Facebook现在已经修改了他们的政策。 如果您的应用程序没有Canvas实现,并且您的应用程序不是游戏,则无法获取整个好友列表。 当然,也有taggable_friends,但那只是标签。

您将能够拉取仅授权应用程序的朋友的名单。

使用Graph API 1.0的应用程序将一直工作到2015年4月30日,之后将被弃用。

请参阅下面的链接,以获得更多的细节

https://developers.facebook.com/docs/graph-api/reference/v2.2/user/friends

https://developers.facebook.com/docs/apps/faq#invite_to_app

希望这可以帮助

正如西蒙所说,这是不可能在新的Facebook API。 纯技术上说,你可以通过浏览器自动化来完成。

  • 这是违反Facebook的政策,所以根据你居住的国家这可能是不合法的
  • 你将不得不使用你的凭证/询问用户的凭据,并可能存储他们(即使对称encryption存储密码不是一个好主意)
  • 当facebook更改api时,还必须更新浏览器自动化代码(如果您不能强制更新应用程序,则应该将浏览器自动化部分作为web服务)
  • 这是绕过OAuth的概念
  • 另一方面我的感觉是我拥有我的数据,包括我的朋友列表和FB不应该限制我通过API访问

使用WatiN的示例实现

 class FacebookUser { public string Name { get; set; } public long Id { get; set; } } public IList<FacebookUser> GetFacebookFriends(string email, string password, int? maxTimeoutInMilliseconds) { var users = new List<FacebookUser>(); Settings.Instance.MakeNewIeInstanceVisible = false; using (var browser = new IE("https://www.facebook.com")) { try { browser.TextField(Find.ByName("email")).Value = email; browser.TextField(Find.ByName("pass")).Value = password; browser.Form(Find.ById("login_form")).Submit(); browser.WaitForComplete(); } catch (ElementNotFoundException) { // we're already logged in } browser.GoTo("https://www.facebook.com/friends"); var watch = new Stopwatch(); watch.Start(); Link previousLastLink = null; while (maxTimeoutInMilliseconds.HasValue && watch.Elapsed.TotalMilliseconds < maxTimeoutInMilliseconds.Value) { var lastLink = browser.Links.Where(l => l.GetAttributeValue("data-hovercard") != null && l.GetAttributeValue("data-hovercard").Contains("user.php") && l.Text != null ).LastOrDefault(); if (lastLink == null || previousLastLink == lastLink) { break; } var ieElement = lastLink.NativeElement as IEElement; if (ieElement != null) { var htmlElement = ieElement.AsHtmlElement; htmlElement.scrollIntoView(); browser.WaitForComplete(); } previousLastLink = lastLink; } var links = browser.Links.Where(l => l.GetAttributeValue("data-hovercard") != null && l.GetAttributeValue("data-hovercard").Contains("user.php") && l.Text != null ).ToList(); var idRegex = new Regex("id=(?<id>([0-9]+))"); foreach (var link in links) { string hovercard = link.GetAttributeValue("data-hovercard"); var match = idRegex.Match(hovercard); long id = 0; if (match.Success) { id = long.Parse(match.Groups["id"].Value); } users.Add(new FacebookUser { Name = link.Text, Id = id }); } } return users; } 

实现这种方法的原型(使用C#/ Watin)见https://github.com/svejdo1/ShadowApi它也允许dynamic更新Facebook连接器,检索您的联系人列表。;

尝试/我/ taggable_friends?限制= 5000使用您的JavaScript代码

要么

尝试graphicsAPI

https://graph.facebook.com/v2.3/user_id_here/taggable_friends?access_token=

玩的开心

在FBSDKGraphAPI v2.0或更高版本中,您必须在FBlogin时向每个用户请求user_friends权限。由于每个login名中不再包含user_friends,因此我们必须添加该用户。 每个用户必须授予user_friends权限才能出现在/ me / friends的回复中

  let fbLoginManager : FBSDKLoginManager = FBSDKLoginManager() fbLoginManager.loginBehavior = FBSDKLoginBehavior.web fbLoginManager.logIn(withReadPermissions: ["email","user_friends","public_profile"], from: self) { (result, error) in if (error == nil){ let fbloginresult : FBSDKLoginManagerLoginResult = result! if fbloginresult.grantedPermissions != nil { if(fbloginresult.grantedPermissions.contains("email")) { // Do the stuff }else { } }else { } } } 

所以在FBlogin的时候,它会提示包含所有权限的屏幕 在这里输入图像描述

如果用户按继续button,权限将被设置。 当您使用FBGraphAPI访问好友列表时,将会列出如上所述login到应用程序的朋友

  if((FBSDKAccessToken.current()) != nil){ FBSDKGraphRequest(graphPath: "/me/friends", parameters: ["fields" : "id,name"]).start(completionHandler: { (connection, result, error) -> Void in if (error == nil){ print(result!) } }) } 

输出将包含在通过Facebooklogin到应用程序时授予user_friends权限的用户

 { data = ( { id = xxxxxxxxxx; name = "xxxxxxxx"; } ); paging = { cursors = { after = xxxxxx; before = xxxxxxx; }; }; summary = { "total_count" = 8; }; }