API Grafik Facebook v2.0 + - / saya / teman kembali kosong, atau hanya teman yang juga menggunakan aplikasi saya


366

Saya mencoba mendapatkan nama dan id teman saya dengan Graph API v2.0, tetapi data kembali kosong:

{
  "data": [
  ]
}

Ketika saya menggunakan v1.0, semuanya baik-baik saja dengan permintaan berikut:

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

Tapi sekarang saya tidak bisa mendapatkan teman!


kemungkinan mengatasi masalah ini stackoverflow.com/a/25584013/2529087
java.quaso

Jawaban:


627

Di v2.0 dari Graph API, panggilan /me/friendsmengembalikan teman orang yang juga menggunakan aplikasi.

Selain itu, di v2.0, Anda harus meminta user_friendsizin dari setiap pengguna. user_friendstidak lagi disertakan secara default di setiap login. Setiap pengguna harus memberikan user_friendsizin untuk muncul dalam respons /me/friends. Lihat panduan peningkatan Facebook untuk informasi lebih rinci, atau tinjau ringkasan di bawah ini.

Jika Anda ingin mengakses daftar teman yang tidak menggunakan aplikasi, ada dua opsi:

  1. Jika Anda ingin orang-orang Anda menandai teman-teman mereka dalam cerita yang mereka terbitkan ke Facebook menggunakan Aplikasi Anda, Anda dapat menggunakan/me/taggable_friendsAPI. Penggunaan titik akhir ini membutuhkan peninjauan oleh Facebook dan hanya boleh digunakan untuk kasus di mana Anda memberikan daftar teman untuk memungkinkan pengguna menandai mereka dalam sebuah pos.

  2. Jika Aplikasi Anda adalah Game DAN Game Anda mendukung Facebook Canvas , Anda dapat menggunakan/me/invitable_friendstitik akhir untuk merender dialog undangan khusus , lalu meneruskan token yang dikembalikan oleh API ini ke Dialog Permintaan standar.

Dalam kasus lain, aplikasi tidak lagi dapat mengambil daftar lengkap teman-teman pengguna (hanya teman-teman yang secara khusus mengizinkan aplikasi Anda menggunakan user_friendsizin). Ini telah dikonfirmasi oleh Facebook sebagai 'oleh desain'.

Untuk aplikasi yang ingin memungkinkan orang mengundang teman untuk menggunakan aplikasi, Anda masih dapat menggunakan Dialog Kirim di Web atau Dialog Pesan baru di iOS dan Android .

UPDATE: Facebook telah menerbitkan FAQ tentang perubahan ini di sini: https://developers.facebook.com/docs/apps/faq yang menjelaskan semua opsi yang tersedia untuk pengembang untuk mengundang teman, dll.


Adakah berita sejak edit terakhir Anda atau kami di halaman yang sama?
Ilya Gazman

Tidak dapat melihat taggable_friendsdalam item untuk pengiriman ulasan.
AlikElzin-kilaka

7
Saya tidak mengerti mengapa mereka harus membatasi sebanyak ini. Maksud saya sistem lama terlalu kasar tetapi yang ini tidak berguna. Melihat profil publik dari semua teman Anda tentu bukan masalah privasi. Kecuali jika Anda berpikir bahwa hubungan pertemanan itu bersifat pribadi (tetapi mengapa tidak dalam kasus teman yang dapat taggable). Ini bukan langkah untuk membatasi penyalahgunaan privasi yang merupakan efek samping, mereka ingin menutup kemampuan pengembang normal (yang tidak berafiliasi facebook) untuk mengembangkan bisnis mereka menggunakan data facebook.
Daniel Sharp

3
Facebook baru-baru ini menerbitkan perubahan besar pada data yang tersedia: lihat changelog . The taggable_friendssekarang mengembalikan apa-apa. Juga, tinjauan login diperlukan sebelum Anda dapat user_friendsizin.
Duncan Jones

Apa gunanya menyediakan API jika tidak memungkinkan Anda melakukan tugas dasar seperti mendaftar teman?
6infinity8

17

Meskipun jawaban Simon Cross diterima dan benar, saya pikir saya akan menambahkannya sedikit dengan contoh (Android) tentang apa yang perlu dilakukan. Saya akan menjaganya agar tetap umum dan fokus hanya pada pertanyaan. Secara pribadi saya akhirnya menyimpan hal-hal dalam database sehingga pemuatannya lancar, tetapi itu membutuhkan CursorAdapter dan ContentProvider yang sedikit keluar dari ruang lingkup di sini.

Saya datang ke sini sendiri dan kemudian berpikir, sekarang apa ?!

Masalah

Sama seperti user3594351 , saya memperhatikan bahwa data teman itu kosong. Saya menemukan ini dengan menggunakan FriendPickerFragment. Apa yang berhasil tiga bulan lalu, tidak lagi berhasil. Bahkan contoh-contoh Facebook pecah. Jadi masalah saya adalah 'Bagaimana Saya membuat FriendPickerFragment dengan tangan?

Apa yang Tidak Berhasil

