API do Facebook Graph v2.0 + - / me / friends retorna vazio ou apenas amigos que também usam meu aplicativo

366

Estou tentando obter o nome e os IDs de meu amigo com a Graph API v2.0, mas os dados retornam vazios:

{
  "data": [
  ]
}

Quando eu estava usando a v1.0, tudo estava bem com a seguinte solicitação:

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

Mas agora não posso ter amigos!

Kaslico
fonte
uma possível superar a este problema stackoverflow.com/a/25584013/2529087
java.quaso

Respostas:

627

Na v2.0 da API do Graph, a chamada /me/friendsretorna os amigos da pessoa que também usam o aplicativo.

Além disso, na v2.0, você deve solicitar a user_friendspermissão de cada usuário. user_friendsnão é mais incluído por padrão em todos os logins. Cada usuário deve conceder a user_friendspermissão para aparecer na resposta a /me/friends. Consulte o guia de atualização do Facebook para obter informações mais detalhadas ou revise o resumo abaixo.

Se você deseja acessar uma lista de amigos que não usam aplicativos, há duas opções:

  1. Se você deseja permitir que seu pessoal marque seus amigos em histórias que eles publicam no Facebook usando seu aplicativo, você pode usar a/me/taggable_friendsAPI. O uso desse terminal requer a revisão do Facebook e deve ser usado apenas no caso em que você estiver renderizando uma lista de amigos para permitir que o usuário os marque em uma postagem.

  2. Se seu aplicativo for um jogo E seu jogo for compatível com o Facebook Canvas , você poderá usar o/me/invitable_friendsterminal para renderizar uma caixa de diálogo de convite personalizada e passar os tokens retornados por esta API para o diálogo de solicitações padrão.

Em outros casos, os aplicativos não podem mais recuperar a lista completa de amigos de um usuário (apenas aqueles que autorizaram seu aplicativo especificamente usando a user_friendspermissão). Isso foi confirmado pelo Facebook como 'por design'.

Para aplicativos que desejam permitir que as pessoas convidem amigos para usar um aplicativo, você ainda pode usar a caixa de diálogo Enviar na Web ou a nova caixa de diálogo de mensagem no iOS e Android .

ATUALIZAÇÃO: O Facebook publicou uma FAQ sobre essas alterações aqui: https://developers.facebook.com/docs/apps/faq, que explica todas as opções disponíveis para os desenvolvedores para convidar amigos etc.

Simon Cross
fonte
Alguma notícia desde sua última edição ou estamos na mesma página?
Ilya Gazman
Não é possível ver taggable_friendso item nos itens para envio da revisão.
precisa saber é o seguinte
7
Não consigo entender por que eles tiveram que restringir isso tanto. Quero dizer, o sistema antigo era muito abusável, mas este é quase inútil. Ver o perfil público de todos os seus amigos certamente não seria um problema de privacidade. A menos que você pense que a conexão da amizade é privada em si (mas, novamente, por que não ocorre no caso de amigos com tags). Esta não foi uma ação para restringir o abuso de privacidade, o que é um efeito colateral, eles queriam diminuir a capacidade de desenvolvedores normais (não afiliados ao Facebook) aumentarem seus negócios usando dados do Facebook.
Daniel Sharp
3
O Facebook publicou recentemente grandes mudanças nos dados disponíveis: consulte changelog . O taggable_friendsagora não retorna nada. Além disso, a revisão do login é necessária antes que você possa receber user_friendspermissão.
Duncan Jones
Qual o sentido de fornecer uma API se ela não permitir que você execute uma tarefa básica, como listar os amigos?
6infinity8
17

Embora a resposta de Simon Cross seja aceita e correta, pensei em reforçá-la um pouco com um exemplo (Android) do que precisa ser feito. Vou mantê-lo o mais geral possível e me concentrar apenas na questão. Pessoalmente, acabei armazenando coisas em um banco de dados para que o carregamento fosse tranquilo, mas isso requer um CursorAdapter e ContentProvider, que está um pouco fora do escopo aqui.

Eu vim aqui e pensei: e agora ?!

O problema

Assim como user3594351 , eu estava percebendo que os dados do amigo estavam em branco. Descobri isso usando o FriendPickerFragment. O que funcionou há três meses, não funciona mais. Até os exemplos do Facebook quebraram. Portanto, meu problema foi 'Como faço para criar FriendPickerFragment manualmente?

O que não funcionou

