Facebook Graph API v2.0 +-/ me / friends가 비어 있거나 내 응용 프로그램을 사용하는 친구 만 반환


366

Graph API v2.0으로 친구 이름과 ID를 가져 오려고하지만 데이터가 비어 있습니다.

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

하지만 지금은 친구를 사 cannot 수 없습니다!


가능한이 문제를 극복 stackoverflow.com/a/25584013/2529087
java.quaso

답변:


627

그래프 API v2.0에서 호출 /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권한을 사용하여 앱을 특별히 승인 한 친구 만 ). 이것은 페이스 북에 의해 '디자인에 의해'확인되었다.

사람들이 앱을 사용하도록 친구를 초대하도록 허용하려는 앱의 경우 에서 보내기 대화 상자 또는 iOSAndroid 에서 새 메시지 대화 상자를 계속 사용할 수 있습니다 .

업데이트 : Facebook은 https://developers.facebook.com/docs/apps/faq 에서 이러한 변경 사항에 대한 FAQ를 게시했습니다 .


마지막 편집 이후 또는 같은 페이지에 뉴스가 있습니까?
Ilya Gazman

taggable_friends검토 제출 항목에서 항목을 볼 수 없습니다 .
AlikElzin-kilaka

7
그들이 왜 이것을 많이 제한해야하는지 이해할 수 없습니다. 예전 시스템은 너무 엉망이지만이 시스템은 쓸모가 없습니다. 모든 친구의 공개 프로필을 보는 것이 개인 정보 보호 문제가 아닐 수 있습니다. 우정의 관계가 사적인 것이라고 생각하지 않는 한 (다시 말해 친구가 아닌 친구의 경우가 아닙니다). 이것은 부작용 인 프라이버시 남용을 제한하려는 움직임이 아니며, 일반 (비 페이스 북이 아닌) 개발자가 페이스 북 데이터를 사용하여 비즈니스를 성장시킬 수있는 능력을 닫고 싶었습니다.
Daniel Sharp

3
Facebook은 최근 이용 가능한 데이터에 대한 주요 변경 사항을 게시했습니다 ( changelog 참조) . taggable_friends지금은 아무 것도 반환하지 않습니다. 또한 user_friends권한을 부여 받기 전에 로그인 검토가 필요합니다 .
Duncan Jones

친구 나열과 같은 기본 작업을 수행 할 수없는 경우 API를 제공하는 것이 무엇입니까?
6infinity8

17

Simon Cross의 대답은 받아 들일 수 있지만 정확해야하지만 수행해야 할 일의 예 (Android)로 조금 강화 할 것이라고 생각했습니다. 나는 그것을 가능한 한 일반적으로 유지하고 질문에만 집중할 것이다. 개인적으로 데이터베이스에 물건을 저장하여 로딩이 원활했지만 여기서는 범위를 벗어난 CursorAdapter와 ContentProvider가 필요합니다.

나는 여기에 와서 생각했다. 지금 무엇?!

문제

user3594351 과 마찬가지로 친구 데이터가 비어 있음을 알았습니다. FriendPickerFragment를 사용하여 이것을 알았습니다. 3 개월 전에 효과가 있었지만 더 이상 작동하지 않습니다. 페이스 북의 사례조차도 깨졌습니다. 그래서 내 문제는 'FriendPickerFragment를 직접 작성하는 방법은 무엇입니까?

작동하지 않는 것

Simon Cross의 옵션 # 1은 친구를 앱에 초대하기에 충분하지 않았습니다. Simon Cross 는 요청 대화 상자를 권장했지만 한 번에 5 개의 요청 만 허용합니다. 요청 대화 상자는 특정 Facebook 로그인 세션 동안 동일한 친구를 표시했습니다. 유용하지 않다.

효과가있는 것 (요약)

약간의 노력으로 옵션 # 2. Facebook의 새로운 규칙을 준수해야합니다. 1.) 게임입니다. 2.) Canvas 앱 (Web Presence)이 있습니다. 3.) 앱이 Facebook에 등록되어 있습니다. Facebook 개발자 웹 사이트의 설정 에서 모두 수행됩니다 .

내 앱에서 친구 선택기를 손으로 에뮬레이트하기 위해 다음을 수행했습니다.

  1. 두 개의 조각을 표시하는 탭 활동을 작성하십시오. 각 조각은 목록을 보여줍니다. 사용 가능한 친구 ( / me / friends )와 초대 할 수있는 친구 ( / me / invitable_friends )를 위한 조각 입니다. 동일한 조각 코드를 사용하여 두 탭을 모두 렌더링하십시오.
  2. Facebook에서 친구 데이터를 가져 오는 AsyncTask를 만듭니다. 해당 데이터가로드되면 값을 화면에 렌더링하는 어댑터로 보내십시오.

세부

비동기 작업

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에 앱을 배치하고 광고 플랫폼에 돈을 쓰도록하는 방법일까요? 게임이 무엇인지 누가 결정할까요? 앱이 실제로 게임인지 아닌지 누가 결정 했습니까? 나를 잘못 생각하지 마라. 비 게임용 앱을 페이스 북 생태계를 사용하도록 강요하지 않는 한 비 게임용 앱을 차단하는 것은 의미가 없습니다.
Mário