Opsi # 1 dari Simon Cross tidak cukup kuat untuk mengundang teman ke aplikasi. Simon Cross juga merekomendasikan Dialog Permintaan, tetapi itu hanya akan memungkinkan lima permintaan sekaligus. Dialog permintaan juga menunjukkan teman yang sama selama sesi login Facebook yang diberikan. Tidak berguna.

Apa yang Bekerja (Ringkasan)

Opsi # 2 dengan kerja keras. Anda harus memastikan Anda memenuhi aturan baru Facebook: 1.) Anda adalah game 2.) Anda memiliki aplikasi Canvas (Keberadaan Web) 3.) Aplikasi Anda terdaftar di Facebook. Itu semua dilakukan di situs web pengembang Facebook di bawah Pengaturan .

Untuk meniru pemetik teman dengan tangan di dalam aplikasi saya, saya melakukan hal berikut:

  1. Buat aktivitas tab yang menampilkan dua fragmen. Setiap fragmen menunjukkan daftar. Satu fragmen untuk teman yang tersedia ( / saya / teman ) dan lainnya untuk teman yang invitable ( / me / invitable_friends ). Gunakan kode fragmen yang sama untuk merender kedua tab.
  2. Buat AsyncTask yang akan mendapatkan data teman dari Facebook. Setelah data dimuat, lemparkan ke adaptor yang akan memberikan nilai ke layar.

Detail

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

Kelas FacebookFriend yang saya buat

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
Bagaimana dengan aplikasi non-game? Situs web kencan ... permainan untuk menemukan orang, aplikasi untuk menemukan restoran ... permainan untuk menemukan restoran, dll. Anda mendapatkan idenya. Jadi apakah ini BENAR-BENAR dekat dengan game atau ini hanya cara memaksa Anda untuk menempatkan aplikasi di Facebook dan menghabiskan uang di platform iklan mereka? Siapa yang akan memutuskan game apa itu? Siapa yang memutuskan bahwa aplikasi Anda sebenarnya adalah permainan atau bukan? Jangan salah paham dalam hal ini, tetapi bagi saya tidak masuk akal untuk memblokir aplikasi non-game kecuali Anda hanya ingin memaksa mereka untuk menggunakan ekosistem facebook.
Mário

@ Mario Itu maksud Facebook di bawah tenda. Anda dapat meletakkan apa saja dan menandainya sebagai game karena mereka tidak peduli apakah itu benar-benar game atau bukan. yang mereka pedulikan hanyalah mendapatkan uang dari kantong Anda.
sandalone

12

Facebook telah merevisi kebijakan mereka sekarang. Anda tidak bisa mendapatkan seluruh daftar teman jika aplikasi Anda tidak memiliki implementasi Canvas dan jika aplikasi Anda bukan game. Tentu saja ada juga taggable_friends, tetapi itu hanya untuk pemberian tag.

Anda akan dapat menarik daftar teman yang telah mengotorisasi aplikasi saja.

Aplikasi yang menggunakan Graph API 1.0 akan bekerja hingga 30 April 2015 dan setelah itu akan ditinggalkan.

Lihat yang berikut untuk mendapatkan detail lebih lanjut tentang ini:


3

Di Swift 4.2 dan Xcode 10.1:

Jika Anda ingin mendapatkan daftar teman dari Facebook, Anda harus mengirimkan aplikasi Anda untuk ditinjau di Facebook. Lihat beberapa Izin Masuk:

Izin Masuk

Inilah dua langkah:

1) Pertama status aplikasi Anda harus dalam Live

2) Dapatkan izin yang diperlukan dari Facebook.

1) Aktifkan status aplikasi kami secara langsung:

  1. Buka halaman aplikasi dan pilih aplikasi Anda

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

  2. Pilih status di kanan atas di Dasbor .

    Masukkan deskripsi gambar di sini

  3. Kirim URL kebijakan privasi

    Masukkan deskripsi gambar di sini

  4. Pilih kategori

    Masukkan deskripsi gambar di sini

  5. Sekarang aplikasi kami dalam status Live .

    Masukkan deskripsi gambar di sini

Satu langkah selesai.

2) Kirim aplikasi kami untuk ditinjau:

  1. Pertama kirim permintaan yang diminta.

    Contoh: user_friends, user_videos, user_posts, dll.

    Masukkan deskripsi gambar di sini

  2. Kedua, buka halaman Permintaan Saat Ini

    Masukkan deskripsi gambar di sini

    Contoh: user_events

  3. Kirim semua detail

    Masukkan deskripsi gambar di sini

  4. Seperti ini kirimkan untuk semua permintaan (user_friends, user_events, user_videos, user_posts, dll.).

  5. Akhirnya kirimkan aplikasi Anda untuk ditinjau.

    Jika ulasan Anda diterima dari sisi Facebook, Anda sekarang berhak membaca kontak, dll.


3
The user_friendsizin sangat terbatas. Dari dokumentasi Facebook (April, 2019): [Ini hanya] memberikan izin aplikasi untuk mengakses daftar teman yang juga menggunakan aplikasi tersebut. Izin ini terbatas untuk mitra terbatas dan penggunaannya memerlukan persetujuan terlebih dahulu oleh Facebook. Agar seseorang dapat muncul di daftar teman orang lain, kedua orang harus telah berbagi daftar teman mereka dengan aplikasi dan tidak menonaktifkan izin ini saat login.
dearsina

