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

366

Я пытаюсь получить имя и идентификаторы моего друга в 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);
    }
}];

Но теперь я не могу найти друзей!

Kaslico
источник
возможное решение этой проблемы stackoverflow.com/a/25584013/2529087
java.quaso

Ответы:

627

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

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

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

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

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

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

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

ОБНОВЛЕНИЕ: Facebook опубликовал FAQ об этих изменениях здесь: https://developers.facebook.com/docs/apps/faq, в котором объясняются все опции, доступные разработчикам для приглашения друзей и т. Д.

Саймон Кросс
источник
Любые новости со времени вашего последнего редактирования или мы на той же странице?
Илья Газман
Не может видеть taggable_friendsв пунктах для представления обзора.
Алик Эльзин-килака
7
Я не могу понять, почему им пришлось так сильно ограничивать это. Я имею в виду, что старая система была слишком жестокой, но эта почти бесполезна. Просмотр общедоступного профиля всех ваших друзей, безусловно, не будет проблемой конфиденциальности. Если только вы не думаете, что дружеская связь сама по себе является частной (но, опять же, почему это не так в случае тегируемых друзей). Это не было попыткой ограничить злоупотребление конфиденциальностью, что является побочным эффектом, они хотели закрыть возможность для обычных (не связанных с Facebook) разработчиков развивать свой бизнес, используя данные Facebook.
Даниэль Шарп
3
Facebook недавно опубликовал серьезные изменения доступных данных: см. Список изменений . taggable_friendsТеперь ничего не возвращает. Кроме того, проверка входа требуется, прежде чем вы можете получить user_friendsразрешение.
Дункан Джонс
Какой смысл предоставлять API, если он не позволяет выполнять базовые задачи, такие как перечисление друзей?
6infinity8
17

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

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

Проблема

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

Что не сработало

Вариант № 1 от Саймона Кросса не был достаточно силен, чтобы пригласить друзей в приложение. Саймон Кросс также рекомендовал Диалог запросов, но он позволял только пять запросов одновременно. Диалоговое окно запросов также показывало одних и тех же друзей во время любого входа в 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);
        }
    }
}

Класс 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());
        }
    }
}
ЛЕО
источник
20
Как насчет неигровых приложений? Сайт знакомств ... игра для поиска людей, приложение для поиска ресторанов ... игра для поиска ресторанов и т.д. Так это действительно близко к играм или это просто способ заставить вас разместить приложение внутри Facebook и тратить деньги на их рекламную платформу? Кто решит, что такое игра? Кто решил, что ваше приложение на самом деле игра или нет? Не поймите меня неправильно, но для меня нет смысла блокировать неигровые приложения, если только вы не хотите заставить их использовать экосистему Facebook.
Марио
@ Mario Это намерение Facebook под капотом. Вы можете поставить что угодно и пометить это как игру, так как им все равно, действительно ли это игра или нет. все, что их волнует, это получать деньги из своего кармана.
сандал
12

Facebook пересмотрел свою политику сейчас. В любом случае вы не сможете получить весь список друзей, если ваше приложение не имеет реализации Canvas и если ваше приложение не является игрой. Конечно, есть также taggable_friends, но этот предназначен только для тегов.

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

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

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

Джобинс Джон
источник
3

В Swift 4.2 и Xcode 10.1:

Если вы хотите получить список друзей из Facebook, вам нужно отправить свое приложение на рассмотрение в Facebook. Посмотрите некоторые из Входов Разрешения:

Разрешения входа

Вот два шага:

1) Сначала статус вашего приложения должен быть в Live

2) Получить необходимые разрешения формы Facebook.

1) Включите статус нашего приложения в реальном времени:

  1. Перейдите на страницу приложений и выберите свое приложение

    https://developers.facebook.com/apps/

  2. Выберите статус в правом верхнем углу панели инструментов .

    Введите описание изображения здесь

  3. Отправить URL политики конфиденциальности

    Введите описание изображения здесь

  4. Выберите категорию

    Введите описание изображения здесь

  5. Теперь наше приложение находится в статусе Live .

    Введите описание изображения здесь