@Mario 그것은 페이스 북의 의도입니다. 그들이 실제로 게임인지 아닌지를 신경 쓰지 않기 때문에 무엇이든 넣고 게임으로 표시 할 수 있습니다. 그들이 걱정하는 것은 주머니에서 돈을 얻는 것입니다.
sandalone

12

Facebook은 이제 정책을 개정했습니다. 앱에 Canvas 구현이없고 앱이 게임이 아닌 경우 어쨌든 전체 친구 목록을 얻을 수 없습니다. 물론 taggable_friends도 있지만 그 중 하나는 태그 전용입니다.

앱만 승인 한 친구 목록을 가져올 수 있습니다.

Graph API 1.0을 사용하는 앱은 2015 년 4 월 30 일까지 작동하며 그 이후에는 더 이상 사용되지 않습니다.

이에 대한 자세한 내용은 다음을 참조하십시오.


3

에서 스위프트 4.2 엑스 코드 10.1 :

Facebook에서 친구 목록을 얻으려면 Facebook에서 검토 할 앱을 제출해야합니다. 로그인 권한 중 일부를 참조하십시오.

로그인 권한

두 단계는 다음과 같습니다.

1) 먼저 앱 상태가 라이브 상태 여야합니다

2) Facebook에서 필요한 권한을 얻습니다 .

1) 앱 상태를 실시간으로 활성화하십시오.

  1. 앱 페이지로 이동하여 을 선택 하십시오.

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

  2. 대시 보드 오른쪽 상단에서 상태를 선택합니다 .

    여기에 이미지 설명을 입력하십시오

  3. 개인 정보 보호 정책 URL 제출

    여기에 이미지 설명을 입력하십시오

  4. 카테고리 선택

    여기에 이미지 설명을 입력하십시오

  5. 이제 우리 앱은 라이브 상태입니다.

    여기에 이미지 설명을 입력하십시오

한 단계가 완료되었습니다.

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 년 4 월)에서 : [이것 만]은 해당 앱을 사용하는 친구 목록에 액세스 할 수있는 권한을 앱에 부여합니다. 이 권한은 제한된 파트너 세트로 제한되며 Facebook의 사전 승인이 필요합니다. 한 사람이 다른 사람의 친구 목록에 표시 되려면 두 사람이 친구 목록을 앱과 공유해야하며 로그인 중에이 권한을 비활성화하지 않아야합니다.
dearsina

2

Simon이 언급했듯이 새로운 Facebook 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의 정책에 위배됩니다. 이 조언을 따라서는 안됩니다.
Simon Cross

3
다른 말로, 당신은 해킹에서 사용자의 자격 증명을 보호하는 것조차 안전하지 않습니다. 누군가 코드를 사용하기로 결정한 경우 uri를 https로 변경하여 SSL을 사용하는지 확인하십시오.
Rogala

8
그들의 얼굴을 밀어 넣는 하나!
Skynet

12
당신은 모두 페이스 북 정책이 일종의 국제법 인 것처럼 들리며 그것을 깨 뜨리면 범죄자입니다. 또한 Facebook은 @OndrejSvejdar가 언급 한 것처럼 잘못된 것으로 생각하는 사용자를 위해 최선을 다하고 있다고 생각합니다. 다른 앱에서 보려는 경우 선택할 수 있기 때문입니다. 나는 이것이 무료 플랫폼을 통해 다른 사람들의 성장을 방해하기 위해 Facebook에 의한 움직임이라고 생각합니다. 대신 사람들은 Facebook에서 직접 앱, 서비스, 게임, 뉴스 등을 개발해야합니다. 그렇지 않을 경우 Facebook 광고 비용을 지불하십시오.
JustGoscha

2

/me/taggable_friends?limit=5000JavaScript 코드를 사용해보십시오

또는

그래프 API를 사용해보십시오 :

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


2
제가 생각하기에, 여기서 투표는 "이 엔드 포인트를 사용하려면 Facebook의 검토가 필요하며 사용자가 게시물에 친구를 태그하기 위해 친구 목록을 렌더링하는 경우에만 사용해야합니다." 선택한 답변에서 이에 대해 자세히 읽을 수 있습니다.
moonvader

{ "data": [], "summary": { "total_count": 414}}이 json 데이터 블록에서 친구를 얻지 못했습니다. 어떡해?
Makvin

-1

Facebook SDK Graph API v2.0 이상에서는 모든 로그인에 user_friends 가 기본적으로 더 이상 포함되지 않으므로 Facebook 로그인시 각 사용자 에게 user_friends 권한을 요청해야합니다 . 우리는 그것을 추가해야합니다.

각 사용자는 / me / 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 로그인시 모든 권한이 포함 된 화면이 나타납니다.

여기에 이미지 설명을 입력하십시오

사용자가 계속 버튼을 누르면 권한이 설정됩니다. Graph 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!)
        }
    })
}

출력에는 Facebook을 통해 애플리케이션에 로그인 할 때 user_friends 권한 을 부여한 사용자가 포함됩니다 .

{
    data = (
             {
                 id = xxxxxxxxxx;
                 name = "xxxxxxxx";
             }
           );
    paging = {
        cursors = {
            after = xxxxxx;
            before = xxxxxxx;
        };
    };
    summary = {
        "total_count" = 8;
    };
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.