Facebook Graph API v2.0 + - / me / friends ritorna vuoto, oppure solo amici che usano anche la mia applicazione


366

Sto cercando di ottenere il nome e gli ID del mio amico con Graph API v2.0, ma i dati restituiscono vuoti:

{
  "data": [
  ]
}

Quando stavo usando v1.0, tutto era OK con la seguente richiesta:

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

Ma ora non riesco a trovare amici!


una possibile superare questo problema stackoverflow.com/a/25584013/2529087
java.quaso

Risposte:


627

Nella v2.0 dell'API Graph, la chiamata /me/friendsrestituisce gli amici della persona che usano anche l'app.

Inoltre, nella versione 2.0, è necessario richiedere l' user_friendsautorizzazione a ciascun utente. user_friendsnon è più incluso per impostazione predefinita in ogni accesso. Ogni utente deve concedere l' user_friendsautorizzazione per apparire nella risposta a /me/friends. Consulta la guida all'aggiornamento di Facebook per informazioni più dettagliate o consulta il riepilogo di seguito.

Se vuoi accedere a un elenco di amici che non utilizzano app, ci sono due opzioni:

  1. Se vuoi lasciare che i tuoi amici taggino i loro amici in storie che pubblicano su Facebook usando la tua App, puoi usare l'/me/taggable_friendsAPI. L'uso di questo endpoint richiede la revisione da parte di Facebook e dovrebbe essere utilizzato solo nel caso in cui si stia visualizzando un elenco di amici per consentire all'utente di contrassegnarli in un post.

  2. Se la tua app è un gioco E il tuo gioco supporta Facebook Canvas , puoi utilizzare l'/me/invitable_friendsendpoint per eseguire il rendering di una finestra di dialogo di invito personalizzata , quindi passare i token restituiti da questa API alla finestra di dialogo delle richieste standard.

In altri casi, le app non sono più in grado di recuperare l'elenco completo degli amici di un utente (solo quegli amici che hanno specificamente autorizzato la tua app utilizzando l' user_friendsautorizzazione). Ciò è stato confermato da Facebook come "di progettazione".

Per le app che desiderano consentire alle persone di invitare gli amici a utilizzare un'app, è comunque possibile utilizzare la finestra di dialogo Invia sul Web o la nuova finestra di messaggio su iOS e Android .

AGGIORNAMENTO: Facebook ha pubblicato una FAQ su queste modifiche qui: https://developers.facebook.com/docs/apps/faq che spiega tutte le opzioni disponibili agli sviluppatori per invitare amici ecc.


Qualche novità dalla tua ultima modifica o siamo nella stessa pagina?
Ilya Gazman,

Non è possibile visualizzare la voce taggable_friendsnegli articoli per l'invio della recensione.
AlikElzin-Kilaka,

7
Non riesco a capire perché abbiano dovuto limitare così tanto. Voglio dire, il vecchio sistema era troppo abusabile ma questo è quasi inutile. Vedere il profilo pubblico di tutti i tuoi amici non sarebbe sicuramente un problema di privacy. A meno che tu non pensi che la connessione dell'amicizia sia privata stessa (ma, di nuovo, perché non lo è nel caso di amici sfidabili). Questa non è stata una mossa per limitare l'abuso della privacy che è un effetto collaterale, hanno voluto chiudere la capacità degli sviluppatori normali (non affiliati a Facebook) di far crescere la propria attività utilizzando i dati di Facebook.
Daniel Sharp,

3
Facebook ha recentemente pubblicato importanti modifiche ai dati disponibili: consultare il log delle modifiche . L' taggable_friendsora non restituisce nulla. Inoltre, è necessaria la revisione dell'accesso prima di poter ottenere l' user_friendsautorizzazione.
Duncan Jones,

Qual è lo scopo di fornire un'API se non ti consente di svolgere un'attività di base come elencare gli amici?
6infinity8

17

Sebbene la risposta di Simon Cross sia stata accettata e corretta, ho pensato di rinforzarla un po 'con un esempio (Android) di ciò che deve essere fatto. Lo terrò il più generale possibile e mi concentrerò solo sulla domanda. Personalmente ho finito per archiviare le cose in un database in modo che il caricamento fosse regolare, ma ciò richiede un CursorAdapter e ContentProvider che qui è un po 'fuori portata.

Sono venuto qui da solo e poi ho pensato, e adesso ?!

Il problema

Proprio come user3594351 , notavo che i dati degli amici erano vuoti. L'ho scoperto usando FriendPickerFragment. Ciò che ha funzionato tre mesi fa, non funziona più. Persino gli esempi di Facebook si sono rotti. Quindi il mio problema era 'Come faccio a creare FriendPickerFragment a mano?

Cosa non ha funzionato

