首页 文章

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

提问于
浏览
358

我想用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);
    }
}];

但现在我不能得到朋友!

6 回答

  • 2

    使用您的javascript代码尝试/ me / taggable_friends?limit = 5000

    要么

    试试图API

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

    玩得开心

  • 2

    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

    希望这可以帮助

  • -1

    虽然西蒙克罗斯的答案是被接受和正确的,但我想我会用一个例子(android)来加强它需要做些什么 . 我会尽可能保持一般,并专注于问题 . 就个人而言,我最终将数据存储在数据库中,因此加载非常顺利,但这需要一个CursorAdapter和ContentProvider,这在这里有点超出范围 .

    我自己来到这里,然后想,现在是什么?!

    The Issue

    就像user3594351一样,我注意到朋友数据是空白的 . 我通过使用FriendPickerFragment找到了这个 . 三个月前有效的,不再有效 . 甚至facebook 's examples broke. So my issue was '如何手动创建FriendPickerFragment?

    What Did Not Work

    Simon Cross的选项#1不足以邀请朋友加入应用程序 . Simon Cross还推荐了Requests Dialog,但这样一次只允许5个请求 . 在任何给定的Facebook登录会话期间,请求对话框也显示了相同的朋友 . 没有用 .

    What Worked (Summary)

    选项#2有一些艰苦的工作 . 你必须确保你符合Facebook的新规则:1 . )你是一个游戏2.)你有一个Canvas应用程序(Web Presence)3 . )你的应用程序是在Facebook注册的 . 所有这些都是在Facebook开发者网站上完成的 .

    要在我的应用程序中手动模拟朋友选择器,我执行了以下操作:

    • 创建一个显示两个片段的选项卡活动 . 每个片段都显示一个列表 . 一个片段为可用的朋友(/我/朋友)和另一个片段为可邀请的朋友(/ me / invitable_friends) . 使用相同的片段代码来呈现两个选项卡 .

    • 创建一个AsyncTask,它将从Facebook获取好友数据 . 加载数据后,将其丢给适配器,适配器将值呈现给屏幕 .

    Details

    AsynchTask

    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);
                }
            }
        }
    

    我创建的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());
            }
        }
    }
    
  • 12

    正如Simon提到的,这在新的facebook API中是不可能的 . Pure technically speaking 您可以通过浏览器自动化来完成 .

    • 这违反了Facebook政策,因此根据您居住的国家/地区而言,这可能不合法

    • 你必须使用你的凭证/要求用户提供凭证并可能存储它们(存储密码甚至是对称加密的并不是一个好主意)

    • 当facebook改变他们的api时,你强制更新你的应用程序,你应该把浏览器自动化片作为webservice)

    • 这绕过了OAuth概念
      另一方面,

    • 我的感觉是我限制我通过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它还允许动态更新正在检索联系人列表的facebook连接器 .

  • 17

    在FBSDKGraphAPI v2.0或更高版本中,您必须在FB登录时请求每个用户的user_friends权限 . 因为默认情况下每次登录都不再包含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 {
                }
            }
        }
    

    所以在FB登录时,它会提示包含所有权限的屏幕
    enter image description here

    如果用户按下继续按钮,则将设置权限 . 当您使用FBGraphAPI访问好友列表时,将列出您登录该应用程序的朋友

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

    输出将包含在通过Facebook登录您的应用程序时授予user_friends权限的用户

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

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

    此外,在v2.0中,您必须从每个用户请求 user_friends 权限 . 每次登录时都不再包含 user_friends . 每个用户必须授予 user_friends 权限才能显示在对 /me/friends 的响应中 . 有关更多详细信息,请参阅the Facebook upgrade guide,或查看以下摘要 .

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

    • If you want to let your people tag their friends 在他们使用您的应用程序发布到Facebook的故事中,您可以使用 /me/taggable_friends API . Use of this endpoint requires review by Facebook并且只应用于呈现朋友列表以便让用户在帖子中标记他们的情况 .

    • If your App is a Game AND your Game supports Facebook Canvas ,您可以使用 /me/invitable_friends endpoints 来渲染a custom invite dialog,然后将此API返回的标记传递给the standard Requests Dialog.

    在其他情况下,应用程序无法再检索用户朋友的完整列表(仅限那些使用 user_friends 权限专门授权您的应用的朋友) . This has been confirmed by Facebook as 'by design'.

    对于希望允许其他人邀请朋友使用应用的应用,您仍然可以使用Send Dialog on Web或新的Message Dialog on iOSAndroid .

    更新:Facebook已在此发布了有关这些更改的常见问题解答:https://developers.facebook.com/docs/apps/faq,它解释了开发人员可以选择的所有选项以邀请朋友等 .

相关问题