Retrieving friends birthdays from Facebook Graph API [duplicate] - python
I am trying to get my friend name and ids with Graph API v2.0, but data returns empty:
{
"data": [
]
}
When I was using v1.0, everything was OK with the following request:
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);
}
}];
But now I cannot get friends!
In v2.0 of the Graph API, calling /me/friends returns the person's friends who also use the app.
In addition, in v2.0, you must request the user_friends permission from each user. user_friends is no longer included by default in every login. Each user must grant the user_friends permission in order to appear in the response to /me/friends. See the Facebook upgrade guide for more detailed information, or review the summary below.
If you want to access a list of non-app-using friends, there are two options:
If you want to let your people tag their friends in stories that they publish to Facebook using your App, you can use the /me/taggable_friends API. Use of this endpoint requires review by Facebook and should only be used for the case where you're rendering a list of friends in order to let the user tag them in a post.
If your App is a Game AND your Game supports Facebook Canvas, you can use the /me/invitable_friends endpoint in order to render a custom invite dialog, then pass the tokens returned by this API to the standard Requests Dialog.
In other cases, apps are no longer able to retrieve the full list of a user's friends (only those friends who have specifically authorized your app using the user_friends permission). This has been confirmed by Facebook as 'by design'.
For apps wanting allow people to invite friends to use an app, you can still use the Send Dialog on Web or the new Message Dialog on iOS and Android.
UPDATE: Facebook have published an FAQ on these changes here: https://developers.facebook.com/docs/apps/faq which explain all the options available to developers in order to invite friends etc.
Although Simon Cross's answer is accepted and correct, I thought I would beef it up a bit with an example (Android) of what needs to be done. I'll keep it as general as I can and focus on just the question. Personally I wound up storing things in a database so the loading was smooth, but that requires a CursorAdapter and ContentProvider which is a bit out of scope here.
I came here myself and then thought, now what?!
The Issue
Just like user3594351, I was noticing the friend data was blank. I found this out by using the FriendPickerFragment. What worked three months ago, no longer works. Even Facebook's examples broke. So my issue was 'How Do I create FriendPickerFragment by hand?
What Did Not Work
Option #1 from Simon Cross was not strong enough to invite friends to the app. Simon Cross also recommended the Requests Dialog, but that would only allow five requests at a time. The requests dialog also showed the same friends during any given Facebook logged in session. Not useful.
What Worked (Summary)
Option #2 with some hard work. You must make sure you fulfill Facebook's new rules: 1.) You're a game 2.) You have a Canvas app (Web Presence) 3.) Your app is registered with Facebook. It is all done on the Facebook developer website under Settings.
To emulate the friend picker by hand inside my app I did the following:
Create a tab activity that shows two fragments. Each fragment shows a list. One fragment for available friend (/me/friends) and another for invitable friends (/me/invitable_friends). Use the same fragment code to render both tabs.
Create an AsyncTask that will get the friend data from Facebook. Once that data is loaded, toss it to the adapter which will render the values to the screen.
Details
The 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);
}
}
}
The FacebookFriend class I created
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 has revised their policies now. You can’t get the whole friendlist anyway if your app does not have a Canvas implementation and if your app is not a game. Of course there’s also taggable_friends, but that one is for tagging only.
You will be able to pull the list of friends who have authorised the app only.
The apps that are using Graph API 1.0 will be working till April 30th, 2015 and after that it will be deprecated.
See the following to get more details on this:
User Friends
Facebook Application Development FAQ
In Swift 4.2 and Xcode 10.1:
If you want to get the friends list from Facebook, you need to submit your app for review in Facebook. See some of the Login Permissions:
Login Permissions
Here are the two steps:
1) First your app status is must be in Live
2) Get required permissions form Facebook.
1) Enable our app status live:
Go to the apps page and select your app
https://developers.facebook.com/apps/
Select status in the top right in Dashboard.
Submit privacy policy URL
Select category
Now our app is in Live status.
One step is completed.
2) Submit our app for review:
First send required requests.
Example: user_friends, user_videos, user_posts, etc.
Second, go to the Current Request page
Example: user_events
Submit all details
Like this submit for all requests (user_friends , user_events, user_videos, user_posts, etc.).
Finally submit your app for review.
If your review is accepted from Facebook's side, you are now eligible to read contacts, etc.
As Simon mentioned, this is not possible in the new Facebook API. Pure technically speaking you can do it via browser automation.
this is against Facebook policy, so depending on the country where you live, this may not be legal
you'll have to use your credentials / ask user for credentials and possibly store them (storing passwords even symmetrically encrypted is not a good idea)
when Facebook changes their API, you'll have to update the browser automation code as well (if you can't force updates of your application, you should put browser automation piece out as a webservice)
this is bypassing the OAuth concept
on the other hand, my feeling is that I'm owning my data including the list of my friends and Facebook shouldn't restrict me from accessing those via the API
Sample implementation using 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;
}
Prototype with implementation of this approach (using C#/WatiN) see https://github.com/svejdo1/ShadowApi. It is also allowing dynamic update of Facebook connector that is retrieving a list of your contacts.
Try /me/taggable_friends?limit=5000 using your JavaScript code
Or
try the Graph API:
https://graph.facebook.com/v2.3/user_id_here/taggable_friends?access_token=
If you are still struggling with this issue on a development mode.
Follow the same process as mentioned below:
create a test app of your main app,
create test users, automatically install app for test users and assign them 'user_friend' permission.
Add your test users as a friend with each other.
I followed the same process after going through alot of research and finally it worked.
In the Facebook SDK Graph API v2.0 or above, you must request the user_friends permission from each user in the time of Facebook login since user_friends is no longer included by default in every login; we have to add that.
Each user must grant the user_friends permission in order to appear in the response to /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 {
}
}
}
So at the time of Facebook login, it prompts with a screen which contain all the permissions:
If the user presses the Continue button, the permissions will be set. When you access the friends list using Graph API, your friends who logged into the application as above will be listed
if ((FBSDKAccessToken.current()) != nil) {
FBSDKGraphRequest(graphPath: "/me/friends", parameters: ["fields" : "id,name"]).start(completionHandler: { (connection, result, error) -> Void in
if (error == nil) {
print(result!)
}
})
}
The output will contain the users who granted the user_friends permission at the time of login to your application through Facebook.
{
data = (
{
id = xxxxxxxxxx;
name = "xxxxxxxx";
}
);
paging = {
cursors = {
after = xxxxxx;
before = xxxxxxx;
};
};
summary = {
"total_count" = 8;
};
}
Related
Saving Longitude and Latitude to a user profile in Django
I was looking for a way to use HTML5 (and possibly JS) to save visitor/user Longitudnal & Latitudnal data to a database. I do not wish to use packages out there as they seem a bit outdated and may break my code in future considerting their own reliance on other APIs. I know there is a way around using AJAX, but I clearly dont know and understand it well enough to implement it. My ask of the learned Lords is - 1. Get Loc data 2. Send it to Python in dict or json or string format from where it can be further processed and saved. Why you may ask - Good question. I would use it for displaying weather on the homepage and local twitter trends on a 'logged-in' page. Any assistance would be appreciated. Cheers! My JS code is below: // Set up global variable var result; function showPosition() { // Store the element where the page displays the result result = document.getElementById("result"); // If geolocation is available, try to get the visitor's position if (navigator.geolocation) { navigator.geolocation.getCurrentPosition(successCallback, errorCallback); result.innerHTML = "Getting the position information..."; } else { alert("Sorry, your browser does not support HTML5 geolocation."); } }; // Define callback function for successful attempt function successCallback(position) { result.innerHTML = [position.coords.latitude, position.coords.longitude]; } // Define callback function for failed attempt function errorCallback(error) { if (error.code == 1) { result.innerHTML = "You've decided not to share your position, but it's OK. We won't ask you again."; } else if (error.code == 2) { result.innerHTML = "The network is down or the positioning service can't be reached."; } else if (error.code == 3) { result.innerHTML = "The attempt timed out before it could get the location data."; } else { result.innerHTML = "Geolocation failed due to unknown error."; } } window.onload = showPosition;
what works for me: First I recommend you to use models.PointField on your model. When I obtain the long/lat data on FE, I send it as form-data in the following format eg: "{\"type\":\"Point\",\"coordinates\":[14.215641,50.0100000001]}" Then I map it to the model field and save it. It saves well and later I am able to query google geocoder or anything with it.
In your JS code: function successCallback(position) { result.innerHTML = [position.coords.latitude, position.coords.longitude]; $.post('your-python-endpoint-url', { latitude: position.coords.latitude, longitude: position.coords.longitude }); } In your python: def index(request): if request.is_ajax(): if request.method == 'POST': print 'Raw Data: "%s"' % request.body return HttpResponse("OK") Change the method name and body according to your needs and don't forget to define a route in django.
How to delete a user's facebook data from firebase with firebase admin?
I'm using firebase UI to authenticate users in a given frontend. Facebook authentication is enabled. I need to implement a facebook data deletion callback so I need to make my backend do two things: delete/disable the facebook sign in method from the user that issued the data deletion request from facebook delete every trace of facebook data from my firebase user (the provider user info) but without deleting the user However, I can't find anything in firebase admin's documentation to delete facebook data. So, how can I delete the data? PD: Keep in mind that I want to delete the user's provider user info, but not the whole user (because I need the user to stay there for data consistency)
If someone is looking for a NodeJS implementation, this is how you can do it: module.exports = functions.https.onRequest(async (req, res) => { try { const signedRequest = req.body.signed_request; const userObj = parseSignedRequest(signedRequest, FB_SECRET_KEY); const userRecord = await admin .auth() .getUserByProviderUid("facebook.com", userObj.user_id); await admin.auth().deleteUser(userRecord.uid); res.json({ url: "<status_url>", confirmation_code: "<code>", }); } catch (e) { // console.log(e); res.status(400).json({ message: "Bad Request", }); } }); function base64decode(data: string) { while (data.length % 4 !== 0) { data += "="; } data = data.replace(/-/g, "+").replace(/_/g, "/"); return Buffer.from(data, "base64").toString("utf-8"); } function parseSignedRequest(signedRequest: string, secret: string) { var encoded_data = signedRequest.split(".", 2); // decode the data var sig = encoded_data[0]; var json = base64decode(encoded_data[1]); var data = JSON.parse(json); if (!data.algorithm || data.algorithm.toUpperCase() != "HMAC-SHA256") { throw Error( "Unknown algorithm: " + data.algorithm + ". Expected HMAC-SHA256" ); } var expected_sig = crypto .createHmac("sha256", secret) .update(encoded_data[1]) .digest("base64") .replace(/\+/g, "-") .replace(/\//g, "_") .replace("=", ""); if (sig !== expected_sig) { throw Error("Invalid signature: " + sig + ". Expected " + expected_sig); } return data; } PS. There is no way to just unlink providers via Firebase Admin SDK for now so best we can do is delete the user data.
firebase_admin prints None but I have data in db and permission is allow all [duplicate]
I have a chat app using Firebase that keeps on having a setValue at x failed: DatabaseError: permission denied error every time I type a message. I set my Database to be public already: service cloud.firestore { match /databases/{database}/documents { match /{allPaths=**} { allow read, write: if request.auth.uid != null; } } } Is it something from within my chat reference? private void displayChat() { ListView listOfMessage = findViewById(R.id.list_of_message); Query query = FirebaseDatabase.getInstance().getReference(); FirebaseListOptions<Chat> options = new FirebaseListOptions.Builder<Chat>() .setLayout(R.layout.list_item) .setQuery(query, Chat.class) .build(); adapter = new FirebaseListAdapter<Chat>(options) { #Override protected void populateView(View v, Chat model, int position) { //Get reference to the views of list_item.xml TextView messageText, messageUser, messageTime; messageText = v.findViewById(R.id.message_text); messageUser = v.findViewById(R.id.message_user); messageTime = v.findViewById(R.id.message_time); messageText.setText(model.getMessageText()); messageUser.setText(model.getMessageUser()); messageTime.setText(DateFormat.format("dd-MM-yyyy (HH:mm:ss)", model.getMessageTime())); } }; listOfMessage.setAdapter(adapter); }
Your code is using the Firebase Realtime Database, but you're changing the security rules for Cloud Firestore. While both databases are part of Firebase, they are completely different and the server-side security rules for one, don't apply to the other. When you go the database panel in the Firebase console, you most likely end up in the Cloud Firestore rules: If you are on the Cloud Firestore rules in the Firebase console, you can change to the Realtime Database rules by clicking Cloud Firestore BETA at the top, and then selecting Realtime Database from the list. You can also directly go to the security rules for the Realtime Database, by clicking this link. The security rules for the realtime database that match what you have are: { "rules": { ".read": "auth.uid !== null", ".write": "auth.uid !== null" } } This will grant any authenticated user full read and write access to the entire database. Read my answer to this question on more on the security/risk trade-off for such rules: Firebase email saying my realtime database has insecure rules.
change this request.auth.uid != null to request.auth.uid == null or defined a proper auth mechanism before starting the conversation where user defined by userID
loop in GCP datastore (NDB)
How to loop through entities in GCP datastore ? We would like to loop each user in the datastore and update based on it's status.
Use Datastore Queries to achieve this. Link to Documentation
If you are using node js, try some like this : datastore.runQuery(query, (err,entities) => { var searches = []; if(typeof entities !== 'undefined' && entities.length > 0) { var keys = entities.map(function(entity) { searches.push(entity); }); //Setting the response object response.status="OK"; response.message=""; response.data={ "searches": searches }; }else{ response.status="OK"; response.message="Empty result"; } //Returning the response to client res.status(200).send(JSON.stringify(response)); });
Python - Facebook API, messing around [duplicate]
I am trying to get my friend name and ids with Graph API v2.0, but data returns empty: { "data": [ ] } When I was using v1.0, everything was OK with the following request: 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); } }]; But now I cannot get friends!
In v2.0 of the Graph API, calling /me/friends returns the person's friends who also use the app. In addition, in v2.0, you must request the user_friends permission from each user. user_friends is no longer included by default in every login. Each user must grant the user_friends permission in order to appear in the response to /me/friends. See the Facebook upgrade guide for more detailed information, or review the summary below. If you want to access a list of non-app-using friends, there are two options: If you want to let your people tag their friends in stories that they publish to Facebook using your App, you can use the /me/taggable_friends API. Use of this endpoint requires review by Facebook and should only be used for the case where you're rendering a list of friends in order to let the user tag them in a post. If your App is a Game AND your Game supports Facebook Canvas, you can use the /me/invitable_friends endpoint in order to render a custom invite dialog, then pass the tokens returned by this API to the standard Requests Dialog. In other cases, apps are no longer able to retrieve the full list of a user's friends (only those friends who have specifically authorized your app using the user_friends permission). This has been confirmed by Facebook as 'by design'. For apps wanting allow people to invite friends to use an app, you can still use the Send Dialog on Web or the new Message Dialog on iOS and Android. UPDATE: Facebook have published an FAQ on these changes here: https://developers.facebook.com/docs/apps/faq which explain all the options available to developers in order to invite friends etc.
Although Simon Cross's answer is accepted and correct, I thought I would beef it up a bit with an example (Android) of what needs to be done. I'll keep it as general as I can and focus on just the question. Personally I wound up storing things in a database so the loading was smooth, but that requires a CursorAdapter and ContentProvider which is a bit out of scope here. I came here myself and then thought, now what?! The Issue Just like user3594351, I was noticing the friend data was blank. I found this out by using the FriendPickerFragment. What worked three months ago, no longer works. Even Facebook's examples broke. So my issue was 'How Do I create FriendPickerFragment by hand? What Did Not Work Option #1 from Simon Cross was not strong enough to invite friends to the app. Simon Cross also recommended the Requests Dialog, but that would only allow five requests at a time. The requests dialog also showed the same friends during any given Facebook logged in session. Not useful. What Worked (Summary) Option #2 with some hard work. You must make sure you fulfill Facebook's new rules: 1.) You're a game 2.) You have a Canvas app (Web Presence) 3.) Your app is registered with Facebook. It is all done on the Facebook developer website under Settings. To emulate the friend picker by hand inside my app I did the following: Create a tab activity that shows two fragments. Each fragment shows a list. One fragment for available friend (/me/friends) and another for invitable friends (/me/invitable_friends). Use the same fragment code to render both tabs. Create an AsyncTask that will get the friend data from Facebook. Once that data is loaded, toss it to the adapter which will render the values to the screen. Details The 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); } } } The FacebookFriend class I created 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 has revised their policies now. You can’t get the whole friendlist anyway if your app does not have a Canvas implementation and if your app is not a game. Of course there’s also taggable_friends, but that one is for tagging only. You will be able to pull the list of friends who have authorised the app only. The apps that are using Graph API 1.0 will be working till April 30th, 2015 and after that it will be deprecated. See the following to get more details on this: User Friends Facebook Application Development FAQ
In Swift 4.2 and Xcode 10.1: If you want to get the friends list from Facebook, you need to submit your app for review in Facebook. See some of the Login Permissions: Login Permissions Here are the two steps: 1) First your app status is must be in Live 2) Get required permissions form Facebook. 1) Enable our app status live: Go to the apps page and select your app https://developers.facebook.com/apps/ Select status in the top right in Dashboard. Submit privacy policy URL Select category Now our app is in Live status. One step is completed. 2) Submit our app for review: First send required requests. Example: user_friends, user_videos, user_posts, etc. Second, go to the Current Request page Example: user_events Submit all details Like this submit for all requests (user_friends , user_events, user_videos, user_posts, etc.). Finally submit your app for review. If your review is accepted from Facebook's side, you are now eligible to read contacts, etc.
As Simon mentioned, this is not possible in the new Facebook API. Pure technically speaking you can do it via browser automation. this is against Facebook policy, so depending on the country where you live, this may not be legal you'll have to use your credentials / ask user for credentials and possibly store them (storing passwords even symmetrically encrypted is not a good idea) when Facebook changes their API, you'll have to update the browser automation code as well (if you can't force updates of your application, you should put browser automation piece out as a webservice) this is bypassing the OAuth concept on the other hand, my feeling is that I'm owning my data including the list of my friends and Facebook shouldn't restrict me from accessing those via the API Sample implementation using 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; } Prototype with implementation of this approach (using C#/WatiN) see https://github.com/svejdo1/ShadowApi. It is also allowing dynamic update of Facebook connector that is retrieving a list of your contacts.
Try /me/taggable_friends?limit=5000 using your JavaScript code Or try the Graph API: https://graph.facebook.com/v2.3/user_id_here/taggable_friends?access_token=
If you are still struggling with this issue on a development mode. Follow the same process as mentioned below: create a test app of your main app, create test users, automatically install app for test users and assign them 'user_friend' permission. Add your test users as a friend with each other. I followed the same process after going through alot of research and finally it worked.
In the Facebook SDK Graph API v2.0 or above, you must request the user_friends permission from each user in the time of Facebook login since user_friends is no longer included by default in every login; we have to add that. Each user must grant the user_friends permission in order to appear in the response to /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 { } } } So at the time of Facebook login, it prompts with a screen which contain all the permissions: If the user presses the Continue button, the permissions will be set. When you access the friends list using Graph API, your friends who logged into the application as above will be listed if ((FBSDKAccessToken.current()) != nil) { FBSDKGraphRequest(graphPath: "/me/friends", parameters: ["fields" : "id,name"]).start(completionHandler: { (connection, result, error) -> Void in if (error == nil) { print(result!) } }) } The output will contain the users who granted the user_friends permission at the time of login to your application through Facebook. { data = ( { id = xxxxxxxxxx; name = "xxxxxxxx"; } ); paging = { cursors = { after = xxxxxx; before = xxxxxxx; }; }; summary = { "total_count" = 8; }; }