TGViewer
Мобильный трудоголик Мобильный трудоголик @hardworkerit · 1.64K subscribers
Post #342 1.15K
🔢 Тихий режим для push-уведомлений: обход системных ограничений iOS.

Отключить звук уведомлений - кажется, одна из самых простых пользовательских настроек. Но для iOS-разработчика эта кнопка превращается в сложную архитектурную задачу. Почему? Потому что звук push-уведомления контролируется не приложением, а серверным payload, который iOS исполняет как приказ. Пользователь ждет тишины, а система послушно проигрывает звук из этого самого payload. Разрыв между ожиданием и реальностью можно устранить, но для этого потребуется нестандартный подход, затрагивающий саму цепочку доставки уведомления.


Архитектурная головоломка и ее решение:

Основная сложность заключается в разделенности процессов. Основное приложение и сервис, обрабатывающий входящие пуши (Notification Service Extension), работают в изолированных песочницах. Они не имеют прямого доступа к памяти друг друга. Стандартный UserDefaults здесь бесполезен.

Ключ к решению - App Groups. Это технология, позволяющая выделить область общей памяти, доступную для нескольких компонентов одного приложения (основной таргет и экстеншены). Настройка происходит через добавление кастомной capability в оба таргета и использование идентичного suiteName для инициализации UserDefaults(suiteName:).


Сердце системы - Notification Service Extension:

Этот extension - единственная точка в системе iOS, где можно программно модифицировать контент удаленного уведомления до его показа пользователю. Он активируется системой при получении пуша, имеет строго ограниченное время на выполнение (порядка 30 секунд) и должен вызвать contentHandler. Логика работы экстеншена:

🔵Получить входящий контент (UNNotificationRequest).

🔵Проверить в общих UserDefaults (через App Group), активен ли звук в настройках приложения.

🔵Если звук отключен - удалить свойство .sound из UNMutableNotificationContent.

🔵Передать модифицированный контент в contentHandler.

Именно этот шаг позволяет обмануть систему, заставив ее показать уведомление с визуальной частью, но без звукового сопровождения, даже если сервер изначально его отправил.


Синхронизация состояния - менеджер настроек:

В основном приложении необходим менеджер, который будет записывать значение настройки звука одновременно в стандартные UserDefaults (для быстрого доступа в самом приложении) и в общие UserDefaults App Group (для доступа extension). Это гарантирует консистентность данных независимо от того, запущено ли основное приложение в момент прихода пуша.


Обработка в foreground - делегат центра уведомлений:

Extension работает только для уведомлений, пришедших, когда приложение в фоне или заблокировано. Для случая, когда приложение активно, модификацию необходимо проводить в методе userNotificationCenter(_:willPresent:withCompletionHandler:). Здесь, основываясь на тех же настройках, мы определяем, передавать ли в completionHandler опцию .sound.


Критически важные детали реализации:

🔵Членство в таргетах (Target Membership): файлы, которые должны быть доступны и основному приложению, и extension (например кастомный звуковой файл или GoogleService-Info.plist для Firebase), должны быть отмечены галочками в обоих таргетах.

🔵Точность идентификатора App Group: строка-идентификатор в .entitlements файлах должна быть абсолютно идентичной в основном таргете и в таргете extension. Чувствительна к регистру.

🔵Ограничение времени: код в didReceive extension должен быть максимально эффективным. Если обработка не успевает, система вызовет serviceExtensionTimeWillExpire, где нужно отдать хотя бы исходный контент.


🔗 Ссылка на подробную статью


💡 Вывод:

Реализация пользовательского управления звуком уведомлений - это блестящий пример того, как понимание архитектурных возможностей iOS позволяет создавать кастомный UX вопреки ограничениям стандартных API. Решение элегантно обходит главное препятствие: отсутствие возможности напрямую влиять на серверный payload.


➡️ Подписаться на канал
Мобильный трудоголик
  • ❤ 18
  • 👍 9
  • 🔥 3
  • 🤔 1
  • 🙏 1
More from @hardworkerit
  1. Oct 2, 2026👣 Архитекторы, тестировщики и кодеры. Создаем мультиагентную команду Разработка с ИИ-аген…
  2. Oct 1, 2026🔢 Работа с Picture-in-Picture в iOS. Picture-in-Picture - системная функция iOS, которая…
  3. Sep 29, 2026🔢 Управление тулбарами на iPhone Duo. На iPhone Duo элементы управления навигацией, дейст…
  4. Sep 27, 2026🔢 Новые возможности Hashable в Swift 6.4 В Swift 6.4 добавили Hashable для нескольких тип…
  5. Sep 25, 2026🔢 Приватные свойства больше не ломают memberwise инициализатор в Swift 6.4 Swift автомати…
  6. Sep 24, 2026👨‍💻 Почему разработчики ненавидят своих менеджеров. Всем привет! Сегодня хочу разобрать…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →