Xamarin iOS: Getting a list of Contacts

Getting Contacts from iOS and Android is a little harder than it really should be. I hope one day it will be added to Xamarin.Essentials, but until then, here’s how to get them in a simple way.

I won’t cover all the DTOs needed as those are simple and not really part of the point, but here’s the overview of the PhoneContact class I’ll use:

public class PhoneContact
{
    public string Identifier { getset; }
    public string FirstName { getset; }
    public string LastName { getset; }
    public List<PhoneNumberContact> PhoneNumbers { getset; } = new List<PhoneNumberContact>();
    public List<EmailContact> Emails { getset; } = new List<EmailContact>();
    public List<AddressContact> PostalAddresses { getset; } = new List<AddressContact>();
    public List<DateLabelContact> Dates { getset; } = new List<DateLabelContact>();
    public string DepartmentName { getset; }
    public List<InstantMessageContact> InstantMessageAddresses { getset; } = new List<InstantMessageContact>();
    public string JobTitle { getset; }
    public string OrganizationName { getset; }
    public List<SocialContact> SocialProfiles { getset; }
    public string Notes { getset; }
}

To get the contacts out of iOS, you can use this service. The namespace is marked as a Dependency so you could inject it into a Xamarin.Forms project.

using Contacts;
using Foundation;
using MyApp.Extensions;
using MyApp.Interfaces;
using MyApp.iOS.Dependencies;
using MyApp.Services.Contacts;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Telerik.XamarinForms.Common.iOS;
using Xamarin.Forms;
 
[assemblyDependency(typeof(ContactService))]
namespace MyApp.iOS.Dependencies
{
 
    /// <summary>
    /// SEE for more help on Android: https://github.com/jamesmontemagno/Xamarin.Mobile/blob/master/MonoDroid/Xamarin.Mobile/Contacts/ContactHelper.cs
    /// </summary>
    public class ContactService : IContactService
    {
 
        public Task<IList<PhoneContact>> GetContactListAsync()
        {
            return Task.Run(GetContactList);
        }
 
        public IList<PhoneContactGetContactList()
        {
            List<PhoneContactresult = new List<PhoneContact>();
            try
            {
                var keysToFetch = new[]
                {
                    CNContactKey.GivenName,
                    CNContactKey.FamilyName,
                    CNContactKey.EmailAddresses  ,
                    CNContactKey.PhoneNumbers  ,
                    CNContactKey.OrganizationName,
                    CNContactKey.Dates,
                    CNContactKey.DepartmentName,
                    CNContactKey.Identifier,
                    CNContactKey.InstantMessageAddresses,
                    CNContactKey.JobTitle,
                    CNContactKey.Birthday,
                    CNContactKey.PostalAddresses,
                    CNContactKey.SocialProfiles,
                };
                var contactList = ReadRawContactList(keysToFetch);
 
                if (contactList != null)
                    result = GetContacts(contactList).ToList();
            }
            catch (Exception ex)
            {
                App.Logger.LogError(ex);
                result = new List<PhoneContact>();
            }
 
            return result;
        }
 
        private static IEnumerable<CNContactReadRawContactList(IEnumerable<NSStringkeysToFetch)
        {
            using (var store = new CNContactStore())
            {
                var allContainers = store.GetContainers(nullout _);
                return ContactListFromAllContainers(keysToFetchallContainersstore);
            }
 
        }
 
        private static IEnumerable<CNContactContactListFromAllContainers(
            IEnumerable<NSStringkeysToFetch,
            IEnumerable<CNContainerallContainers,
            CNContactStore store)
        {
            var nsStrings = keysToFetch.ToList();
            var contactList = new List<CNContact>();
            foreach (var container in allContainers)
            {
                var contacts = ReadFromContainer(nsStringscontainerstore);
                if (contacts != null)
                {
                    contactList.AddRange(contacts);
                }
                else
                {
                    Console.WriteLine("ERROR unable to get contacts");
                }
            }
 
            return contactList;
        }
 
        private static IEnumerable<CNContactReadFromContainer(
            IEnumerable<NSStringkeysToFetch,
            CNContainer container,
            CNContactStore store)
        {
            try
            {
                using (var predicate = CNContact.GetPredicateForContactsInContainer(container.Identifier))
                {
                    return store.GetUnifiedContacts(predicatekeysToFetch.ToArray(), out _);
                }
            }
            catch (Exception ex)
            {
                App.Logger.LogError(ex);
            }
 
            return null;
        }
 
        private static IEnumerable<PhoneContactGetContacts(IEnumerable<CNContactcontactList)
        {
            return contactList.Select(GetContact);
        }
 
        private static PhoneContact GetContact(CNContact item)
        {
            if (item == nullreturn new PhoneContact();
 
            try
            {
                var contact = new PhoneContact
                {
                    FirstName = item.GivenName,
                    LastName = item.FamilyName,
                    PhoneNumbers = item?.PhoneNumbers?
                        .Where(x => x.Value != null)
                        .Select(x => new PhoneNumberContact() { Name = x.Label, Phone = x.Value?.StringValue })
                        .ToList(),
                    Emails = item.EmailAddresses?
                        .Where(x => x.Value != null)
                        .Select(x => new EmailContact() { Name = x.Label, Email = x.Value?.PathComponents?.FirstOrDefault() })
                        .ToList(),
                    OrganizationName = item?.OrganizationName,
                    Dates = item?.Dates?
                        .Where(q => q.Value != null)
                        .Select(x => new DateLabelContact { Name = x.Label, Date = x.Value?.Date?.ToDateTime() }).ToList(),
                    DepartmentName = item.DepartmentName,
                    Identifier = item.Identifier,
                    InstantMessageAddresses = item?.InstantMessageAddresses?
                        .Where(x => x.Value != null)
                        .Select(x => new InstantMessageContact { Service = x.Value?.Service, Username = x.Value?.Username })
                        .ToList(),
                    JobTitle = item.JobTitle,
 
                    PostalAddresses = item?.PostalAddresses?
                        .Where(x => x.Value != null)
                        .Select(x => new AddressContact()
                        {
                            City = x.Value.City,
                            Country = x.Value.Country,
                            PostalCode = x.Value.PostalCode,
                            State = x.Value.State,
                            Street = x.Value.Street
                        }).ToList(),
                    SocialProfiles = item?.SocialProfiles?
                        .Where(x => x.Value != null)
                        .Select(x => new SocialContact() { Username = x.Value.Username, Service = x.Value.Service, }).ToList()
                };
 
                var birthDate = item?.Birthday?.Date?.ToDateTime().Date;
                if (birthDate != null)
                {
                    contact?.Dates?.Add(new DateLabelContact()
                    {
                        Name = "BIRTHDATE",
                        Date = birthDate
                    });
                }
 
                //  Console.WriteLine(contact.ToJson());
                return contact;
            }
            catch (Exception ex)
            {
                App.Logger.LogError(ex);
            }
 
            return null;
        }
 
    }
}

 

In my next post I’ll show you how to get it from Android, much harder sadly 😦

 

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 )

Google photo

You are commenting using your Google 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 )

Connecting to %s