Facebook Graph API v2.0 + - / me / friends renvoie vide, ou seulement des amis qui utilisent également mon application

366

J'essaie d'obtenir le nom et les identifiants de mon ami avec Graph API v2.0, mais les données retournent vides:

{
  "data": [
  ]
}

Lorsque j'utilisais la v1.0, tout allait bien avec la demande suivante:

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

Mais maintenant, je ne peux plus me faire d'amis!

Kaslico
la source
une
solution

Réponses:

627

Dans la version 2.0 de l'API Graph, l'appel /me/friendsrenvoie les amis de la personne qui utilisent également l'application.

De plus, dans la version 2.0, vous devez demander l' user_friendsautorisation à chaque utilisateur. user_friendsn'est plus inclus par défaut dans chaque connexion. Chaque utilisateur doit accorder l' user_friendsautorisation pour apparaître dans la réponse à /me/friends. Consultez le guide de mise à niveau de Facebook pour des informations plus détaillées ou consultez le résumé ci-dessous.

Si vous souhaitez accéder à une liste d'amis qui n'utilisent pas d'application, il existe deux options:

  1. Si vous souhaitez laisser vos gens taguer leurs amis dans des histoires qu'ils publient sur Facebook à l'aide de votre application, vous pouvez utiliser l'/me/taggable_friendsAPI. L'utilisation de ce point de terminaison nécessite un examen par Facebook et ne doit être utilisée que dans le cas où vous affichez une liste d'amis afin de permettre à l'utilisateur de les étiqueter dans un message.

  2. Si votre application est un jeu ET que votre jeu prend en charge Facebook Canvas , vous pouvez utiliser le/me/invitable_friendspoint de terminaison pour afficher une boîte de dialogue d'invitation personnalisée , puis transmettre les jetons renvoyés par cette API à la boîte de dialogue des demandes standard.

Dans d'autres cas, les applications ne peuvent plus récupérer la liste complète des amis d'un utilisateur (uniquement les amis qui ont spécifiquement autorisé votre application en utilisant l' user_friendsautorisation). Cela a été confirmé par Facebook comme `` par conception ''.

Pour les applications qui souhaitent autoriser les utilisateurs à inviter des amis à utiliser une application, vous pouvez toujours utiliser la boîte de dialogue Envoyer sur le Web ou la nouvelle boîte de dialogue Message sur iOS et Android .

MISE À JOUR: Facebook a publié une FAQ sur ces changements ici: https://developers.facebook.com/docs/apps/faq qui explique toutes les options disponibles pour les développeurs afin d'inviter des amis, etc.

Simon Cross
la source
Des nouvelles depuis votre dernier montage ou nous sur la même page?
Ilya Gazman
Impossible de voir le taggable_friendsdans les éléments à soumettre pour examen.
AlikElzin-kilaka
7
Je ne comprends pas pourquoi ils ont dû le restreindre autant. Je veux dire que l'ancien système était beaucoup trop abusif, mais celui-ci est presque inutile. Voir le profil public de tous vos amis ne serait certainement pas un problème de confidentialité. A moins que vous ne pensiez que le lien d'amitié est lui-même privé (mais encore une fois pourquoi ne l'est-il pas dans le cas d'amis taggables). Ce n'était pas un geste pour limiter les abus de la vie privée qui est un effet secondaire, ils voulaient restreindre la possibilité pour les développeurs normaux (non affiliés à Facebook) de développer leur entreprise en utilisant les données Facebook.
Daniel Sharp
3
Facebook a récemment publié des modifications majeures des données disponibles: voir le changelog . Le taggable_friendsne renvoie désormais rien. En outre, un examen de connexion est requis avant que vous puissiez obtenir une user_friendsautorisation.
Duncan Jones
Quel est l'intérêt de fournir une API si elle ne vous permet pas d'effectuer une tâche de base telle que répertorier les amis?
6infinity8
17

Bien que Simon Cross réponse de soit acceptée et correcte, j'ai pensé que je la renforcerais un peu avec un exemple (Android) de ce qui doit être fait. Je vais le garder aussi général que possible et me concentrer uniquement sur la question. Personnellement, j'ai fini par stocker des choses dans une base de données, donc le chargement était fluide, mais cela nécessite un CursorAdapter et ContentProvider qui est un peu hors de portée ici.

Je suis venu ici moi-même et j'ai pensé, maintenant quoi?!

Le problème

Tout comme user3594351 , je remarquais que les données des amis étaient vides. J'ai découvert cela en utilisant le FriendPickerFragment. Ce qui a fonctionné il y a trois mois ne fonctionne plus. Même les exemples de Facebook ont ​​éclaté. Mon problème était donc «Comment créer manuellement FriendPickerFragment?

Ce qui n'a pas fonctionné

L'option n ° 1 de Simon Cross n'était pas assez forte pour inviter des amis à l'application. Simon Cross a également recommandé la boîte de dialogue Demandes, mais cela ne permettrait que cinq demandes à la fois. La boîte de dialogue des demandes a également montré les mêmes amis lors d'une session de connexion Facebook donnée. Pas utile.

Ce qui a fonctionné (résumé)

Option # 2 avec un travail acharné. Vous devez vous assurer que vous respectez les nouvelles règles de Facebook: 1.) Vous êtes un jeu 2.) Vous avez une application Canvas (présence Web) 3.) Votre application est enregistrée sur Facebook. Tout est fait sur le site Web des développeurs Facebook sous Paramètres .

Pour émuler le sélecteur d'amis à la main dans mon application, j'ai fait ce qui suit:

  1. Créez une activité d'onglet qui montre deux fragments. Chaque fragment montre une liste. Un fragment pour les amis disponibles ( / me / friends ) et un autre pour les amis invitables ( / me / invitable_friends ). Utilisez le même code de fragment pour rendre les deux onglets.
  2. Créez une tâche AsyncTask qui obtiendra les données d'amis de Facebook. Une fois ces données chargées, jetez-les à l'adaptateur qui restituera les valeurs à l'écran.

Détails

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

La classe FacebookFriend que j'ai créée

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());
        }
    }
}
LEO
la source
20
Qu'en est-il des applications non liées au jeu? Un site de rencontres ... un jeu pour trouver des gens, une application pour trouver des restaurants ... un jeu pour trouver des restaurants, etc. vous avez l'idée. Alors, est-ce vraiment proche des jeux ou est-ce juste un moyen de vous forcer à placer une application sur Facebook et à dépenser de l'argent sur leur plate-forme publicitaire? Qui va décider ce qu'est un jeu? Qui a décidé que votre application était en fait un jeu ou non? Ne vous méprenez pas sur cela, mais pour moi, cela n'a aucun sens de bloquer les applications non liées au jeu, sauf si vous voulez simplement les forcer à utiliser l'écosystème Facebook.
Mário
@ Mário C'est l'intention de Facebook sous le capot. Vous pouvez mettre n'importe quoi et le marquer comme un jeu car ils ne se soucient pas si c'est vraiment un jeu ou non. tout ce dont ils se soucient, c'est de retirer de l'argent de votre poche.
sandalone
12

