API API API v2.0 + - / me / friends повертається порожньою, або лише друзі, які також використовують мою програму


366

Я намагаюся отримати ім’я та ідентифікатор свого друга за допомогою API 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);
    }
}];

Але зараз я не можу завести друзів!


можливим подолати до цієї проблеми stackoverflow.com/a/25584013/2529087
java.quaso

Відповіді:


627

У v2.0 графічного API виклик /me/friendsповертає друзів людини, які також використовують додаток.

Крім того, в v2.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 опублікував тут поширені запитання щодо цих змін: 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 від Simon Cross був недостатньо сильним, щоб запросити друзів у додаток. Саймон Кросс також рекомендував діалог запитів, але це дозволило б одночасно п’ять запитів. Діалогове вікно запитів також показало тих самих друзів під час будь-якого даного Facebook, який увійшов у сесію. Не корисно.

Що працювало (резюме)

Варіант №2 з важкою працею. Ви повинні переконатися, що ви виконуєте нові правила Facebook: 1.) Ви граєте 2.) У вас є додаток Canvas (веб-присутність) 3.) Ваш додаток зареєстровано у Facebook. Все це робиться на веб-сайті розробника Facebook у розділі Налаштування .

Щоб наслідувати вибору друга вручну в моєму додатку, я зробив наступне:

  1. Створіть активність на вкладці, яка показує два фрагменти Кожен фрагмент показує список. Один фрагмент для доступного друга ( / мене / друзів ) та ще один для запрошених друзів ( / мене / запрошених друзів ). Використовуйте один і той же код фрагмента для відображення обох вкладок.
  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.
Маріо

@ Mário Це намір Facebook під кришкою. Ви можете поставити що завгодно і позначити це грою, оскільки їм все одно, це справді гра чи ні. все, що їм важливо, - це отримати гроші з кишені.
сандалон

12

Зараз Facebook переглянув їх політику. Ви не можете отримати весь список друзів, якщо у вашому додатку немає програми Canvas та якщо ваш додаток не є грою. Звичайно, є також taggable_friends, але це лише для тегів.

Ви зможете витягнути список друзів, які авторизували лише додаток.

Додатки, які використовують Graph API 1.0, працюватимуть до 30 квітня 2015 року, після чого його буде знято.

Щоб отримати детальнішу інформацію про це, перегляньте наступне:


3

У Swift 4.2 та Xcode 10.1:

Якщо ви хочете отримати список друзів з Facebook, вам потрібно подати свою заявку на розгляд у Facebook. Перегляньте деякі дозволи на вхід:

Дозволи на вхід

Ось два кроки:

1) По-перше, ваш статус додатка повинен бути в прямому ефірі

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, тепер ви маєте право читати контакти тощо.


3
user_friendsДозвіл дуже обмежена. З документації Facebook (квітень 2019 р.): [Це лише] надає програмі дозвіл на доступ до списку друзів, які також використовують цей додаток. Цей дозвіл обмежений обмеженим набором партнерів, а використання вимагає попереднього затвердження Facebook. Для того, щоб людина з’явилася в чужому списку друзів, обидва люди повинні поділитися своїм списком друзів із додатком, а не відключили цей дозвіл під час входу.
dearsina

2

Як зазначив Саймон, це неможливо в новому API API. Чисто технічно кажучи, ви можете це зробити за допомогою автоматизації браузера.

  • це проти політики 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

Або

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

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


2
Як я вважаю, зворотний зв'язок тут полягає в тому, що "Використання цієї кінцевої точки вимагає перегляду у Facebook, і воно повинно використовуватися лише у випадку, коли ви надаєте список друзів, щоб користувач міг їх розмістити в публікації". Детальніше про це ви можете прочитати у вибраній відповіді.
moonvader

{"data": [], "Summary": {"total_count": 414}} Я отримав цей блок даних json null not friends. Що я можу зробити?
Маквін

-1

У Facebook SDK Graph API v2.0 або вище, ви повинні вимагати дозволу user_friends від кожного користувача під час входу в Facebook, оскільки користувач_friends більше не включається у кожне вхід; ми повинні додати це.

Кожен користувач повинен надати user_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, запит на екрані, який містить усі дозволи:

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

Якщо користувач натисне кнопку « Продовжити », дозволи будуть встановлені. Коли ви отримуєте доступ до списку друзів за допомогою API 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;
    };
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.