2

Seperti yang Simon katakan, ini tidak mungkin di Facebook API baru. Murni secara teknis Anda dapat melakukannya melalui otomatisasi browser.

  • ini melanggar kebijakan Facebook, jadi tergantung pada negara tempat Anda tinggal, ini mungkin tidak sah
  • Anda harus menggunakan kredensial Anda / meminta kredensial pengguna dan mungkin menyimpannya (menyimpan kata sandi yang bahkan dienkripsi secara simetris bukanlah ide yang baik)
  • ketika Facebook mengubah API mereka, Anda juga harus memperbarui kode otomatisasi browser (jika Anda tidak dapat memaksa pembaruan aplikasi Anda, Anda harus mengesampingkan otomatisasi browser sebagai layanan web)
  • ini melewati konsep OAuth
  • di sisi lain, perasaan saya adalah bahwa saya memiliki data saya termasuk daftar teman-teman saya dan Facebook tidak boleh membatasi saya mengaksesnya melalui API

Implementasi sampel menggunakan 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;
}

Prototipe dengan implementasi pendekatan ini (menggunakan C # / WatiN) lihat https://github.com/svejdo1/ShadowApi . Hal ini juga memungkinkan pembaruan dinamis dari konektor Facebook yang mengambil daftar kontak Anda.


2
Kode Anda mengasumsikan bahwa aplikasi memiliki akses ke nama pengguna dan kata sandi pengguna. Ini bukan cara kerja OAuth, dan sebagian besar pengguna tidak akan memberikan nama pengguna dan kata sandi FB mereka ke suatu aplikasi. Itu akan menjadi risiko keamanan yang sangat besar.
jbustamovej

32
Ini bertentangan dengan kebijakan Facebook. Nasihat ini tidak harus diikuti.
Simon Cross

3
Pada catatan lain, Anda bahkan tidak aman menjaga kredensial pengguna dalam peretasan Anda. Untuk berjaga-jaga jika seseorang memutuskan untuk menggunakan kode Anda, harap pastikan ia menggunakan SSL dengan mengubah uri menjadi https.
Rogala

8
Plus satu untuk mendorong wajah mereka!
Skynet

12
Anda semua terdengar seperti kebijakan Facebook adalah semacam Hukum Internasional dan dengan melanggar itu Anda adalah penjahat. Anda juga berpikir Facebook hanya memberikan yang terbaik bagi pengguna, yang menurut saya salah seperti yang dikatakan oleh @OndrejSvejdar, karena dengan begitu mereka akan membiarkan Anda memilih jika Anda ingin dilihat di aplikasi lain. Saya pikir ini hanya langkah oleh Facebook untuk mengganggu pertumbuhan orang lain melalui platform mereka secara GRATIS. Sebaliknya orang-orang harus mulai mengembangkan aplikasi, layanan, game, berita dll langsung di Facebook mereka. Dan bayar untuk iklan Facebook jika mereka tidak mau.
JustGoscha

2

Coba /me/taggable_friends?limit=5000gunakan kode JavaScript Anda

Atau

coba Grafik API :

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


2
Seperti yang saya pikirkan - downvotes di sini adalah karena "Penggunaan titik akhir ini membutuhkan peninjauan oleh Facebook dan hanya boleh digunakan untuk kasus di mana Anda membuat daftar teman untuk membiarkan pengguna menandai mereka dalam sebuah posting." Anda dapat membaca lebih lanjut tentang ini di jawaban yang dipilih.
moonvader

{"data": [], "ringkasan": {"total_count": 414}} saya mendapat blok data json ini nol tidak mendapat teman. Apa yang dapat saya?
Makvin

-1

Di Facebook SDK Graph API v2.0 atau lebih tinggi, Anda harus meminta izin user_friends dari setiap pengguna saat login Facebook karena user_friends tidak lagi disertakan secara default di setiap login; kita harus menambahkan itu.

Setiap pengguna harus memberikan izin kepada user_friends agar dapat muncul dalam respons terhadap / saya / teman .

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 {
        }
    }
}

Jadi pada saat login Facebook, ia meminta dengan layar yang berisi semua izin:

Masukkan deskripsi gambar di sini

Jika pengguna menekan tombol Lanjutkan , izin akan ditetapkan. Saat Anda mengakses daftar teman menggunakan Graph API, teman Anda yang masuk ke aplikasi seperti di atas akan terdaftar

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

            print(result!)
        }
    })
}

Output akan berisi pengguna yang memberikan izin user_friends pada saat masuk ke aplikasi Anda melalui Facebook.

{
    data = (
             {
                 id = xxxxxxxxxx;
                 name = "xxxxxxxx";
             }
           );
    paging = {
        cursors = {
            after = xxxxxx;
            before = xxxxxxx;
        };
    };
    summary = {
        "total_count" = 8;
    };
}
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.