Facebook Contacts
| | By using the Facebook Developer Toolkit and the Bluetooth and Contacts APIs from the Coding4Fun Developer Toolkit, I created an application which transfers information about your Facebook friends to your mobile phone. |
| Jon Schuster Difficulty: Intermediate Time Required: 6-10 hours Cost: Free Hardware: Bluetooth-enabled computer and phone |
Facebook is a great social networking site which keeps track of all kinds of information about your friends. Since things like your friends’ hometown, picture, and even the correct spelling of their name are already provided for you there, it would be great if you could automatically send all of that information to your phone, instead of having to manually type it in yourself. By using a couple of different toolkits, I was able to create a simple application which does all of this for me without writing a lot of code.
Disclaimer: Unfortunately, the Facebook API does not allow you to get a user’s contact information, such as phone number or e-mail address. If it did, they would certainly be included here, but as it is I’m limited to the information that Facebook provides.
To give a quick overview, the sample first uses the Facebook Developer Toolkit to connect to Facebook and download information about the user’s friends. These are displayed in a list on the main form, and multiple users can be selected with checkboxes. Then, using the Bluetooth API from the Coding4Fun Developer Toolkit, I get a list of Bluetooth devices (including mobile phones) within range, allowing the user to select one of them. Finally, when the user clicks “OK”, I use the Contacts API, also from the Coding4Fun toolkit, to turn each of the selected users into a transferable file, and then send it to the phone over a Bluetooth connection. The following sections describe this process in more detail.
Figure 1: The Facebook Contacts main screen
Retrieving Information From Facebook
To get started developing applications with the Facebook API, you first need to register your application and get an API key from Facebook which will allow you to connect to their site and download data. Their Get Started page will lead you through the process.
Now that you have an API key, you can start developing. While you can connect to Facebook and get the information manually through HTTP REST calls, I chose to use the Facebook Developer Toolkit, which took care of maintaining a connection, requesting the information, and parsing the response into objects that I can use in code. The following code loads the user’s friends into memory, using the included FacebookService component:
C#
private void LoadFriends()
{
List<User> users = new List<User>();
try
{
users = new List<User>(facebookService1.GetFriends());
}
catch (FacebookInvalidUserException)
{
this.Close();
return;
}
catch (FacebookException)
{
// do nothing: this exception just means no friends were returned,
// so we can leave the users list empty
}
users.Sort(Compare);
_friends = users;
}
VB.NET
Private Sub LoadFriends()
Dim users As List(Of User) = New List(Of User)()
Try
users = New List(Of User)(facebookService1.GetFriends())
Catch e1 As FacebookInvalidUserException
Me.Close()
Return
Catch e2 As FacebookException
' do nothing: this exception just means no friends were returned,
' so we can leave the users list empty
End Try
users.Sort(AddressOf Compare)
_friends = users
End Sub
I sort the users by comparing their last names, and then their first names if the last names are equal:
C#
private int Compare(User leftUser, User rightUser)
{
int lastNameComparison = leftUser.LastName.CompareTo(rightUser.LastName);
if (lastNameComparison != 0)
{
return lastNameComparison;
}
return leftUser.FirstName.CompareTo(rightUser.FirstName);
}
VB.NET
Private Function Compare(ByVal leftUser As User, ByVal rightUser As User) As Integer
Dim lastNameComparison As Integer = leftUser.LastName.CompareTo(rightUser.LastName)
If lastNameComparison <> 0 Then
Return lastNameComparison
End If
Return leftUser.FirstName.CompareTo(rightUser.FirstName)
End Function
On Facebook, most users are a part of one or more “networks”, such as “Chicago, IL”, or “Notre Dame”. For my application, I wanted to be able to filter the displayed friends according to their associated networks. To do this, I first had to get a list of networks from all my Facebook friends:
C#
private List<string> GetNetworks()
{
List<string> networkNames = new List<string>();
foreach (User friend in _friends)
{
foreach (Network network in friend.Affiliations)
{
if (!networkNames.Contains(network.Name))
{
networkNames.Add(network.Name);
}
}
}
networkNames.Sort();
networkNames.Insert(0, ALL_NETWORKS);
return networkNames;
}
VB.NET
Private Function GetNetworks() As List(Of String)
Dim networkNames As List(Of String) = New List(Of String)()
For Each [friend] As User In _friends
For Each network As Network In [friend].Affiliations
If (Not networkNames.Contains(network.Name)) Then
networkNames.Add(network.Name)
End If
Next network
Next [friend]
networkNames.Sort()
networkNames.Insert(0, ALL_NETWORKS)
Return networkNames
End Function
This list was displayed as a combo box on my form. Then, whenever the selection in the combo box changed, I had to filter the displayed list:
C#
private void FilterDisplayedFriends(string selectedNetwork)
{
List<User> friendsToDisplay;
if (selectedNetwork.Equals(ALL_NETWORKS))
{
friendsToDisplay = _friends;
}
else
{
friendsToDisplay = new List<User>();
foreach (User friend in _friends)
{
foreach (Network network in friend.Affiliations)
{
if (network.Name.Equals(selectedNetwork))
{
friendsToDisplay.Add(friend);
continue;
}
}
}
}
Display(friendsToDisplay);
}
VB.NET
Private Sub FilterDisplayedFriends(ByVal selectedNetwork As String)
Dim friendsToDisplay As List(Of User)
If selectedNetwork.Equals(ALL_NETWORKS) Then
friendsToDisplay = _friends
Else
friendsToDisplay = New List(Of User)()
For Each [friend] As User In _friends
For Each network As Network In [friend].Affiliations
If network.Name.Equals(selectedNetwork) Then
friendsToDisplay.Add([friend])
Continue For
End If
Next network
Next [friend]
End If
Display(friendsToDisplay)
End Sub
Connecting to the Phone via Bluetooth
Now we have a list of friends that we can search through and select from. The next step is to transform the users we are going to send to the phone into vCard files. vCards are a common, human-readable file format for exchanging contact information between computers or other devices. Fortunately, the Contacts API released with the Coding4Fun Toolkit can create vCards for me. All I have to do is provide the mapping from the properties of a Facebook User object to those of a Contact object (using the included SimpleContactView).
C#
private void FillContact(Contact contact, User facebookUser, WebClient webClient)
{
SimpleContactView simpleContact = new SimpleContactView(contact);
simpleContact.FirstName = facebookUser.FirstName;
simpleContact.LastName = facebookUser.LastName;
Location location = facebookUser.CurrentLocation;
if (location != null)
{
simpleContact.HomeCity = location.City;
if (location.StateAbbreviation != Facebook.Entity.StateAbbreviation.Unknown)
{
simpleContact.HomeState = location.StateAbbreviation.ToString();
}
if (location.Country != Facebook.Entity.Country.Unknown)
{
simpleContact.HomeCountry = ToString(location.Country);
}
simpleContact.HomeZip = location.ZipCode;
}
if (facebookUser.Sex == Facebook.Entity.Gender.Female)
{
simpleContact.Gender = Contacts.Gender.Female;
}
else if (facebookUser.Sex == Facebook.Entity.Gender.Male)
{
simpleContact.Gender = Contacts.Gender.Male;
}
else
{
simpleContact.Gender = Contacts.Gender.Unspecified;
}
if (!facebookUser.PictureUrl.Equals(DEFAULT_FACEBOOK_PICTURE))
{
string pictureFile = Path.GetTempFileName();
webClient.DownloadFile(facebookUser.PictureUrl, pictureFile);
using (FileStream fs = new FileStream(pictureFile, FileMode.Open))
{
contact.Photos[PhotoLabels.UserTile] = new Contacts.Photo(fs, "image");
}
File.Delete(pictureFile);
}
}
VB.NET
Private Sub FillContact(ByVal contact As Contact, ByVal facebookUser As User, ByVal webClient As WebClient)
Dim simpleContact As SimpleContactView = New SimpleContactView(contact)
simpleContact.FirstName = facebookUser.FirstName
simpleContact.LastName = facebookUser.LastName
Dim location As Location = facebookUser.CurrentLocation
If Not location Is Nothing Then
simpleContact.HomeCity = location.City
If location.StateAbbreviation <> Facebook.Entity.StateAbbreviation.Unknown Then
simpleContact.HomeState = location.StateAbbreviation.ToString()
End If
If location.Country <> Facebook.Entity.Country.Unknown Then
simpleContact.HomeCountry = ToString(location.Country)
End If
simpleContact.HomeZip = location.ZipCode
End If
If facebookUser.Sex = Facebook.Entity.Gender.Female Then
simpleContact.Gender = Contacts.Gender.Female
ElseIf facebookUser.Sex = Facebook.Entity.Gender.Male Then
simpleContact.Gender = Contacts.Gender.Male
Else
simpleContact.Gender = Contacts.Gender.Unspecified
End If
If (Not facebookUser.PictureUrl.Equals(DEFAULT_FACEBOOK_PICTURE)) Then
Dim pictureFile As String = Path.GetTempFileName()
webClient.DownloadFile(facebookUser.PictureUrl, pictureFile)
Using fs As FileStream = New FileStream(pictureFile, FileMode.Open)
contact.Photos(PhotoLabels.UserTile) = New Contacts.Photo(fs, "image")
End Using
File.Delete(pictureFile)
End If
End Sub
Finally, now that we can create vCards for Facebook users, we can make one for each selected user and send them off to the phone. First, however, we need to learn a little bit about how Bluetooth works. Every Bluetooth device implements a set of “profiles”, which are interface specifications that let Bluetooth devices know how to communicate with each other. Each profile is responsible for providing a different kind of service, such as phone headset communication, video streaming, and file transfer. To communicate with another Bluetooth device, you have to first find out if the device supports the profile you wish to use, connect to the device using that profile, and use the interface defined by the profile to accomplish your tasks.
For this application, I used the Object Push Profile (known as OBEX Object Push in the API), which is specifically designed to transfer objects such as vCards from one phone to another. The OppMananger component in the API takes care of the more difficult parts of making the connection. Once I’m connected, I just create a vCard for each user, transfer each one, and disconnect when I’m done:
C#
private void SendToPhone(IEnumerable<User> users)
{
Device device = (Device) cmbDevices.SelectedItem;
RemoteService pushService;
try
{
pushService = deviceServicesManager1.DiscoverServicesByType(device, ServiceType.OBEXObjectPush).ElementAt(0);
}
catch
{
MessageBox.Show("Could not connect to Bluetooth device " + cmbDevices.Text + ". It may be out of range.");
return;
}
try
{
oppManager1.NetworkStream = pushService.Connect();
}
catch (ServiceConnectionException)
{
MessageBox.Show("Could not connect to Bluetooth device " + device.Name);
return;
}
oppManager1.Connect();
WebClient webClient = new WebClient();
foreach (User user in users)
{
Contact contact = CreateContact(user, webClient);
string tempFile = Path.GetTempFileName();
string tempVCard = Path.GetDirectoryName(tempFile) + "\\" + Path.GetFileNameWithoutExtension(tempFile) + ".vcf";
File.Delete(tempFile);
contactsService1.SaveContactToVCard(contact, tempVCard);
oppManager1.PushObject(tempVCard);
File.Delete(tempVCard);
}
oppManager1.Disconnect();
pushService.Disconnect();
MessageBox.Show("Successfully transferred " + users.Count() + " friends to " + device.Name + ".");
}
VB.NET
Private Sub SendToPhone(ByVal users As IEnumerable(Of User))
Dim device As Device = CType(cmbDevices.SelectedItem, Device)
Dim pushService As RemoteService
Try
pushService = deviceServicesManager1.DiscoverServicesByType(device, ServiceType.OBEXObjectPush).ElementAt(0)
Catch
MessageBox.Show("Could not connect to Bluetooth device " & cmbDevices.Text & ". It may be out of range.")
Return
End Try
Try
oppManager1.NetworkStream = pushService.Connect()
Catch e1 As ServiceConnectionException
MessageBox.Show("Could not connect to Bluetooth device " & device.Name)
Return
End Try
oppManager1.Connect()
Dim webClient As WebClient = New WebClient()
For Each user As User In users
Dim contact As Contact = CreateContact(user, webClient)
Dim tempFile As String = Path.GetTempFileName()
Dim tempVCard As String = Path.GetDirectoryName(tempFile) & "\" & Path.GetFileNameWithoutExtension(tempFile) & ".vcf"
File.Delete(tempFile)
contactsService1.SaveContactToVCard(contact, tempVCard)
oppManager1.PushObject(tempVCard)
File.Delete(tempVCard)
Next user
oppManager1.Disconnect()
pushService.Disconnect()
MessageBox.Show("Successfully transferred " & users.Count() & " friends to " & device.Name & ".")
End Sub
Voila! You can now see your Facebook friends, including their profile pictures, on your phone. This application can also save Facebook friends as Windows Contacts. The code is mostly identical, except that the contacts get saved directly to the local machine using the ContactsService component, instead of using Bluetooth to connect to a separate device.
Conclusion
The three APIs I used for this project (Facebook, Bluetooth, and Contacts) made the application a breeze to set up. With the exception of one or two bits of code that could be improved, the APIs were all very simple and easy to use, and took care of all the low-level details so that I could focus on the code relevant to this project. There’s still more work that could be done, including more ways to search through Facebook friends besides the network and improving load time. Overall, though, I’m very pleased with how it came out, and I hope this has shown you how you can take advantage of some of these APIs to create a really useful tool.
About the Author
Jon Schuster is a consultant at Clarity Consulting, and can be reached at his e-mail address, jschuster [at] claritycon [dot] com