Fetching Address book AKA Contact information from Device using Xamarin.Forms


It's  been while I didn't write anything. This time I came with something in Xamarin.Forms. This article is intended to show the powerfulness of Xamarin.Forms and it's component to achieve the result with a common code base.

This article demonstrate on how to fetch address book (Contacts) information from a platforms (Android/iOS) using Xamarin.Forms. It works in conjunction with Xamarin.Mobile components. Xamarin.Mobile components is an API for accessing common platform features, such as reading the user's address book and using the camera, across iOS, Android, and Windows Phone.
Its truly a fantastic component to achieve the functionality of platform specific features. but sadly, it does not have any support for Xamarin.Forms and thats where this article comes in picture.

What I did is,  used Dependency service of Xamarin to get platform specific features in Xamarin.Forms.


For more information about Dependency service please visit: http://developer.xamarin.com/guides/cross-platform/xamarin-forms/dependency-service/

You also need to download Xamarin.Mobile components from following link:
 https://components.xamarin.com/view/xamarin.mobile

So, now the real cook, all you need to create a new project of Xamarin.Forms(PCL/Shared) and add an interface in your shared/PCL project.

    public interface IAddressBookInformation
      {
         Task<List<Contacts>> GetContacts();
    }
The above interface define a method GetContacts() which is primarly responsible to get the list of contacts from device. The implementation of this interface would be platform specific. We will see it in moment!


Then create a model class called "Contacts" and define it's property like below:

public class Contacts
{
     public string FirstName { get; set; }
     public string LastName { get; set; }
}

Now its time to define ViewModel which will call the actual method:

public class ContactViewModel : BaseViewModel
{
       public ObservableCollection ContactList { get; set; }
     
       public ContactViewModel()
       {
             ContactList = new ObservableCollection();
       }


        public async Task BindContacts()
        {
            var addressBook = DependencyService.Get<IAddressBookInformation>();
            if (addressBook != null)
            {
                var allAddress = await addressBook.GetContacts();
                foreach (var c in allAddress)
                {
                    var name = c.FirstName + " " + c.LastName;
                }

                this.ContactList = new ObservableCollection(allAddress);
                //foreach (var c in allAddress)
                //{
                //    var name = c.FirstName + " " + c.LastName;
                //}
            }
        }

}


I know.. I know.. you'll stretch your head about BaseViewModel, but I will come to there in a moment!

First lets understand the ContactViewModel. It inherits from BaseViewModel and hold a property of Contacts as ObservableCollection. Observable collection is useful when there is a change in underlying list of contacts. For instance, if a new contact is added in device, then it can be reflect in our contact list. nice isn't it?.

The BindContact() method have a important stuffs. The actual beauty lies here. It resolve the IAddressBookInformation interface using DependencyService of Xamarin.Forms. so from here the device specific implementation of IAddressBookInformation interface would be invoke by calling GetContacts Method. This method will returns list of contacts and then bind it with the ContactList property.

Its time to look at BaseViewModel now:
public abstract class BaseViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
 
        protected bool ChangeAndNotify(ref T property, T value, [CallerMemberName] string propertyName = "")
        {
            if (!EqualityComparer.Default.Equals(property, value))
            {
                property = value;
                this.NotifyPropertyChanged(propertyName);
                return true;
            }

            return false;
        }

        protected void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
        {
            if (this.PropertyChanged != null)
            {
                this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }

BaseViewModel is an abstract class which inherits from INotifyPropertyChanged and used to set/get and handle binding and notifying the appropriate properties that something has changed. So I advise when you start building xamarin.forms app, you should always create a baseviewmodel where all common stuffs stayed in. and then all your viewmodels can be inherits from it. Sound interesting! ain't ?

Now let's create a Xamarin content page to see what we have cooked so far. So for that I will create a page with listview and bind my contacts with that list. Simple!

using AddressbookSample.ViewModel;
    using Xamarin.Forms;

    public class AddressBookListPage : ContentPage
    {
        private ListView listView;
        private ContactViewModel contactViewModel;

        public AddressBookListPage()
        {
            this.contactViewModel = new ContactViewModel();
            listView = new ListView
            {
                RowHeight = 40
            };

            var layout = new StackLayout()
            {
                // Padding = new Thickness(10, 0, 10, 0),
                VerticalOptions = LayoutOptions.FillAndExpand,
                Children = { this.listView }
            };

            this.Content = layout;
        }

        protected override async void OnAppearing()
        {
            base.OnAppearing();

            var cell = new DataTemplate(typeof(TextCell));
            cell.SetBinding(TextCell.TextProperty, "FirstName");
            cell.SetBinding(TextCell.DetailProperty, "LastName");
            listView.ItemTemplate = cell;

            await this.contactViewModel.BindContcts();

            listView.ItemsSource = this.contactViewModel.ContactList;

        }
    }
the code is pretty simple. It define a listview and get the list of of contactlist and bind with the listview.


The real charm is here now:
Android implementation of IAddressBookInformation
using System;
using System.Collections.Generic;
using System.Linq;
using AddressbookSample.Droid;
using Xamarin.Forms;

[assembly: Dependency(typeof(AddressBookInformation))]
namespace AddressbookSample.Droid
{
    using System.Threading.Tasks;

    using AddressbookSample.Model;

    using Xamarin.Contacts;
    using Xamarin.Forms;

    public class AddressBookInformation : IAddressBookInformation
    {
     
        private AddressBook book = null;

        public AddressBookInformation()
        {
            this.book = new AddressBook(Forms.Context.ApplicationContext);
        }

        public async Task<List<Contacts>>  GetContacts()
        {
            var contacts = new List<Contacts> ();
            
            // Observation:
            // On device RequestPermission() returns false sometimes so you can use  this.book.RequestPermission().Result (remove await)
            var permissionResult = await this.book.RequestPermission();
            if (permissionResult)
            {
                if (!this.book.Any())
                {
                    Console.WriteLine("No contacts found");
                }

                foreach (Contact contact in book.OrderBy(c => c.LastName))
                {
                    // Note: on certain android device(Htc for example) it show name in DisplayName Field
                    contacts.Add(new Contacts() { FirstName = contact.FirstName, LastName = contact.LastName });
                }
            }

            return contacts;
        }
    }
}


this one is for iOS:
[assembly: Dependency(typeof(AddressBookInformation_iOS))]
namespace AddressbookSample.iOS
{
    using System.Linq;
    using System.Threading.Tasks;

    using AddressbookSample.Model;
    using Xamarin.Contacts;

    public class AddressBookInformation_iOS : IAddressBookInformation
    {
        private AddressBook book = null;

        public AddressBookInformation_iOS()
        {
            this.book = new AddressBook();
        }

        public async Task<List<Contacts>>  GetContacts()
        {
            var contacts = new List<Contacts>();
           
            // Observation:
            // On device this returns false sometimes so you can use like this.book.RequestPermission().Result (remove await)
            var permissionResult = await this.book.RequestPermission();
            if (permissionResult)
            {
                if (!this.book.Any())
                {
                    Console.WriteLine("No contacts found");
                }

                foreach (Contact contact in book.OrderBy(c => c.LastName))
                {
                    contacts.Add(new Contacts() { FirstName = contact.FirstName, LastName = contact.LastName });
                }
            }

            return contacts;
        }
    }
}


Feel free to download the code from github

Comments

Unknown said…
DevRabbit is offering the best Xamarin Consulting Solutions for Healthcare, Education, Retail and other industries. Enquiry now!


Popular posts from this blog

Hyperlink label in Xamarin.Forms

Partial view and AJAX Form with MVC3 Razor