Facebook Graph API v2.0+ - /me/friends返回空,或者只有朋友也使用我的应用程序

我试图得到我的朋友的名字和id与图形API v2.0,但数据返回空:

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

但是现在我找不到朋友了!

251180 次浏览

在Graph API的2.0版本中,调用/me/friends将返回此人的同样使用该应用程序的朋友。

此外,在2.0版本中,你必须向每个用户请求user_friends权限。user_friends不再默认包含在每次登录中。每个用户必须授予user_friends权限才能出现在/me/friends的响应中。有关更详细的信息,请参阅Facebook升级指南,或查看下面的摘要。

如果你想访问未使用应用程序的好友列表,有两个选项:

  1. 如果你想让你的人在他们使用你的应用程序发布到Facebook的故事中标记他们的朋友,你可以使用/me/taggable_friends API。这个端点的使用需要Facebook的审查,并且应该只用于呈现好友列表以便让用户在帖子中标记他们的情况。

  2. 如果你的应用是一款游戏并且你的游戏支持Facebook Canvas,你可以使用/me/invitable_friends端点来渲染一个自定义邀请对话框,然后将这个API返回的令牌传递给标准请求对话框。

在其他情况下,应用程序不再能够检索用户的朋友的完整列表(只有那些特别授权你的应用程序使用user_friends权限的朋友)。Facebook已经证实这是“故意的”。

对于希望允许人们邀请朋友使用应用程序的应用程序,您仍然可以使用网上发送对话框或新的iOS消息对话框安卓

更新:Facebook已经发布了一个关于这些变化的常见问题解答:https://developers.facebook.com/docs/apps/faq,其中解释了所有可供开发者邀请朋友等的选项。

正如Simon提到的,这在新的Facebook API中是不可能的。从技术上讲你可以通过浏览器自动化来实现。

  • 这违反了Facebook的政策,所以根据你居住的国家,这可能是不合法的
  • 您必须使用您的凭据/向用户询问凭据,并可能存储它们(存储密码,即使对称加密也不是一个好主意)
  • 当Facebook改变他们的API时,你也必须更新浏览器自动化代码(如果你不能强制更新你的应用程序,你应该把浏览器自动化作为一个web服务)
  • 这就绕过了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连接器,检索您的联系人列表。

虽然西蒙•罗斯的的答案是被接受和正确的,我想我会用一个需要做什么的例子(Android)来加强它。我会尽量概括一下,只关注这个问题。就我个人而言,我把东西存储在数据库中,所以加载很顺利,但这需要一个CursorAdapter和ContentProvider,这有点超出了这里的范围。

我自己来到这里,然后想,现在该怎么办!

这个问题

就像user3594351一样,我注意到朋友数据是空白的。我发现这是通过使用FriendPickerFragment。三个月前有用的,现在没用了。就连Facebook的例子也失败了。所以我的问题是“我如何手工创建FriendPickerFragment ?”

什么不起作用

西蒙交叉中的选项#1不足以邀请朋友到应用程序。西蒙交叉还推荐了请求对话框,但一次只允许5个请求。请求对话框还会在任何特定的Facebook登录会话中显示相同的朋友。不是有用的。

什么有效(总结)

第二种选择,需要付出一些努力。你必须确保你遵守Facebook的新规则:1)你是第二场比赛。)你有一个Canvas应用(Web Presence)你的应用已经在Facebook上注册了。这都是在Facebook开发者网站设置下完成的。

为了在我的应用程序中模拟好友选择器,我做了以下工作:

  1. 创建显示两个片段的选项卡活动。每个片段显示一个列表。一个片段用于可用的朋友(/我/朋友),另一个片段用于可邀请的朋友(/我/ invitable_friends)。使用相同的片段代码来呈现两个选项卡。
  2. 创建一个AsyncTask从Facebook获取好友数据。一旦数据被加载,将其扔给适配器,适配器将把值呈现到屏幕上。

细节

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

我创建的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日,之后将被弃用。

请参阅以下内容了解更多详细信息:

使用JavaScript代码尝试/me/taggable_friends?limit=5000

试试图形API:

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

在Facebook SDK Graph API v2.0或以上版本中,你必须在Facebook登录时向每个用户请求user_friends权限,因为默认情况下,user_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登录时,它会提示一个包含所有权限的屏幕:

Enter image description here

如果用户按下继续按钮,权限将被设置。当您使用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;
};
}

斯威夫特 4.2和Xcode 10.1中:

如果你想从Facebook获得好友列表,你需要在Facebook上提交应用进行审查。请参阅一些登录权限:

登录权限

以下是两个步骤:

1)首先你的app状态必须在Live中

2)从Facebook获取需要的权限

1)启用我们的应用状态

  1. 进入应用程序页面并选择你的应用

    https://developers.facebook.com/apps/ < / p >

  2. 选择指示板中右上角的状态。

    Enter image description here < / p >

  3. < p >提交隐私政策URL

    Enter image description here < / p >

  4. < p >选择类别

    Enter image description here < / p >

  5. 现在我们的应用程序处于生活状态。

    Enter image description here < / p >

完成了第一步。

2)提交应用进行审核:

  1. 首先发送所需的请求。

    例如:user_friends, user_videos, user_posts等。

    Enter image description here < / p >

  2. 秒,进入当前请求页面

    Enter image description here

    例如:user_events < / p >

  3. 提交所有详细信息

    Enter image description here < / p >

  4. 像这样提交所有请求(user_friends, user_events, user_videos, user_posts等)。

  5. 最后提交你的应用进行审查。

    如果你的评论被Facebook接受,你现在就有资格阅读联系人,等等

如果你仍然在开发模式下与此问题作斗争。 遵循如下所述的相同过程:

  1. 为你的主应用创建一个测试应用,
  2. 创建测试用户,自动为测试用户安装app,并为他们分配“user_friend”权限。
  3. 将测试用户添加为彼此的好友。

经过大量的研究,我遵循了同样的过程,最后它起作用了