Facebook a révisé ses politiques maintenant. De toute façon, vous ne pouvez pas obtenir la liste d'amis complète si votre application n'a pas d'implémentation Canvas et si votre application n'est pas un jeu. Bien sûr, il y a aussi taggable_friends, mais celui-ci est uniquement pour le marquage.

Vous pourrez extraire la liste des amis qui ont autorisé l'application uniquement.

Les applications qui utilisent Graph API 1.0 fonctionneront jusqu'au 30 avril 2015 et après cela, elles seront obsolètes.

Voir ce qui suit pour obtenir plus de détails à ce sujet:

Jobins John
la source
3

Dans Swift 4.2 et Xcode 10.1:

Si vous souhaitez obtenir la liste d'amis de Facebook, vous devez soumettre votre application pour examen sur Facebook. Voir certaines des autorisations de connexion:

Autorisations de connexion

Voici les deux étapes:

1) Le statut de votre application doit d'abord être en direct

2) Obtenez les autorisations requises via Facebook.

1) Activez l'état de notre application en direct:

  1. Accédez à la page des applications et sélectionnez votre application

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

  2. Sélectionnez l'état en haut à droite du tableau de bord .

    Entrez la description de l'image ici

  3. Soumettre l' URL de la politique de confidentialité

    Entrez la description de l'image ici

  4. Sélectionnez une catégorie

    Entrez la description de l'image ici

  5. Maintenant, notre application est en statut Live .

    Entrez la description de l'image ici

Une étape est terminée.

2) Soumettez notre application pour examen:

  1. Envoyez d'abord les demandes requises.

    Exemple: user_friends, user_videos, user_posts, etc.

    Entrez la description de l'image ici

  2. Ensuite, accédez à la page Demande actuelle

    Entrez la description de l'image ici

    Exemple: user_events

  3. Soumettre tous les détails

    Entrez la description de l'image ici

  4. Comme cette soumission pour toutes les demandes (user_friends, user_events, user_videos, user_posts, etc.).

  5. Enfin, soumettez votre application pour examen.

    Si votre avis est accepté du côté de Facebook, vous pouvez désormais lire les contacts, etc.

