How to create an iOS call directory extension in Xamarin for blocking thousands of phone numbers

A call directory extension is used to block or identify phone numbers on an iPhone, phone numbers the user don't have in their contact list.


TL;DR: Because iOS app extensions have very limited resources, it is difficult to load many thousand phone numbers into the call directory without the extension crashing. This is my attempt to get around this issue.

This post expands on Xamarin's tutorial for how to create a call directory extension, which you probably should read first, here: Xamarin: Implementing a Call Directory Extension

The end result of that tutorial is a call directory extension that can block or identify two hard coded phone numbers.

Based on Xamarin's sample code, I have further made an accompanying app that saves some thousand phone numbers in text files. The app saves the phone numbers in files called phonenumbers.0.txt, phonenumbers.1.txt, etc., with a few hundred phone numbers in each file.

It is really important that the phone numbers are in numerical order, smallest number first. You don't want to do any sorting or filtering in the extension, do all that kind of memory intensive tasks in the app when you create the text files.

Another important nugget of information, is that a phone number has to be saved including the country code. So American phone numbers always start with 1, and Norwegian phone numbers always start with 47. This is my modified method to add phone numbers from the text files to the phone's identification directory:

private bool AddIdentificationPhoneNumbers ( CXCallDirectoryExtensionContext context) { var fileIndex = 0; var fileName = FileHelper.GetPhoneFilePath(fileIndex); // Read all existing files while (File.Exists(fileName)) { // Memory is limited, so flush memory // after each file is read using (new NSAutoreleasePool()) { // The text files have one phone number per line foreach (var phoneString in File.ReadAllLines(fileName)) { // Parse string of format // "4722334455;Company name" var delimiterIndex = phoneString.IndexOf(';'); if (delimiterIndex <= -1 || delimiterIndex > phoneString.Length) { continue; } var phoneNumberString = phoneString.Substring(0, delimiterIndex); long phoneNumber; if (!long.TryParse(phoneNumberString, out phoneNumber)) { continue; } // Add phone number to the // phone's call directory callDirectoryContext.AddIdentificationEntry( phoneNumber, phoneString.Substring(delimiterIndex + 1) ); } // Find filename of next file fileName = FileHelper .GetPhoneFilePath(++fileIndex); } // Free memory to read next file GC.Collect(); } } private string GetPhoneFilePath(int index) { var fileManager = new NSFileManager(); return Path.Combine( fileManager .GetContainerUrl("") .Path, $"phonenumbers.{index}.txt"); }

Categories: .NET C# Xamarin