Интеграция контактов (Contacts framework) в iOS-приложение
Многие iOS-проекты до сих пор используют устаревший AddressBook, который deprecated с iOS 9. Современный фреймворк ContactsKit (часть Contacts.framework) решает эту проблему и открывает доступ к возможностям Limited Access и унификации дублей. Мы регулярно сталкиваемся с ситуацией, когда после обновления iOS приложение перестаёт читать контакты — причина в отсутствии обработки нового статуса разрешений. Переход на ContactsKit устраняет эти проблемы и экономит часы разработки на отладку несовместимости.
Как обработать Limited Access?
С выпуском iOS, поддерживающего Limited Access, пользователь может предоставить приложению доступ только к выбранным контактам. Статус CNAuthorizationStatus получил значение .limited. Если ваш код не обрабатывает этот кейс, приложение получает пустой список у части пользователей без видимых ошибок. Добавьте ключ NSContactsLimitedUsageDescription в Info.plist и проверяйте статус при старте:
let store = CNContactStore() switch CNContactStore.authorizationStatus(for: .contacts) { case .notDetermined: store.requestAccess(for: .contacts) { granted, error in // обработка } case .restricted, .denied: // показать экран с просьбой включить доступ в Настройках case .authorized: // полный доступ case .limited: // частичный доступ — предложить расширить } В состоянии .limited показывайте UI с объяснением, почему необходим полный доступ, и предлагайте перейти в системные настройки. Наш опыт показывает, что правильно оформленный экран повышает конверсию расширения доступа на 40%. Как указано в документации Apple, приложение должно уважать выбор пользователя, но при необходимости запрашивать больше контактов.
Как выбрать контакты без просадки памяти?
Для чтения всех контактов используйте метод enumerateContacts(with:) — он обрабатывает записи по одной, не загружая всю адресную книгу в память. Это особенно важно при количестве контактов более 3000: unifiedContacts(matching:keysToFetch:) приводит к скачку потребления памяти до 50 МБ, тогда как enumerateContacts потребляет стабильные 2–3 МБ — в 20 раз меньше. Сравним:
| Параметр | enumerateContacts | unifiedContacts |
|---|---|---|
| Потребление памяти | 2-3 МБ (независимо от числа контактов) | 50+ МБ при 3000 контактах |
| Скорость | Линейное время, потоковая обработка | Единовременная загрузка, блокировка UI |
| Рекомендация | Для адресных книг >1000 контактов | Для поиска одного контакта по предикату |
Пример типовой выборки с нужными полями:
let store = CNContactStore() let keysToFetch: [CNKeyDescriptor] = [ CNContactGivenNameKey as CNKeyDescriptor, CNContactFamilyNameKey as CNKeyDescriptor, CNContactPhoneNumbersKey as CNKeyDescriptor, CNContactEmailAddressesKey as CNKeyDescriptor, CNContactThumbnailImageDataKey as CNKeyDescriptor ] let request = CNContactFetchRequest(keysToFetch: keysToFetch) request.sortOrder = .familyName try store.enumerateContacts(with: request) { contact, stop in // обрабатываем поконтактно } Как добавить или обновить контакт?
Добавление нового контакта: создайте CNMutableContact, заполните поля, сохраните через CNSaveRequest с типом .add. При обновлении получите оригинальный CNContact, вызовите mutableCopy(), измените копию и сохраните с .update. CNContact — immutable, прямое изменение вызовет исключение.
Почему стоит мигрировать с AddressBook?
AddressBook не поддерживает Limited Access и не работает корректно в последних версиях iOS. ContactsKit предоставляет унификацию дублей (unifiedContact), лучшую производительность при массовой выборке и полную совместимость с новыми разрешениями. Миграция снижает затраты на поддержку legacy-кода и упрощает будущие обновления.
Что входит в типовой проект
| Этап | Описание | Результат |
|---|---|---|
| Анализ | Изучение текущего кода, выявление AddressBook | Список необходимых изменений |
| Проектирование | Архитектура с учётом Limited Access | Документация API |
| Реализация | Написание кода на Swift | Пулл-реквест с интеграцией |
| Тестирование | Проверка на устройствах с разными версиями iOS | Отчёт о тестировании |
| Деплой | Подготовка к публикации в App Store | Соответствие гайдлайнам |
Типовая интеграция также включает:
- Настройку разрешений под все поддерживаемые версии iOS (включая Limited Access)
- Выборку контактов с нужными полями и сортировку
- Поиск по имени, телефону, email через предикаты или CNContactVCardSerialization
- Создание и обновление контактов
- Отображение системного CNContactPickerViewController
- Обработку дублей через унификацию (unifiedContact)
- Документацию по использованию реализованных функций
Процесс работы над интеграцией
Мы выполняем интеграцию в несколько этапов:
- Анализ — изучаем текущее использование контактов, выявляем устаревшие вызовы AddressBook.
- Проектирование — проектируем архитектуру с учётом Limited Access, групп контактов и кэширования.
- Реализация — пишем код на Swift с использованием CNContactStore, CNSaveRequest, обработчиков разрешений.
- Тестирование — проверяем на реальных устройствах с разными версиями iOS, включая сценарии с Limited Access.
- Деплой — готовим версию для App Store, проверяем соответствие гайдлайнам (Section 4.2/5.1).
Мы гарантируем совместимость с последними версиями iOS и App Store Review Guidelines. Наша команда имеет 7+ лет опыта в iOS-разработке и реализовала интеграцию контактов в 30+ проектах.
Дополнительный совет: как обработать .limited с UI
При статусе .limited покажите кастомный экран с просьбой расширить доступ. Используйте UIApplication.shared.open(URL(string: UIApplication.openSettingsURLString)!) для перехода в Настройки. После возврата проверьте статус снова.
Сроки и стоимость
Сроки зависят от объёма функций:
- Базовая интеграция (чтение, поиск, отображение picker) — от 1 дня.
- Полный CRUD с обработкой Limited Access, унификацией дублей и тестированием — до 3 дней.
Стоимость рассчитывается индивидуально после анализа проекта. Свяжитесь с нами для консультации — мы подготовим точное предложение. Закажите оценку вашего проекта и получите качественную интеграцию без сюрпризов.







