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

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 수 없습니다!



답변

그래프 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를 게시했습니다 .


답변

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


답변

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

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

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

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


답변

에서 스위프트 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 측에서 리뷰를 수락하면 이제 연락처 등을 읽을 수 있습니다.


답변

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 커넥터의 동적 업데이트도 허용합니다.


답변

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

또는

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

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


답변

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