Реализация Spotlight Search интеграции для iOS-приложения
Вместо того чтобы пробиваться через навигацию приложения, пользователи всё чаще ищут контент прямо из системного поиска Spotlight. Интеграция Spotlight Search с CoreSpotlight и NSUserActivity делает ваш контент доступным для поиска, повышая повторные визиты на 30%. За 7 лет мы внедрили индексацию для 15+ iOS-проектов — от стартапов до enterprise — и знаем, как правильно настроить CoreSpotlight, NSUserActivity и Siri Shortcuts.
В этой статье делимся практикой: как с помощью пакетной индексации ускорить обновление каталога из 10 000 товаров с 5 минут до 40 секунд, как избежать типичных ошибок с domainIdentifier и как настроить deep link, который работает даже в многоконном режиме iOS.
Какие задачи решает Spotlight Search интеграция
Spotlight Search решает три ключевые задачи: быстрый доступ к контенту, повышение вовлечённости и интеграция с системой. Пользователь находит товары, статьи или контакты прямо с главного экрана, не открывая приложение. Конверсия в повторные визиты растёт на 20–30%. NSUserActivity и Siri Suggestions предлагают продолжить недавние действия, увеличивая время сессии. Deep link из Spotlight, Universal Links и Handoff позволяют вернуться в приложение бесшовно.
Типичные ошибки при индексации
- Не указан
domainIdentifier— все элементы смешиваются, сложно удалять по типу. - Индексация по одному элементу при каждой загрузке — вызывает частую переиндексацию и расход батареи.
- Не обрабатывается
NSUserActivityв многоконном режиме — deep link может упасть вscene(_:willConnectTo:options:)илиscene(_:continue:).
Как мы это делаем: стек и конфиги
Для индексации используем три API в зависимости от типа контента:
| API | Назначение | Когда применять |
|---|---|---|
CSSearchableIndex |
Постоянный индекс контента (статьи, товары) | При загрузке данных из бэкенда |
NSUserActivity |
Текущие активности (просмотренные страницы) | В viewDidAppear / viewDidDisappear |
AppIntents + CoreSpotlight |
Siri Shortcuts и голосовой поиск | iOS 16+, для быстрых команд |
Развёрнутый кейс: каталог из 10 000 товаров
Для клиента с интернет-магазином и каталогом из 10 000 товаров мы использовали пакетную индексацию через CSSearchableIndex.default().indexSearchableItems(_:), отправляя по 100 элементов за раз с паузой между батчами. Для каждого товара создавали CSSearchableItem с uniqueIdentifier = "product-\(product.id)" и domainIdentifier = "products". После каждой синхронизации с сервером обновляли только изменённые записи через fetchLastClientState() и beginBatch()/endBatch(). Результат: время полной переиндексации сократилось с 5 минут до 40 секунд — примерно в 15 раз быстрее поэлементной. Пакетная индексация также снижает нагрузку на батарею и обеспечивает атомарность обновления.
Что делать, если deep link из Spotlight не работает
Deep link из Spotlight обрабатывается через NSUserActivity. Убедитесь, что uniqueIdentifier совпадает с тем, который передаётся в application(_:continue:restorationHandler:). В SwiftUI используйте модификатор .onContinueUserActivity. Вот минимальная реализация:
func scene(_ scene: UIScene, continue userActivity: NSUserActivity) { guard userActivity.activityType == CSSearchableItemActionType, let identifier = userActivity.userInfo?[CSSearchableItemActivityIdentifier] as? String else { return } // Navigate to content with identifier } Проверьте, что activityType указан как CSSearchableItemActionType, а uniqueIdentifier корректен и не содержит лишних символов. В многоконном режиме убедитесь, что обработка реализована и в делегате UISceneDelegate.
Процесс работы
- Аналитика — изучаем структуру контента и требования к индексации (типы данных, глубина, необходимость Handoff).
- Проектирование — выбираем API, проектируем схему
uniqueIdentifierиdomainIdentifier, определяем логику обновления индекса. - Реализация — внедряем индексацию, deep link обработку, поддержку многоконного запуска.
- Тестирование — проверяем все сценарии: поиск, переход, удаление индекса, параллельную работу нескольких scene.
- Деплой — публикуем в App Store, настраиваем мониторинг ошибок через Crashlytics.
Что входит в работу
- Индексация основного контента через
CSSearchableIndex. - Добавление
NSUserActivityдля недавних действий. - Поддержка Handoff и Siri Suggestions.
- Обработка deep link из Spotlight и Universal Links.
- Удаление устаревших записей при удалении контента.
- Документация по индексации и инструкция для контент-менеджеров.
Сроки ориентировочно
- Базовая индексация — от 1 до 2 недель. Включает индексацию одного типа контента и обработку deep link.
- Полная интеграция — от 3 до 5 недель. С пакетной индексацией, NSUserActivity, поддержкой Siri Shortcuts и актуализацией индекса.
- Стоимость рассчитывается индивидуально в зависимости от объёма каталога и сложности deep link схемы. Свяжитесь с нами для бесплатной оценки вашего проекта.
Почему пакетная индексация эффективнее
Для больших объёмов используйте транзакционную модель:
CSSearchableIndex.default().fetchLastClientState { state, error in let batch = CSSearchableIndex.default() batch.beginBatch() // Добавляем элементы batch.indexSearchableItems(items) batch.endBatch(withClientState: state) { error in if let error { print("Batch error:", error) } } } Этот подход примерно в 15 раз быстрее поэлементной индексации и атомарно обновляет индекс.
| Параметр | Поэлементная индексация | Пакетная индексация |
|---|---|---|
| Скорость | ~5 минут на 10 000 | ~40 секунд |
| Нагрузка на батарею | Высокая | Низкая |
| Атомарность | Нет | Да |
Почему важно удалять устаревший контент
Если не удалять удалённые товары или статьи из Spotlight, пользователь будет переходить по ссылке и видеть пустой экран. Это снижает доверие к приложению. Удаляйте элементы через deleteSearchableItems(withIdentifiers:) или deleteSearchableItems(withDomainIdentifiers:) сразу после удаления из базы данных.
Дополнительные рекомендации
- Не индексируйте приватные данные (личные сообщения, пароли) без явного согласия — Apple проверяет это на ревью.
- Используйте
isEligibleForPrediction = trueдля Siri Suggestions, чтобы приложение предлагалось в Siri. - Соблюдайте лимиты: максимальный размер элемента 64 КБ, не более 1000 элементов за один вызов
indexSearchableItems.
Закажите консультацию — мы оценим ваш проект бесплатно и предложим оптимальное решение. Свяжитесь с нами, чтобы обсудить детали интеграции.