L'opzione n. 1 di Simon Cross non era abbastanza forte da invitare amici all'app. Anche Simon Cross ha raccomandato la finestra di dialogo Richieste, ma ciò consentirebbe solo cinque richieste alla volta. La finestra di dialogo delle richieste mostrava anche gli stessi amici durante una determinata sessione di accesso a Facebook. Inutile.

Cosa ha funzionato (Riepilogo)

Opzione n. 2 con un duro lavoro. Devi assicurarti di soddisfare le nuove regole di Facebook: 1.) Sei un gioco 2.) Hai un'app Canvas (Presenza Web) 3.) La tua app è registrata con Facebook. È tutto fatto sul sito Web degli sviluppatori di Facebook in Impostazioni .

Per emulare il selettore di amici a mano all'interno della mia app ho fatto quanto segue:

  1. Creare un'attività di tabulazione che mostra due frammenti. Ogni frammento mostra un elenco. Un frammento per amico disponibile ( / me / amici ) e un altro per amici invitabili ( / me / invitable_friends ). Utilizzare lo stesso codice frammento per eseguire il rendering di entrambe le schede.
  2. Crea un AsyncTask che otterrà i dati degli amici da Facebook. Una volta caricati quei dati, lanciarli sull'adattatore che renderà i valori sullo schermo.

Dettagli

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 che ho creato

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
Che ne dici di app non gaming? Un sito di incontri ... un gioco per trovare persone, un'app per trovare ristoranti ... un gioco per trovare ristoranti, ecc. Ti viene l'idea. Quindi è davvero vicino ai giochi o questo è solo un modo per costringerti a posizionare un'app all'interno di Facebook e spendere soldi sulla loro piattaforma pubblicitaria? Chi deciderà cos'è un gioco? Chi ha deciso che la tua app è effettivamente un gioco o no? Non fraintendetemi, ma per me non ha senso bloccare le app non di gioco a meno che non vogliate costringerle a usare l'ecosistema di Facebook.
Mário,

@ Mário Questa è l'intenzione di Facebook sotto il cofano. Puoi mettere qualsiasi cosa e contrassegnarlo come un gioco in quanto a loro non importa se è davvero un gioco o no. a loro importa solo ottenere soldi dalla tua tasca.
sandalone,

12

Facebook ha rivisto le loro politiche ora. Non puoi comunque ottenere l'intera lista amici se la tua app non ha un'implementazione di Canvas e se la tua app non è un gioco. Naturalmente c'è anche taggable_friends, ma quello è solo per tag.

Sarai in grado di estrarre l'elenco di amici che hanno autorizzato solo l'app.

Le app che utilizzano Graph API 1.0 funzioneranno fino al 30 aprile 2015 e successivamente saranno deprecate.

Vedere quanto segue per ottenere maggiori dettagli al riguardo:


3

In Swift 4.2 e Xcode 10.1:

Se desideri ottenere l'elenco di amici da Facebook, devi inviare la tua app per la revisione su Facebook. Vedi alcune delle autorizzazioni di accesso:

Autorizzazioni di accesso

Ecco i due passaggi:

1) Innanzitutto lo stato dell'app deve essere in diretta

2) Ottieni le autorizzazioni richieste da Facebook.

1) Abilita lo stato della nostra app dal vivo:

  1. Vai alla pagina delle app e seleziona la tua app

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

  2. Seleziona lo stato in alto a destra in Dashboard .

    Inserisci qui la descrizione dell'immagine

  3. Invia l' URL della politica sulla privacy

    Inserisci qui la descrizione dell'immagine

  4. Seleziona la categoria

    Inserisci qui la descrizione dell'immagine

  5. Ora la nostra app è nello stato Live .

    Inserisci qui la descrizione dell'immagine

Un passaggio è completato.

2) Invia la nostra app per la revisione:

  1. Innanzitutto invia le richieste richieste.

    Esempio: user_friends, user_videos, user_posts, ecc.

    Inserisci qui la descrizione dell'immagine

  2. Secondo, vai alla pagina Richiesta corrente

    Inserisci qui la descrizione dell'immagine

    Esempio: user_events

  3. Invia tutti i dettagli

    Inserisci qui la descrizione dell'immagine

  4. In questo modo invia per tutte le richieste (user_friends, user_events, user_videos, user_posts, ecc.).

  5. Invia infine la tua app per la revisione.

    Se la tua recensione è accettata dal lato di Facebook, ora sei idoneo a leggere i contatti, ecc.


