I integrated support for Google Cast (TM) to my app. My app has own user agent. I block other user agents on the server side. I found that when media is played on Android TV via Google Cast (TM) client uses user agent as a browser. Is it possible to set user agent for RemoteMediaClient and MediaMetaData?
private void loadRemoteMedia(boolean autoPlay) {
if (mCastSession == null) {
return;
}
RemoteMediaClient remoteMediaClient = mCastSession.getRemoteMediaClient();
if (remoteMediaClient == null) {
return;
}
remoteMediaClient.load(buildMediaInfo(), autoPlay);
}
private MediaInfo buildMediaInfo() {
MediaMetadata mediaMetadata = new MediaMetadata(MediaMetadata.MEDIA_TYPE_TV_SHOW);
mediaMetadata.putString(MediaMetadata.KEY_TITLE, "title");
return new MediaInfo.Builder(selectedStreamingURL)
.setContentType("application/x-mpegurl")
.setStreamType(MediaInfo.STREAM_TYPE_LIVE)
.setMetadata(mediaMetadata)
.build();
}
For all Cast devices, the Chrome browser is the user agent and controls the HTTP request headers. For DRM content and if you use the CAF receiver, there are various options for you to control access to your content:
https://developers.google.com/cast/docs/caf_receiver_features#drm
Related
I have successfully opened the blackberry access from our IOS app using the url scheme access://open? , but it seems to be not working on Android. Our application is not integrated with blackberry sdk .
For anyone who needs it you can open the blackberry access from your app using the blackberry access appid com.good.gdgma.
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse(urlString));
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setPackage("com.good.gdgma");
try {
getApplicationContext().startActivity(intent);
}
catch(ActivityNotFoundException ex) {
showNotInstalledDialog(App.BLACKBERRY_ACCESS);
}
There is a setting the in application configuration policy for BlackBerry Access that enables or disables this feature. It's called "Allow external apps to open HTTP/HTTPS URLs through BlackBerry Access" and is set for the app config for BlackBerry Access within BlackBerry UEM. This setting applies to all non BlackBerry Dynamics methods of opening BlackBerry Access.
If you were to integrate with the BlackBerry Dynamics SDK the recommended method is to use the BlackBerry Dynamics Shared Services framework to call the Open HTTP URL Service. It's available for both iOS and Android. Here's some Android sample code to use it.
Here's a code snippet that does just that:
private static final String SERVICE_ID = "com.good.gdservice.open-url.http";
private static final String SERVICE_VERSION = "1.0.0.0";
private static final String ACCESS_ENTITLEMENT_ID = "com.good.gdgma";
private static final String HTTP_OPEN_URL_SERVICE_METHOD_NAME = "open";
....
//Get the service providers for the Open HTTP URL service.
List<GDServiceProvider> providers = GDAndroid.getInstance().getServiceProvidersFor(SERVICE_ID, SERVICE_VERSION,
GDServiceType.GD_SERVICE_TYPE_APPLICATION);
//Ensure an provider of the Open HTTP URL service was found.
if(providers == null || providers.size() == 0)
{
//No providers found.
showError("No Open HTTP URL were found.");
}
else
{
boolean foundAccess = false;
String yourURL = "www.whereEverYouWantToGo.com";
for (int count = 0; count < providers.size(); count++)
{
GDServiceProvider provider = providers.get(count);
//Ensure BlackBerry Access was found.
if (provider.getIdentifier().equalsIgnoreCase(ACCESS_ENTITLEMENT_ID))
{
foundAccess = true;
String address = providers.get(count).getAddress();
Map<String, Object> params = new HashMap<>();
params.put("url", yourURL);
try
{
//Launch BlackBerry Access.
GDServiceClient.sendTo(address, SERVICE_ID, SERVICE_VERSION,
HTTP_OPEN_URL_SERVICE_METHOD_NAME, params, null,
GDICCForegroundOptions.PreferPeerInForeground);
} catch (GDServiceException e)
{
showError(e.toString());
}
}
}
if (!foundAccess)
{
showError("BlackBerry Access not found.");
}
}
I'm currently building an Android Things application that communicates with an ONVIF IP camera following this youtube tutorial I can talk to the camera and I can get services and device information but when I try to retrieve profiles, it responds with D/RESPONSE: Response{protocol=http/1.1, code=500, message=Internal Server Error
What would cause this response?
onCreate
currentDevice = OnvifDevice("192.168.1.5","admin","password")
currentDevice.listener = this
currentDevice.getServices()
Log.d("REQUEST", "Get services");
requestPerformed
override fun requestPerformed(response: OnvifResponse) {
//method called when response is received from camera
Log.d("RESPONSE", response.parsingUIMessage);
if (response.request.type == OnvifRequest.Type.GetServices) {
Log.d("REQUEST", "Get device information");
currentDevice.getDeviceInformation()
}
else if (response.request.type == OnvifRequest.Type.GetDeviceInformation) {
Log.d("REQUEST", "Get profiles");
currentDevice.getProfiles()
}
else if (response.request.type == OnvifRequest.Type.GetProfiles) {
Log.d("REQUEST", "Get stream URI");
currentDevice.mediaProfiles.firstOrNull()?.let {
currentDevice.getStreamURI(it)
}
}
else if (response.request.type == OnvifRequest.Type.GetStreamURI) {
Log.d("REQUEST", "Get get video stream");
currentDevice.rtspURI?.let { uri ->
val surfaceView = findViewById<SurfaceView>(R.id.surfaceView)
vlcVideoLibrary = VlcVideoLibrary(this, this, surfaceView)
vlcVideoLibrary?.play(uri)
}
}
}
Sometimes, the problem isn't with the code you wrote, but with the device/camera you're using... I had a problem with one of my camera... It wasn't returning a valid response when asked for its status. here
I would suggest you to look for any camera software update. If this still doesn't work, I would suggest to try with another device as #sasikumar said.
I am able to play videos using the YouTube Player API 1.2.2 for Android. However, users always see pre-roll ads even if they have a YouTube Red subscription. I could not find any documentation surrounding video playback as a specific YouTube user, in order to take advantage of a YouTube Red subscription, which disables ads.
The javadoc for YouTubePlayerSupportFragment.initialize() says:
public void initialize (String developerKey, YouTubePlayer.OnInitializedListener listener)
Initialize a YouTubePlayer, which can be used to play videos and control video playback. One of the callbacks in listener will be invoked when the initialization succeeds or fails.
Parameters
developerKey A valid API key that is enabled to use the YouTube Data API v3 service. To generate a new key, visit the Google Developers Console.
listener The callbacks that will be invoked when the initialization succeeds or fails.
So it takes an API key, rather than a user's OAuth credentials. Is there any way to pass the OAuth credentials instead, to play a video as a specific user?
I saw this example app: https://github.com/youtube/yt-direct-lite-android -- It shows an example of using OAuth 2.0 to upload videos, but the playback uses a simple API key only.
There is not currently a way to play videos as a specific user, aside from using WebView. It is the same as the answer to Play private YouTube video using YoutubePlayerView from YoutubeAndroidPlayerAPI?:
This is not possible with the Android Player API. The only way to play private videos on a device is to implement a WebView in your app, have the user log into their YouTube account, and then play back the Private video in that specific browser session only.
As long as you app uses oath and is verified you can build and play private playlists as if you were the user of the account [for that account]. Using the youtube v3 api and the .player api. If not authenticated properly for whatever reason, you can run into situations where the api lets you create a private playlist as a user of the account but the list is empty within the player api.
also, you can actually play private video:
#SuppressLint("StaticFieldLeak")
private void loadUploadedVideos() {
if (mChosenAccountName == null) {
return;
}
Log.d(TAG, "loadUploads");
showProgressDialog();
new AsyncTask<Void, Void, List<VideoData>>() {
#Override
protected List<VideoData> doInBackground(Void... voids) {
try {
YouTube youtube = new YouTube.Builder(transport, jsonFactory,
credential).setApplicationName(Constants.APP_NAME)
.build();
/*
* Now that the user is authenticated, the app makes a
* channels list request to get the authenticated user's
* channel. Returned with that data is the playlist id for
* the uploaded videos.
* https://developers.google.com/youtube
* /v3/docs/channels/list
*/
ChannelListResponse clr = youtube.channels()
.list("contentDetails").setMine(true).execute();
// Get the user's uploads playlist's id from channel list
// response
String uploadsPlaylistId = clr.getItems().get(0)
.getContentDetails().getRelatedPlaylists()
.getUploads();
List<VideoData> videos = new ArrayList<VideoData>();
// Get videos from user's upload playlist with a playlist
// items list request
PlaylistItemListResponse pilr = youtube.playlistItems()
.list("id,contentDetails")
.setPlaylistId(uploadsPlaylistId)
.setMaxResults(50L).execute();
List<String> videoIds = new ArrayList<String>();
// Iterate over playlist item list response to get uploaded
// videos' ids.
for (PlaylistItem item : pilr.getItems()) {
videoIds.add(item.getContentDetails().getVideoId());
}
// Get details of uploaded videos with a videos list
// request.
VideoListResponse vlr = youtube.videos()
.list("id,snippet,status")
.setId(TextUtils.join(",", videoIds)).execute();
// Add only the public videos to the local videos list.
for (Video video : vlr.getItems()) {
//if ("public".equals(video.getStatus().getPrivacyStatus())) {
VideoData videoData = new VideoData();
videoData.setVideo(video);
videos.add(videoData);
//}
}
// Sort videos by title
Collections.sort(videos, new Comparator<VideoData>() {
#Override
public int compare(VideoData videoData,
VideoData videoData2) {
return videoData.getTitle().compareTo(
videoData2.getTitle());
}
});
return videos;
} catch (final GooglePlayServicesAvailabilityIOException availabilityException) {
showGooglePlayServicesAvailabilityErrorDialog(availabilityException
.getConnectionStatusCode());
} catch (UserRecoverableAuthIOException userRecoverableException) {
startActivityForResult(
userRecoverableException.getIntent(),
REQUEST_AUTHORIZATION);
} catch (IOException e) {
Utils.logAndShow(MainActivity.this, Constants.APP_NAME, e);
}
catch (Exception e) {
Log.e(TAG, e.getMessage());
}
return null;
}
#Override
protected void onPostExecute(List<VideoData> videos) {
if (videos == null) {
hideProgressDialog();
return;
}
if (mMyUploadsFragment != null)
mMyUploadsFragment.setUploads(videos);
hideProgressDialog();
}
}.execute((Void) null);
}
And finally this is the answer to the question, but it needed context:
Also once authenticated, youtube prime features are available in the player api. Nice. The trick seems to be to log the Youtube user into the youtube app on the phone as well as using the same creds in your own app.
anyway any playlist the app is authenticated to play on android can be played this way:
public void onPlaylistSelected(PlaylistData playlist) {
try {
mPlaylistData = playlist;
//Intent intent = YouTubeIntents.createPlayPlaylistIntent(this, playlist.getId());
Intent intent = YouTubeIntents.createOpenPlaylistIntent(this, playlist.getId());
startActivity(intent);
} catch (ActivityNotFoundException e) {
Log.w(TAG,e.getMessage());
Toast.makeText(this, R.string.warn_install_yt,Toast.LENGTH_LONG).show();
}
}
I am using the following cast receiver
When I connect my android sender to chromecast device, it show a black screen and never plays video.
https://github.com/googlecast/CastReferencePlayer
I'm setting licenseUrl for widevine in receiver as follow:
sampleplayer.CastPlayer.prototype.preloadVideo_ = function(mediaInformation) {
this.log_('preloadVideo_');
var self = this;
var url = mediaInformation.contentId;
var protocolFunc = sampleplayer.getProtocolFunction_(mediaInformation);
if (!protocolFunc) {
this.log_('No protocol found for preload');
return false;
}
var host = new cast.player.api.Host({
'url': url,
'mediaElement': self.mediaElement_
});
host.onError = function() {
self.preloadPlayer_.unload();
self.preloadPlayer_ = null;
self.showPreviewModeMetadata(false);
self.displayPreviewMode_ = false;
self.log_('Error during preload');
};
host.licenseUrl = event.data.customData.licenseUrl;
self.preloadPlayer_ = new cast.player.api.Player(host);
self.preloadPlayer_.preload(protocolFunc(host));
return true;
};
host.licenseUrl = event.data.customData.licenseUrl;
I've hosted it on a https server which is registered on developers console.
I'm passing custom data as licenseUrl in a json object.
The code of my android sender setting media info is below.
private MediaInfo buildMediaInfo() {
MediaMetadata movieMetadata = new MediaMetadata(MediaMetadata.MEDIA_TYPE_MOVIE);
movieMetadata.putString(MediaMetadata.KEY_SUBTITLE, "Subtitle");
movieMetadata.putString(MediaMetadata.KEY_TITLE, "Title");
jsonObj = new JSONObject();
try{
jsonObj.put("licenseUrl","https://wv.test.expressplay.com/hms/wv/rights/?ExpressPlayToken=token-value");
}catch (JSONException e){
Log.e(null,"Failed to add description to the json object", e);
}
/*drmModel.getData().getStreamURL()*/
return new MediaInfo.Builder("https://pathOfMystream.mpd")
.setStreamType(MediaInfo.STREAM_TYPE_BUFFERED)
.setContentType("application/dash+xml")
.setMetadata(movieMetadata)
.setCustomData(jsonObj)
.setStreamDuration(player.getDuration()*1000)
.build();
}
What changes are further required ?
Do I need to edit receiver? If yes, then what edits are needed?
Is the string name in customData "licenseUrl" needs to be
changed?
CORS is enabled on the S3 server which is hosting the video contents.
Please help! I'm stuck here for more than a week.
Thank you.
I figured out that event.data.customData was undefined while connecting from android sender application.
So I used event.data.media.customData
And accessed the key as follow:
if(event.data.media.customData['licenseUrl'] !== null){
console.log('setting license URL from mobile');
host.licenseUrl = event.data.media.customData.licenseUrl;
}
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;
};
}