A opção 1 de Simon Cross não era forte o suficiente para convidar amigos para o aplicativo. Simon Cross também recomendou o Diálogo de Solicitações, mas isso permitiria apenas cinco solicitações por vez. O diálogo de solicitações também mostrava os mesmos amigos durante qualquer sessão de logon do Facebook. Nao é útil.

O que funcionou (Resumo)

Opção # 2 com algum trabalho duro. Você deve certificar-se de cumprir as novas regras do Facebook: 1.) Você é um jogo 2.) Você tem um aplicativo Canvas (presença na Web) 3.) Seu aplicativo está registrado no Facebook. Tudo é feito no site do desenvolvedor do Facebook em Configurações .

Para emular o seletor de amigos manualmente no meu aplicativo, fiz o seguinte:

  1. Crie uma atividade de guia que mostre dois fragmentos. Cada fragmento mostra uma lista. Um fragmento para amigo disponível ( / me / friends ) e outro para amigos com convite ( / me / invitable_friends ). Use o mesmo código de fragmento para renderizar as duas guias.
  2. Crie uma AsyncTask que obterá os dados de amigos do Facebook. Depois que esses dados forem carregados, jogue-os no adaptador que renderizará os valores na tela.

Detalhes

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

A classe FacebookFriend que criei

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
fonte
20
Que tal para aplicativos que não são de jogos? Um site de namoro ... um jogo para encontrar pessoas, um aplicativo para encontrar restaurantes ... um jogo para encontrar restaurantes, etc., você entendeu. Então, isso é REALMENTE próximo aos jogos ou é apenas uma maneira de forçá-lo a colocar um aplicativo no Facebook e gastar dinheiro na plataforma de publicidade deles? Quem vai decidir o que é um jogo? Quem decidiu que seu aplicativo é realmente um jogo ou não? Não me entenda mal, mas para mim não faz sentido bloquear aplicativos que não sejam de jogos, a menos que você queira apenas forçá-los a usar o ecossistema do Facebook.
Mário
@ Mário Essa é a intenção do Facebook sob o capô. Você pode colocar qualquer coisa e marcá-lo como um jogo, pois eles não se importam se é realmente um jogo ou não. tudo o que eles se importam é tirar dinheiro do seu bolso.
sandalone
12

O Facebook revisou suas políticas agora. Você não pode obter toda a lista de amigos de qualquer maneira, se o aplicativo não tiver uma implementação do Canvas e se o aplicativo não for um jogo. Claro que também há taggable_friends, mas esse é apenas para marcação.

Você poderá puxar a lista de amigos que autorizaram apenas o aplicativo.

Os aplicativos que estão usando a Graph API 1.0 estarão funcionando até 30 de abril de 2015 e depois disso serão preteridos.

Veja o seguinte para obter mais detalhes sobre isso:

Jobins John
fonte
3

No Swift 4.2 e no Xcode 10.1:

Se você deseja obter a lista de amigos do Facebook, envie seu aplicativo para análise no Facebook. Veja algumas das permissões de logon:

Permissões de login

Aqui estão os dois passos:

1) Primeiro, o status do seu aplicativo deve estar no Live

2) Obtenha as permissões necessárias do Facebook.

1) Ative o status do nosso aplicativo ao vivo:

  1. Vá para a página de aplicativos e selecione seu aplicativo

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

  2. Selecione o status no canto superior direito do Painel .

    Digite a descrição da imagem aqui

  3. Enviar URL da política de privacidade

    Digite a descrição da imagem aqui

  4. Selecionar categoria

    Digite a descrição da imagem aqui

  5. Agora, nosso aplicativo está no status Ao vivo .

    Digite a descrição da imagem aqui

Uma etapa está concluída.

2) Envie nosso aplicativo para revisão:

  1. Primeiro, envie as solicitações necessárias.

    Exemplo: user_friends, user_videos, user_posts etc.

    Digite a descrição da imagem aqui

  2. Segundo, vá para a página Solicitação Atual

    Digite a descrição da imagem aqui

    Exemplo: user_events

  3. Enviar todos os detalhes

    Digite a descrição da imagem aqui

  4. Como este envio para todas as solicitações (user_friends, user_events, user_videos, user_posts etc.).

  5. Por fim, envie seu aplicativo para análise.

    Se a sua crítica for aceita do lado do Facebook, você estará qualificado para ler contatos etc.