iOS
la source
3
L' user_friendsautorisation est très limitée. D'après la documentation de Facebook (avril 2019): [Cela uniquement] accorde à une application la permission d'accéder à une liste d'amis qui utilisent également ladite application. Cette autorisation est limitée à un ensemble limité de partenaires et son utilisation nécessite l'approbation préalable de Facebook. Pour qu'une personne apparaisse dans la liste d'amis d'une autre personne, les deux personnes doivent avoir partagé leur liste d'amis avec l'application et ne pas avoir désactivé cette autorisation lors de la connexion.
dearsina
2

Comme Simon l'a mentionné, cela n'est pas possible dans la nouvelle API Facebook. Techniquement parlant, vous pouvez le faire via l'automatisation du navigateur.

  • cela est contraire à la politique de Facebook, donc selon le pays où vous vivez, cela peut ne pas être légal
  • vous devrez utiliser vos informations d'identification / demander à l'utilisateur des informations d'identification et éventuellement les stocker (le stockage de mots de passe même cryptés symétriquement n'est pas une bonne idée)
  • lorsque Facebook modifie son API, vous devrez également mettre à jour le code d'automatisation du navigateur (si vous ne pouvez pas forcer les mises à jour de votre application, vous devez mettre la pièce d'automatisation du navigateur en tant que service Web)
  • cela contourne le concept OAuth
  • d'autre part, mon sentiment est que je possède mes données, y compris la liste de mes amis et Facebook ne devrait pas m'empêcher d'accéder à celles-ci via l'API

Exemple d'implémentation utilisant 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;
}

Prototype avec implémentation de cette approche (en utilisant C # / WatiN) voir https://github.com/svejdo1/ShadowApi . Il permet également la mise à jour dynamique du connecteur Facebook qui récupère une liste de vos contacts.

Ondrej Svejdar
la source
2
Votre code suppose que l'application a accès au nom d'utilisateur et au mot de passe de l'utilisateur. Ce n'est pas ainsi que fonctionne OAuth, et la plupart des utilisateurs ne vont pas fournir leur nom d'utilisateur et mot de passe FB à une application. Ce serait un énorme risque pour la sécurité.
jbustamovej
32
C'est contraire à la politique de Facebook. Ce conseil ne doit pas être suivi.
Simon Cross
3
Sur une autre note, vous n'êtes même pas sûr de protéger les informations d'identification de votre utilisateur dans votre hack. Juste au cas où quelqu'un décide d'utiliser votre code, assurez-vous qu'il utilise SSL en changeant l'uri en https.
Rogala
8
Plus un pour le pousser sur leur visage!
Skynet
12
Vous semblez tous que les politiques Facebook sont une sorte de droit international et qu'en les brisant, vous êtes un criminel. Vous pensez également que Facebook n'a que le meilleur pour l'utilisateur, ce qui, selon moi, est faux, comme @OndrejSvejdar l'a déclaré, car ils vous laisseraient simplement choisir si vous souhaitez être vu dans d'autres applications. Je pense que c'est juste une initiative de Facebook pour perturber la croissance des autres via leur plate-forme GRATUITEMENT. Au lieu de cela, les gens devraient commencer à développer leurs applications, services, jeux, actualités, etc. directement sur Facebook. Et payez la publicité Facebook quand ce n'est pas le cas.
JustGoscha
2

Essayez d' /me/taggable_friends?limit=5000utiliser votre code JavaScript

Ou

essayez l' API Graph :

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

Abhishek Sharma
la source
2
Comme je pense - les downvotes sont ici parce que "L'utilisation de ce point de terminaison nécessite un examen par Facebook et ne doit être utilisée que dans le cas où vous affichez une liste d'amis afin de permettre à l'utilisateur de les étiqueter dans un message." Vous pouvez en savoir plus à ce sujet dans la réponse sélectionnée.
Moonvader
{"data": [], "summary": {"total_count": 414}} j'ai obtenu ce bloc de données json nul pour ne pas avoir d'amis. Que puis-je faire?
Makvin
-1

Dans Facebook SDK Graph API v2.0 ou supérieure, vous devez demander l' autorisation user_friends à chaque utilisateur au moment de la connexion Facebook depuis user_friends n'est plus inclus par défaut dans chaque connexion; nous devons ajouter cela.

Chaque utilisateur doit accorder l' autorisation user_friends afin d'apparaître dans la réponse à / 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 {
        }
    }
}

Ainsi, au moment de la connexion Facebook, il vous invite avec un écran qui contient toutes les autorisations:

Entrez la description de l'image ici

Si l'utilisateur appuie sur le bouton Continuer , les autorisations seront définies. Lorsque vous accédez à la liste d'amis à l'aide de l'API Graph, vos amis qui se sont connectés à l'application comme ci-dessus seront répertoriés

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

            print(result!)
        }
    })
}

La sortie contiendra les utilisateurs qui ont accordé l' autorisation user_friends au moment de la connexion à votre application via Facebook.

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