Xamarin.Tip – Read All Contacts in iOS 2.0

This is a second post to follow Xamarin.Tip – Read All Contacts in iOS to give a more efficient alternative to interacting with the CNContact API. Check out the change in the ContactService below! Using the EnumerateContacts ensures we get contacts from all groups including non standard groups like those brought from backups or iCloud integrated contacts. It is also a newer API call that has better performance.

Since Xamarin hasn’t been working on the Xamarin.Mobile component for a while, and James Montemagno dropped support for his Contacts Plugin, if you want to access the contact APIs on each platform, you might just have to go at it yourself – or just copy this code!

iOS

Today we’ll look at getting all of the contacts in iOS and mapping them to a local shared model that any platform can ingest.

So let’s first define a simple model for our contact. This can have more models that are shared, but we will focus on the phone number and name for the sake of demonstrating.

PhoneContact.cs


    public class PhoneContact
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string PhoneNumber { get; set; }

        public string Name { get => $"{FirstName} {LastName}"; }

    }

Now let’s create a service in our iOS app project that uses the CNContact API. This will be responsible for getting all of the devices contacts (whether they have come from a back up, added, or are synced through iCloud).

The breakdown of this code can be found below.

ContactService.cs

    public class ContactService
    {
       public IEnumerable<PhoneContact> GetAllContacts()
        {
            var keysTOFetch = new[] { CNContactKey.GivenName, CNContactKey.FamilyName, CNContactKey.PhoneNumbers };
            NSError error;
            //var containerId = new CNContactStore().DefaultContainerIdentifier;
            // using the container id of null to get all containers
            var contactList = new List<CNContact>();

            using (var store = new CNContactStore())
            {
                var request = new CNContactFetchRequest(keysTOFetch);
                store.EnumerateContacts(request, out error, new CNContactStoreListContactsHandler((CNContact contact, ref bool stop) => contactList.Add(contact)));
                
            }
            var contacts = new List<PhoneContact>();

            foreach (var item in contactList)
            {
                var numbers = item.PhoneNumbers;
                if (numbers != null)
                {
                    foreach (var item2 in numbers)
                    {
                        contacts.Add(new PhoneContact
                        {
                            FirstName = item.GivenName,
                            LastName = item.FamilyName,
                            PhoneNumber = item2.Value.StringValue

                        });
                    }
                }
            }
            return contacts;
        }
    
    }

Let’s breakdown what the code is doing here:

  1. Identify the properties of the contacts you want to grab – see keysToFetch
  2. Instantiate the CNContactStore and get all of the collections which will contain all of the contacts.
  3. Fetch all of the contacts from each container and add them to the master list.
  4. Loop over all of the contact data and add a new PhoneContact
    for each of the phone numbers they have. This could be done with giving a contact an IEnumerable PhoneNumbers rather than just one phone number, but in order to separate each phone number, that’s how we will do it.
  5. Return the formatted list of contacts/phone numbers

We can list this out in a UITableView, or in the case of the screenshot below, in a Xamarin.Forms ListView.

The last thing we need to do is make sure we have the permission to access the user’s contacts! We can do this by updating the info.plist with a Privacy - Contacts Usage Description property.

Screen Shot 2017-08-22 at 10.34.43 AM

Try building some other fun features into your ContactsService or selector!
– Filter the list via search
– Build a more user friendly selector without duplicating contacts
– Gather additional properties for contacts

Simulator Screen Shot Aug 21, 2017, 11.20.32 AM.png

Next we’ll look at building this same type of ContactService for Android in order to be able to gather all of the contacts on the device and follow up with using both of these services in Xamarin.Forms to create a contact picker control!

If you like what you see, don’t forget to follow me on twitter @Suave_Pirate, check out my GitHub, and subscribe to my blog to learn more mobile developer tips and tricks!

Interested in sponsoring developer content? Message @Suave_Pirate on twitter for details.

Advertisements

One thought on “Xamarin.Tip – Read All Contacts in iOS 2.0”

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s