How to fetch Contacts in Xamarin?
We know that Xamarin is a platform that enables fantastic mobile app developments. With Material visual support in Xamarin forms, you could probably create an impeccable design, handling the layout and look of an app. In this blog, we will create a project in Xamarin forms to fetch contacts with a search bar option.
With any mobile app development, there is one common thing that permit access to read the phone contacts. Here some plugins are available for getting the phone contacts you have to make sure that Plugin.CurrentActivity and Acr.UserDialogs packages are installed. You can also apply Material design rule in Xamarin.Forms applications.
The following step shows how to fetch phone contacts.
Step: 1
Open Visual Studio and select Xamarin project.
After selecting Xamarin forms, give it the appropriate name and select Blank App for Android and iOS platforms.
Step: 2
First, create a Model.
GetContact.cs
using System;
using System.Collections.Generic;
using System.Text;
namespace FetchContact.Model
{
public class GetContact
{
public string NameofContact { get; set; }
public string ImageofContact { get; set; }
public string[] Emailsofperson { get; set; }
public string[] Numberofperson { get; set; }
}
}
Step: 3
Create an Interface.
IGetContactServices.cs
using FetchContact.Model;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace FetchContact.Service
{
public class IGetContactServices : EventArgs
{
public GetContact getContact { get; }
public IGetContactServices(GetContact contact)
{
getContact = contact;
}
}
public interface IContacts
{
event EventHandler<IGetContactServices> OnContactLoad;
bool IsLoading { get; }
Task<IList<GetContact>> RetrieveContacts(CancellationToken? token = null);
}
}
Step: 4
After creating the interface open AndroidManifest.xml in the Android project and add the below permission.
<uses-permission android:name=”android.permission.READ_CONTACTS” />
Step: 5
After adding the user permission, add the implementation for the contact service in the Android project.
AndroidContactService.cs
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Acr.UserDialogs;
using Android;
using Android.App;
using Android.Content;
using Android.Content.PM;
using Android.Database;
using Android.Provider;
using Android.Runtime;
using Android.Support.V4.App;
using FetchContact.Model;
using FetchContact.Service;
using Plugin.CurrentActivity;
namespace FetchContact.Droid.Services
{
public class AndroidContactsService : IContacts
{
const string Thumbnail = “thumbIcon”;
bool stopLoad = false;
static TaskCompletionSource<bool> contactPermission;
public string TAG
{
get
{
return “MainActivity”;
}
}
bool _isLoading = false;
public bool IsLoading => _isLoading;
public const int RequestContacts = 1239;
static string[] PermissionsContact = {
Manifest.Permission.ReadContacts
};
public event EventHandler<IGetContactServices> OnContactLoad;
async void RequestContactsPermissions()
{
if (ActivityCompat.ShouldShowRequestPermissionRationale(CrossCurrentActivity.Current.Activity, Manifest.Permission.ReadContacts)
|| ActivityCompat.ShouldShowRequestPermissionRationale(CrossCurrentActivity.Current.Activity, Manifest.Permission.WriteContacts))
{
await UserDialogs.Instance.AlertAsync(“Permission”, “Set the permission”, “Ok”);
}
else
{
ActivityCompat.RequestPermissions(CrossCurrentActivity.Current.Activity, PermissionsContact, RequestContacts);
}
}
public static void RqstPermissionsData(int rqstpermission, string[] permissions, [GeneratedEnum] Permission[] grants)
{
if (rqstpermission == AndroidContactsService.RequestContacts)
{
if (PermissionUtil.VerifyPermissions(grants))
{
contactPermission.TrySetResult(true);
}
else
{
contactPermission.TrySetResult(false);
}
}
}
public async Task<bool> RequestPermission()
{
contactPermission = new TaskCompletionSource<bool>();
if (Android.Support.V4.Content.ContextCompat.CheckSelfPermission(CrossCurrentActivity.Current.Activity, Manifest.Permission.ReadContacts) != (int)Permission.Granted
|| Android.Support.V4.Content.ContextCompat.CheckSelfPermission(CrossCurrentActivity.Current.Activity, Manifest.Permission.WriteContacts) != (int)Permission.Granted)
{
RequestContactsPermissions();
}
else
{
contactPermission.TrySetResult(true);
}
return await contactPermission.Task;
}
public async Task<IList<GetContact>> RetrieveContacts(CancellationToken? cancelToken = null)
{
stopLoad = false;
if (!cancelToken.HasValue)
cancelToken = CancellationToken.None;
var taskCompletionSource = new TaskCompletionSource<IList<GetContact>>();
cancelToken.Value.Register(() =>
{
stopLoad = true;
taskCompletionSource.TrySetCanceled();
});
_isLoading = true;
var task = LoadContacts();
var completedTask = await Task.WhenAny(task, taskCompletionSource.Task);
_isLoading = false;
return await completedTask;
}
async Task<IList<GetContact>> LoadContacts()
{
IList<GetContact> contacts = new List<GetContact>();
var hasPermission = await RequestPermission();
if (hasPermission)
{
var uri = ContactsContract.Contacts.ContentUri;
var ctx = Application.Context;
await Task.Run(() =>
{
var cursor = ctx.ApplicationContext.ContentResolver.Query(uri, new string[]
{
ContactsContract.Contacts.InterfaceConsts.Id,
ContactsContract.Contacts.InterfaceConsts.DisplayName,
ContactsContract.Contacts.InterfaceConsts.PhotoThumbnailUri
}, null, null, $”{ContactsContract.Contacts.InterfaceConsts.DisplayName} ASC”);
if (cursor.Count > 0)
{
while (cursor.MoveToNext())
{
var contact = CreateContact(cursor, ctx);
if (!string.IsNullOrWhiteSpace(contact.NameofContact))
{
OnContactLoad?.Invoke(this, new IGetContactServices(contact));
contacts.Add(contact);
}
if (stopLoad)
break;
}
}
});
}
return contacts;
}
GetContact CreateContact(ICursor cursor, Context ctx)
{
var contactId = GetString(cursor, ContactsContract.Contacts.InterfaceConsts.Id);
var numbers = GetNumbers(ctx, contactId);
var emails = GetEmails(ctx, contactId);
var uri = GetString(cursor, ContactsContract.Contacts.InterfaceConsts.PhotoThumbnailUri);
string path = null;
if (!string.IsNullOrEmpty(uri))
{
try
{
using (var stream = Android.App.Application.Context.ContentResolver.OpenInputStream(Android.Net.Uri.Parse(uri)))
{
path = Path.Combine(Path.GetTempPath(), $”{Thumbnail}-{Guid.NewGuid()}”);
using (var str = new FileStream(path, FileMode.Create))
{
stream.CopyTo(str);
str.Close();
}
stream.Close();
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex);
}
}
var contact = new GetContact
{
NameofContact = GetString(cursor, ContactsContract.Contacts.InterfaceConsts.DisplayName),
Emailsofperson = emails,
ImageofContact = path,
Numberofperson = numbers,
};
return contact;
}
string[] GetNumbers(Context ctx, string contactId)
{
var key = ContactsContract.CommonDataKinds.Phone.Number;
var cursor = ctx.ApplicationContext.ContentResolver.Query(
ContactsContract.CommonDataKinds.Phone.ContentUri,
null,
ContactsContract.CommonDataKinds.Phone.InterfaceConsts.ContactId + ” = ?”,
new[] { contactId },
null
);
return ReadCursorItems(cursor, key)?.ToArray();
}
string[] GetEmails(Context ctx, string contactId)
{
var key = ContactsContract.CommonDataKinds.Email.InterfaceConsts.Data;
var cursor = ctx.ApplicationContext.ContentResolver.Query(
ContactsContract.CommonDataKinds.Email.ContentUri,
null,
ContactsContract.CommonDataKinds.Email.InterfaceConsts.ContactId + ” = ?”,
new[] { contactId },
null);
return ReadCursorItems(cursor, key)?.ToArray();
}
IEnumerable<string> ReadCursorItems(ICursor cursor, string key)
{
while (cursor.MoveToNext())
{
var value = GetString(cursor, key);
yield return value;
}
cursor.Close();
}
string GetString(ICursor cursor, string key)
{
return cursor.GetString(cursor.GetColumnIndex(key));
}
}
}
Step: 6
Now, add one more class in the Android project to handle permissions.
PermissionUtil.cs
using Android.Content.PM;
namespace FetchContact.Droid
{
public static class PermissionUtil
{
public static bool VerifyPermissions(Permission[] grant)
{
if (grant.Length < 1)
return false;
foreach (Permission result in grant)
{
if (result != Permission.Granted)
{
return false;
}
}
return true;
}
}
}
Step: 7
In MainActivity class, we can add the RequestPermission method and also use contact service.
Step: 8
Now, create a view model in the main project and use contact services.
MainViewModel.cs
using FetchContact.Model;
using FetchContact.Service;
using System;
using System.Collections;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Threading.Tasks;
namespace FetchContact.ViewModel
{
public class MainViewModel : INotifyPropertyChanged
{
IContacts _contactService;
public event PropertyChangedEventHandler PropertyChanged;
public string Title => “Contacts”;
public string SearchContactText { get; set; }
public ObservableCollection<GetContact> Contacts { get; set; }
public ObservableCollection<GetContact> ListContacts
{
get
{
return string.IsNullOrEmpty(SearchContactText) ? Contacts : new ObservableCollection<GetContact>(Contacts?.ToList()?.Where(s => !string.IsNullOrEmpty(s.NameofContact) && s.NameofContact.ToLower().Contains(SearchContactText.ToLower())));
}
}
public MainViewModel(IContacts contactService)
{
_contactService = contactService;
Contacts = new ObservableCollection<GetContact>();
Xamarin.Forms.BindingBase.EnableCollectionSynchronization(Contacts, null, ObservableCollection);
_contactService.OnContactLoad += OnContactLoaded;
LoadContacts();
}
void ObservableCollection(IEnumerable collection, object context, Action accessMethod, bool writeAccess)
{
lock (collection)
{
accessMethod?.Invoke();
}
}
private void OnContactLoaded(object sender, IGetContactServices e)
{
Contacts.Add(e.getContact);
}
async Task LoadContacts()
{
try
{
await _contactService.RetrieveContacts();
}
catch (TaskCanceledException)
{
Console.WriteLine(“Something Went Wrong.”);
}
}
}
}
Step: 9
Add contact service in App.Xaml.cs file.
App.Xaml.cs
public partial class App : Application
{
IContacts _contactsService;
public App(IContacts contactsService)
{
_contactsService = contactsService;
InitializeComponent();
MainPage = new NavigationPage(new MainPage(_contactsService));
}
Step: 10
All steps are done now, we can create a page for display contacts. Using listview we can bind all contacts and also use a search bar for searching.
MainPage.Xaml
<?xml version=”1.0″ encoding=”utf-8″ ?>
<ContentPage xmlns=”http://xamarin.com/schemas/2014/forms”
xmlns:x=”http://schemas.microsoft.com/winfx/2009/xaml”>
<ContentPage.Content>
<StackLayout>
<SearchBar x:Name=”SearchContact”
HeightRequest=”40″
Text=”{Binding SearchContactText}” />
<ListView ItemsSource=”{Binding ListContacts}”
HasUnevenRows=”True”>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Padding=”10″
Orientation=”Horizontal”>
<Image Source=”{Binding ImageofContact}”
VerticalOptions=”Center”
x:Name=”image”
Aspect=”AspectFit”
HeightRequest=”60″/>
<StackLayout VerticalOptions=”Center”>
<Label Text=”{Binding NameofContact}”
FontAttributes=”Bold”/>
<Label Text=”{Binding Numberofperson[0]}”/>
<Label Text=”{Binding Emailsofperson[0]}”/>
</StackLayout>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage.Content>
</ContentPage>
MainPage.Xaml.cs
using FetchContact.Service;
using FetchContact.ViewModel;
using System.ComponentModel;
using Xamarin.Forms;
namespace FetchContact
{
[DesignTimeVisible(false)]
public partial class MainPage : ContentPage
{
public MainPage(IContacts services)
{
BindingContext = new MainViewModel(services);
InitializeComponent();
}
}
}
Output:
Conclusion
In this blog, we have discussed how to fetch contacts on Android. For fetching the contacts, you need to permit access to your phone contact and also need to install Plugin.CurrentActivity and Acr.UserDialogs packages in the Android project.
Author Bio: Vinod Satapara – Technical Director, iFour Technolab Pvt. Ltd.
Technocrat and entrepreneur with years of experience building large scale enterprise web, cloud and mobile applications using latest technologies like ASP.NET, CORE, .NET MVC, Angular and Blockchain. Keen interest in addressing business problems using latest technologies and have been associated with Mobile Application Development Companies.
ImageLinkedIn: https://www.linkedin.com/in/vinodsatapara/