Facebook Graph API v2. 0+ - /me / friends возвращает пустые или только друзья, которые также используют мое приложение


Я пытаюсь получить имя моего друга и идентификаторы с Graph API v2. 0, но данные возвращаются пустыми:

{
  "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 356

6 ответов:

в версии 2.0 API Graph, вызов /me/friends возвращает друзей человека, которые также используют приложения.

кроме того, в версии 2.0, вы должны запросить user_friends разрешение от каждого пользователя. user_friends больше не включается по умолчанию при каждом входе. Каждый пользователь должен предоставить user_friends разрешение для того, чтобы появиться в ответе на /me/friends. Смотрите руководство по обновлению Facebook для получения более подробной информации, или обзор резюме ниже.

если вы хотите получить доступ список друзей, не использующих приложение, есть два варианта:

  1. если вы хотите, чтобы ваши люди тэг своих друзей в историях, которые они публикуют на Facebook с помощью вашего приложения, вы можете использовать /me/taggable_friends API. использование этой конечной точки требует рассмотрения Facebook и должен использоваться только в том случае, когда вы отображаете список друзей, чтобы позволить пользователю пометить их в a должность.

  2. если ваше приложение является игрой и ваша игра поддерживает Facebook Canvas можно использовать /me/invitable_friends конечная точка для того, чтобы сделать пользовательский диалог приглашения, затем передайте токены, возвращенные этим API в стандартный диалог запросов.

в других случаях приложения больше не могут получить полный список друзей пользователя (только те друзья, которые специально авторизация вашего приложения с помощью user_friends разрешения). это было подтверждено Facebook как "по дизайну".

для приложений, желающих разрешить людям приглашать друзей использовать приложение, вы все равно можете использовать отправить диалог в Интернете или новый диалоговое окно сообщения на iOS и Android.

обновление: Facebook опубликовал FAQ по этим изменениям здесь:https://developers.facebook.com/docs/apps/faq который объясните все варианты, доступные разработчикам, чтобы пригласить друзей и т. д.

хотя Саймона Кросса ответ принят и правильный, я думал, что я бы немного увеличил его с примером (android) того, что нужно сделать. Я постараюсь сделать это как можно более общим и сосредоточусь только на вопросе. Лично я закончил хранение вещей в базе данных, поэтому загрузка была гладкой, но для этого требуется CursorAdapter и ContentProvider, который немного выходит за рамки здесь.

Я сам пришел сюда и потом подумал, А что теперь?!

в Выпуск

как user3594351, Я заметил, что данные друга были пустыми. Я узнал это с помощью FriendPickerFragment. То, что работало три месяца назад, больше не работает. Даже примеры facebook сломались. Итак, мой вопрос был "как я могу создать FriendPickerFragment вручную?

Что Не Получилось

Вариант №1 от Симон Крест не было достаточно сильным, чтобы пригласить друзей в приложение. Симон Крест также рекомендуется Диалог запросов, но это позволит только 5 запросов одновременно. Диалог запросов также показывал одних и тех же друзей во время любого сеанса входа в систему Facebook. Не полезный.

Что Сработало (Резюме)

Вариант №2 с некоторой тяжелой работой. Вы должны убедиться, что вы выполняете новые правила Facebook: 1.) Ты игра 2.) У вас есть приложение Canvas (веб-присутствие) 3.) Вы приложение зарегистрировано в Facebook. Все сделано на веб-сайте разработчика Facebook под настройки.

для эмуляции выбора друга вручную в моем приложении я сделал следующее:

  1. создайте действие вкладки, которое показывает два фрагмента. Каждый фрагмент показывает список. Один фрагмент для доступных друзей (/me/friends) и другой для приглашенных друзей (/me/invitable_friends). Используйте один и тот же фрагмент кода для отображения обеих вкладок.
  2. создайте AsyncTask, который будет получать данные о друзьях из Facebook. Как только эти данные будут загружены, бросьте их на адаптер, который отобразит значения на экране.

подробности

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

класс Facebook Bookfriend, который я создал

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 пересмотрел свою политику в настоящее время. Вы не можете получить весь список друзей в любом случае, если ваше приложение не имеет реализации холста, и если ваше приложение не является игрой. Конечно, есть также taggable_friends,но это только для маркировки.

вы сможете вытащить список друзей, которые разрешили только приложение.

приложения, использующие Graph API 1.0, будут работать до 30 апреля 2015 года, и после этого он будет устарел.

посмотреть ссылке ниже, чтобы получить более подробную информацию об этом

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

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

надеюсь, что это помогает

Как упоминал Саймон, это невозможно в новом API facebook. чисто с технической точки зрения вы можете сделать это с помощью автоматизации браузера.

  • это против политики Facebook, так что в зависимости от страны, где вы живете это не может быть законным
  • вам придется использовать свои учетные данные / запрашивать учетные данные пользователя и, возможно, хранить их (хранение паролей даже симметрично зашифрованных не является хорошей идеей)
  • когда facebook изменит свой api, вы будете также необходимо обновить код автоматизации браузера (Если вы не можете принудительно обновлять свое приложение, вы должны поместить часть автоматизации браузера в качестве веб-сервиса)
  • это в обход концепции 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 Это также позволяет динамическое обновление Facebook connector, который извлекает список ваших контактов.

Try/me / taggable_friends?limit=5000 с помощью кода javascript

или

попробуйте graph API

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

удачи

в FBSDKGraphAPI версии 2.0 или выше, вы должны запросить разрешение user_friends от каждого пользователя во время входа в систему FB.поскольку 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!)
            }
        })
    }

вывод будет содержать пользователей, которые предоставили user_friends разрешение на момент входа в приложение через Facebook

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