ChatGPT解决这个技术问题 Extra ChatGPT

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

但是现在我交不到朋友!

解决这个问题的可能方法stackoverflow.com/a/25584013/2529087

S
Simon Cross

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

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

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

如果您想让您的人使用您的应用在他们发布到 Facebook 的故事中标记他们的朋友,您可以使用 /me/taggable_friends API。使用此端点需要 Facebook 审核,并且仅应用于您呈现朋友列表以便让用户在帖子中标记他们的情况。如果您的应用是游戏并且您的游戏支持 Facebook Canvas,您可以使用 /me/invitable_friends 端点来呈现自定义邀请对话框,然后将此 API 返回的令牌传递给标准请求对话框。

在其他情况下,应用程序不再能够检索用户朋友的完整列表(只有那些使用 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,其中解释了开发人员可用于邀请朋友等的所有选项。


自您上次编辑或我们在同一页面后有任何消息吗?
在提交审核的项目中看不到 taggable_friends
我不明白他们为什么要限制这么多。我的意思是旧系统太容易被滥用了,但这个系统几乎没用。查看所有朋友的公开资料肯定不会是隐私问题。除非您认为友谊的联系本身是私密的(但为什么不是在可标记朋友的情况下)。这并不是限制隐私滥用的举措,这是一种副作用,他们希望关闭普通(非 Facebook 附属)开发人员使用 Facebook 数据发展业务的能力。
Facebook 最近发布了可用数据的重大变化:请参阅changelogtaggable_friends 现在什么都不返回。此外,在您被授予 user_friends 权限之前,需要进行登录审核。
如果 API 不能让您完成诸如列出朋友之类的基本任务,那么提供 API 的意义何在?
P
Peter Mortensen

尽管 Simon Cross 的回答被接受并且是正确的,但我想我会用一个需要做的例子(Android)来加强它。我会尽量保持一般性,只关注这个问题。就我个人而言,我最终将东西存储在数据库中,因此加载很顺利,但这需要一个 CursorAdapter 和 ContentProvider ,这有点超出了这里的范围。

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

问题

就像 user3594351 一样,我注意到朋友数据是空白的。我通过使用 FriendPickerFragment 发现了这一点。三个月前有效的方法不再有效。甚至 Facebook 的例子也被打破了。所以我的问题是'如何手动创建 FriendPickerFragment?

什么没有奏效

来自 Simon Cross 的选项 #1 不足以邀请朋友使用该应用程序。 Simon Cross 还推荐了 Requests Dialog,但它一次只允许五个请求。在任何给定的 Facebook 登录会话期间,请求对话框也会显示相同的朋友。没用。

什么有效(总结)

选项 #2 需要一些努力。您必须确保满足 Facebook 的新规则:1.) 您是游戏 2.) 您有 Canvas 应用程序(Web Presence) 3.) 您的应用程序已在 Facebook 注册。这一切都在 Facebook 开发者网站的“设置”下完成。

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

创建一个显示两个片段的选项卡活动。每个片段显示一个列表。一个片段用于可用朋友 (/me/friends),另一个片段用于可邀请朋友 (/me/invitable_friends)。使用相同的片段代码来呈现两个选项卡。创建一个从 Facebook 获取好友数据的 AsyncTask。加载该数据后,将其扔给适配器,该适配器会将值呈现到屏幕上。

细节

异步任务

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 Facebook JSON: " + e.getLocalizedMessage());
        }
    }
}

非游戏应用程序怎么样?一个约会网站......一个寻找人的游戏,一个寻找餐馆的应用程序......一个寻找餐馆的游戏等等。你明白了。那么这真的很接近游戏吗,或者这只是迫使你在 Facebook 中放置应用程序并在他们的广告平台上花钱的一种方式?谁来决定什么是游戏?谁决定您的应用实际上是否是游戏?不要误会我的意思,但对我来说,阻止非游戏应用程序是没有意义的,除非你只是想强迫他们使用 facebook 生态系统。
@Mário 这就是 Facebook 的意图。您可以放置任何内容并将其标记为游戏,因为他们不在乎它是否真的是游戏。他们所关心的只是从你的口袋里赚钱。
P
Peter Mortensen

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

您将能够提取仅授权该应用程序的朋友列表。

使用 Graph API 1.0 的应用程序将在 2015 年 4 月 30 日之前运行,之后将被弃用。

请参阅以下内容以获取更多详细信息:

用户好友

Facebook 应用程序开发常见问题解答


P
Peter Mortensen

Swift 4.2 和 Xcode 10.1 中:

如果您想从 Facebook 获取好友列表,您需要在 Facebook 中提交您的应用以供审核。查看一些登录权限:

Login Permissions

这是两个步骤:

1) 首先你的应用状态必须是 Live

2) 从 Facebook 获取所需的权限。

1) 实时启用我们的应用状态:

转到应用程序页面并选择您的应用程序 https://developers.facebook.com/apps/ 在仪表板的右上角选择状态。提交隐私政策 URL 选择类别 现在我们的应用程序处于 Live 状态。

一步完成。

2) 提交我们的应用以供审核:

首先发送所需的请求。示例:user_friends、user_videos、user_posts 等。其次,转到当前请求页面 示例:user_events 提交所有详细信息 像这样提交所有请求(user_friends、user_events、user_videos、user_posts 等)。最后提交您的应用以供审核。如果您的评论被 Facebook 接受,您现在有资格阅读联系人等。


user_friends 权限非常有限。来自 Facebook 的文档(2019 年 4 月):[仅限此] 授予应用访问也使用所述应用的朋友列表的权限。此权限仅限于有限的合作伙伴,使用需要事先获得 Facebook 的批准。为了让一个人出现在另一个人的朋友列表中,两个人都必须与应用共享他们的朋友列表,并且在登录期间没有禁用此权限。
测试人员帐户呢? user_friends 是我的应用程序,我使用朋友的帐户作为测试人员,他们接受了请求,现在他们的帐户显示为测试人员,但是在查询朋友时仍然没有显示?
P
Peter Mortensen

正如 Simon 提到的,这在新的 Facebook API 中是不可能的。纯粹从技术上讲,您可以通过浏览器自动化来做到这一点。

这违反了 Facebook 政策,因此取决于您居住的国家/地区,这可能不合法

您将不得不使用您的凭据/向用户询问凭据并可能存储它们(存储密码,即使对称加密也不是一个好主意)

当 Facebook 更改他们的 API 时,您还必须更新浏览器自动化代码(如果您不能强制更新您的应用程序,您应该将浏览器自动化部分作为 Web 服务)

这是绕过 OAuth 概念

另一方面,我的感觉是我拥有我的数据,包括我的朋友列表,Facebook 不应该限制我通过 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 连接器。


您的代码假定应用可以访问用户的用户名和密码。这不是 OAuth 的工作方式,大多数用户不会将他们的 FB 用户名和密码提供给应用程序。那将是一个巨大的安全风险。
这违反了 Facebook 的政策。不应遵循此建议。
另一方面,您甚至无法在黑客攻击中安全地保护用户的凭据。万一有人决定使用您的代码,请通过将 uri 更改为 https 来确保它使用 SSL。
加上一个把它推到他们脸上!
你们听起来都像 Facebook 的政策是某种国际法,如果违反它,你就是罪犯。你还认为 Facebook 只为用户考虑最好的,我认为这是错误的,就像 @OndrejSvejdar 所说的那样,因为那样他们只会让你选择是否想在其他应用程序中看到。我认为这只是 Facebook 通过免费平台扰乱他人成长的举措。相反,人们应该直接在 Facebook 上开始开发他们的应用程序、服务、游戏、新闻等。如果他们不这样做,就为 Facebook 广告付费。
P
Peter Mortensen

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

或者

试试 Graph API

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


正如我所认为的 - 这里的投票是因为“使用此端点需要 Facebook 审查,并且应该只用于您呈现朋友列表以便让用户在帖子中标记他们的情况。”您可以在选定的答案中阅读有关此内容的更多信息。
"data": [ ], "summary": { "total_count": 414 } } 我得到了这个 json 数据块 null 没有得到朋友。我能做些什么?
P
Peter Mortensen

在 Facebook SDK Graph API v2.0 或更高版本中,您必须在 Facebook 登录时向每个用户请求 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 {
        }
    }
}

所以在 Facebook 登录时,它会提示一个包含所有权限的屏幕:

https://i.stack.imgur.com/9adBL.png

如果用户按下继续按钮,将设置权限。当您使用 Graph API 访问好友列表时,将列出您如上登录应用程序的好友

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

关注公众号,不定期副业成功案例分享
关注公众号

不定期副业成功案例分享

领先一步获取最新的外包任务吗?

立即订阅