Один шаг завершен.

2) Отправьте наше приложение на рассмотрение:

  1. Сначала отправьте необходимые запросы.

    Пример: user_friends, user_videos, user_posts и т. Д.

    Введите описание изображения здесь

  2. Во-вторых, перейдите на страницу текущего запроса

    Введите описание изображения здесь

    Пример: user_events

  3. Отправить все детали

    Введите описание изображения здесь

  4. Как это отправить для всех запросов (user_friends, user_events, user_videos, user_posts и т. Д.).

  5. Наконец, отправьте ваше приложение на рассмотрение.

    Если ваш отзыв принят со стороны Facebook, вы можете читать контакты и т. Д.

IOS
источник
3
user_friendsРазрешение очень ограничено. Из документации Facebook (апрель 2019 г.): [Только это] предоставляет приложению разрешение на доступ к списку друзей, которые также используют это приложение. Это разрешение ограничено ограниченным набором партнеров, и использование требует предварительного одобрения Facebook. Для того, чтобы человек появился в списке друзей другого пользователя, оба должны были поделиться своим списком друзей с приложением и не отключать это разрешение при входе в систему.
dearsina
2

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

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

Ондрей Свейдар
источник
2
Ваш код предполагает, что приложение имеет доступ к имени пользователя и паролю пользователя. Это не то, как работает OAuth, и большинство пользователей не собираются предоставлять свое имя пользователя FB и пароль для приложения. Это было бы огромным риском для безопасности.
Jbustamovej
32
Это противоречит политике Facebook. Этот совет не должен следовать.
Саймон Кросс
3
С другой стороны, вы даже не можете безопасно защищать учетные данные своего пользователя во время взлома. На случай, если кто-то решит использовать ваш код, убедитесь, что он использует SSL, изменив URI на https.
Рогала
8
Плюс один за то, что сунул им в лицо!
Скайнет
12
Все вы говорите, что политика Facebook - это своего рода международное право, и, нарушая его, вы становитесь преступником. Кроме того, вы думаете, что Facebook имеет в виду только лучшее для пользователя, что, на мой взгляд, неправильно, как сказал @OndrejSvejdar, потому что тогда они просто позволят вам выбрать, хотите ли вы, чтобы вас видели в других приложениях. Я думаю, что это просто шаг со стороны Facebook, чтобы БЕСПЛАТНО нарушить рост других через их платформу. Вместо этого люди должны начать разработку своих приложений, сервисов, игр, новостей и т. Д. Непосредственно на Facebook. И платить за рекламу в Facebook, если они этого не сделают.
JustGoscha
2

Попробуйте /me/taggable_friends?limit=5000использовать свой код JavaScript

Или

попробуйте Graph API :

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

Абхишек Шарма
источник
2
Как я думаю, здесь отрицательные отзывы объясняются тем, что «использование этой конечной точки требует проверки со стороны Facebook и должно использоваться только в том случае, когда вы отображаете список друзей, чтобы позволить пользователю пометить их в сообщении». Вы можете прочитать больше об этом в выбранном ответе.
Moonvader
{"data": [], "summary": {"total_count": 414}} я получил этот блок данных json, ноль не найти друзей. Что я могу сделать?
Маквин
-1

В API Facebook SDK Graph v2.0 или выше вы должны запрашивать разрешение user_friends у каждого пользователя во время входа в Facebook с момента 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, он предлагает экран, который содержит все разрешения:

Введите описание изображения здесь

Если пользователь нажимает кнопку « Продолжить» , разрешения будут установлены. Когда вы получаете доступ к списку друзей с помощью 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!)
        }
    })
}

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

{
    data = (
             {
                 id = xxxxxxxxxx;
                 name = "xxxxxxxx";
             }
           );
    paging = {
        cursors = {
            after = xxxxxx;
            before = xxxxxxx;
        };
    };
    summary = {
        "total_count" = 8;
    };
}
Линееш К Мохан
источник