3
L' user_friendsautorizzazione è molto limitata. Dalla documentazione di Facebook (aprile 2019): [Questo solo] concede a un'app l'autorizzazione ad accedere a un elenco di amici che usano anche detta app. Questa autorizzazione è limitata a un numero limitato di partner e l'utilizzo richiede l'approvazione preventiva di Facebook. Affinché una persona venga visualizzata nell'elenco degli amici di un'altra, entrambe le persone devono aver condiviso il proprio elenco di amici con l'app e non aver disabilitato questa autorizzazione durante l'accesso.
dearsina,

2

Come ha detto Simon, questo non è possibile nella nuova API di Facebook. Tecnicamente parlando , puoi farlo tramite l'automazione del browser.

  • questo è contro la politica di Facebook, quindi a seconda del paese in cui vivi, questo potrebbe non essere legale
  • dovrai usare le tue credenziali / chiedere all'utente le credenziali e possibilmente memorizzarle (archiviare password anche crittografate simmetricamente non è una buona idea)
  • quando Facebook modifica la loro API, dovrai aggiornare anche il codice di automazione del browser (se non puoi forzare gli aggiornamenti della tua applicazione, dovresti mettere l'automazione del browser come servizio web)
  • questo sta aggirando il concetto di OAuth
  • d'altra parte, la mia sensazione è che possiedo i miei dati, incluso l'elenco dei miei amici e Facebook, non dovrebbe impedirmi di accedere a quelli tramite l'API

Implementazione di esempio con 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;
}

Prototipo con l'implementazione di questo approccio (usando C # / WatiN) vedi https://github.com/svejdo1/ShadowApi . Permette anche l'aggiornamento dinamico del connettore Facebook che sta recuperando un elenco dei tuoi contatti.


2
Il codice presuppone che l'app abbia accesso al nome utente e alla password dell'utente. Non è così che funziona OAuth e la maggior parte degli utenti non fornirà il nome utente e la password FB a un'applicazione. Sarebbe un enorme rischio per la sicurezza.
jbustamovej,

32
Questo è contro la politica di Facebook. Questo consiglio non dovrebbe essere seguito.
Simon Cross,

3
In un'altra nota, non sei nemmeno sicuro di proteggere le credenziali del tuo utente nel tuo hack. Nel caso in cui qualcuno decida di utilizzare il tuo codice, assicurati di utilizzare SSL modificando l'uri in https.
Rogala,

8
Più uno per averlo spinto in faccia!
Skynet,

12
Sembri che le politiche di Facebook siano una sorta di diritto internazionale e infrangendolo sei un criminale. Inoltre pensi che Facebook abbia in mente solo il meglio per l'utente, che penso sia sbagliato come affermato da @OndrejSvejdar, perché ti lascerebbero semplicemente scegliere se vuoi essere visto in altre app. Penso che questa sia solo una mossa di Facebook per interrompere la crescita degli altri attraverso la loro piattaforma GRATUITAMENTE. Invece le persone dovrebbero iniziare a sviluppare app, servizi, giochi, notizie, ecc. Direttamente su Facebook. E paga per la pubblicità di Facebook quando non lo faranno.
JustGoscha,

2

Prova a /me/taggable_friends?limit=5000usare il tuo codice JavaScript

O

prova l' API Graph :

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


2
Come penso, i downvotes qui sono perché "L'uso di questo endpoint richiede la revisione da parte di Facebook e dovrebbe essere utilizzato solo nel caso in cui si stia visualizzando un elenco di amici per consentire all'utente di contrassegnarli in un post". Puoi leggere di più su questo nella risposta selezionata.
moonvader,

{"data": [], "summary": {"total_count": 414}} ho ottenuto questo blocco dati json null non ottenere amici. Cosa posso fare?
Makvin,

-1

Nell'API Graph SD2 di Facebook v2.0 o successiva, è necessario richiedere l' autorizzazione user_friends a ciascun utente al momento dell'accesso a Facebook poiché user_friends non è più incluso per impostazione predefinita in ogni accesso; dobbiamo aggiungerlo.

Ogni utente deve concedere l' autorizzazione user_friends per apparire nella risposta a / 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 {
        }
    }
}

Quindi, al momento dell'accesso a Facebook, viene visualizzata una schermata che contiene tutte le autorizzazioni:

Inserisci qui la descrizione dell'immagine

Se l'utente preme il pulsante Continua , verranno impostate le autorizzazioni. Quando accedi all'elenco di amici utilizzando l'API Graph, verranno elencati i tuoi amici che hanno eseguito l'accesso come sopra

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

            print(result!)
        }
    })
}

L'output conterrà gli utenti che hanno concesso l' autorizzazione user_friends al momento dell'accesso all'applicazione tramite Facebook.

{
    data = (
             {
                 id = xxxxxxxxxx;
                 name = "xxxxxxxx";
             }
           );
    paging = {
        cursors = {
            after = xxxxxx;
            before = xxxxxxx;
        };
    };
    summary = {
        "total_count" = 8;
    };
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.