iOS
fonte
3
A user_friendspermissão é muito limitada. Da documentação do Facebook (abril de 2019): [Isso apenas] concede permissão ao aplicativo para acessar uma lista de amigos que também usam o aplicativo. Essa permissão é restrita a um conjunto limitado de parceiros e o uso requer aprovação prévia do Facebook. Para que uma pessoa apareça na lista de amigos de outras pessoas, é necessário que ambas tenham compartilhado sua lista de amigos com o aplicativo e não tenham desabilitado essa permissão durante o login.
dearsina
2

Como Simon mencionou, isso não é possível na nova API do Facebook. Puro tecnicamente falando, você pode fazer isso através da automação do navegador.

  • isso é contra a política do Facebook, portanto, dependendo do país em que você mora, isso pode não ser legal
  • você precisará usar suas credenciais / solicitar credenciais ao usuário e possivelmente armazená-las (armazenar senhas mesmo criptografadas simetricamente não é uma boa ideia)
  • quando o Facebook alterar sua API, você também precisará atualizar o código de automação do navegador (se não conseguir forçar as atualizações do seu aplicativo, deverá colocar a parte da automação do navegador como um serviço da web)
  • isso está ignorando o conceito OAuth
  • por outro lado, sinto que estou possuindo meus dados, incluindo a lista de meus amigos e o Facebook, que não devem me impedir de acessá-los por meio da API

Exemplo de implementação usando 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;
}

Protótipo com a implementação dessa abordagem (usando C # / WatiN), consulte https://github.com/svejdo1/ShadowApi . Também está permitindo a atualização dinâmica do conector do Facebook que está recuperando uma lista de seus contatos.

Ondrej Svejdar
fonte
2
Seu código pressupõe que o aplicativo tenha acesso ao nome de usuário e senha do usuário. Não é assim que o OAuth funciona e a maioria dos usuários não fornece seu nome de usuário e senha do FB a um aplicativo. Isso seria um enorme risco de segurança.
jbustamovej
32
Isso é contra a política do Facebook. Este conselho não deve ser seguido.
Simon Cross
3
Em outra nota, você nem está protegendo as credenciais do usuário em seu hack. Caso alguém decida usar seu código, verifique se ele usa SSL alterando a uri para https.
Rogala 31/08
8
Mais um por enfiar na cara deles!
Skynet
12
Todos vocês parecem que as políticas do Facebook são algum tipo de Direito Internacional e, ao quebrá-lo, você é um criminoso. Além disso, você acha que o Facebook tem apenas o melhor para o usuário, o que eu acho errado, como @OndrejSvejdar afirmou, porque eles deixariam você escolher se você quer ser visto em outros aplicativos. Eu acho que isso é apenas uma jogada do Facebook para atrapalhar o crescimento de outras pessoas através de sua plataforma GRATUITAMENTE. Em vez disso, as pessoas devem começar a desenvolver seus aplicativos, serviços, jogos, notícias etc. diretamente no Facebook. E pague pela publicidade no Facebook quando não o fizerem.
precisa saber é o seguinte
2

Tente /me/taggable_friends?limit=5000usar seu código JavaScript

Ou

tente a API do Graph :

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

Abhishek Sharma
fonte
2
Como eu acho - os votos negativos aqui são porque "O uso desse ponto de extremidade requer revisão pelo Facebook e deve ser usado apenas no caso em que você estiver renderizando uma lista de amigos para permitir que o usuário os marque em uma postagem". Você pode ler mais sobre isso na resposta selecionada.
moonvader
{"data": [], "summary": {"total_count": 414}} recebi este bloco de dados json nulo, não obtendo amigos. O que eu posso fazer?
Makvin 20/02/19
-1

Na SDK Graph API do Facebook v2.0 ou superior, você deve solicitar a permissão user_friends de cada usuário no momento do login do Facebook, pois user_friends não é mais incluído por padrão em todos os logins ; nós temos que adicionar isso.

Cada usuário deve conceder a permissão user_friends para aparecer na resposta 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 {
        }
    }
}

Portanto, no momento do login no Facebook, ele exibe uma tela que contém todas as permissões:

Digite a descrição da imagem aqui

Se o usuário pressionar o botão Continuar , as permissões serão definidas. Quando você acessa a lista de amigos usando a API do Graph, seus amigos que fizeram login no aplicativo como acima serão listados

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

            print(result!)
        }
    })
}

A saída conterá os usuários que concederam a permissão user_friends no momento do login no seu aplicativo através do Facebook.

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