Как проверить кастомный звук в пуш-уведомлениях?
Что проверяют
Знаете ли вы, что звук уведомления задаётся сразу в трёх местах: в приложении, в payload пуша и в настройках системы, и что iOS и Android устроены тут по-разному. Следом часто спрашивают, почему звук играет на одном устройстве и молчит на другом.
Как отвечать
Сначала уточните механику, от неё зависят тест-кейсы:
- iOS: имя файла передаётся в
aps.soundв payload APNs, сам файл лежит в бандле приложения. Контейнерыaiff,wavилиcaf, длительность меньше 30 секунд, иначе система играет стандартный звук; - Android 8 и новее: звук привязан к
NotificationChannel, файл лежит вres/raw. После создания канала приложение не может поменять ему звук, это делает только пользователь в настройках. Новый звук означает новыйchannel_id; - тип сообщения: у FCM
notification-сообщение в фоне показывает система, а в foreground оно приходит вonMessageReceived, и уведомление строит уже код приложения. Data-сообщение всегда обрабатывает приложение.
Отсюда матрица проверок: приложение на переднем плане, в фоне и выгруженное; беззвучный режим, «Не беспокоить» и режимы фокусировки; громкость уведомлений на нуле; звук выключен для приложения или для канала; обновление поверх версии со старым каналом; несколько пушей подряд. Отдельно негатив: имя файла с опечаткой, файл длиннее лимита, неподдерживаемый формат.
Тестовые пуши удобно слать из консоли Firebase или запросом к FCM HTTP v1 API, симулятор iOS принимает файл .apns через xcrun simctl push. Итоговую проверку делайте на реальных устройствах разных производителей: оболочки Android нередко меняют поведение звуков.
Где спотыкаются
Проверяют только «звук есть». Стандартный и кастомный звук на слух легко спутать, поэтому для теста берут заметно отличающийся файл.
Не знают про кеширование канала на Android: разработчики поменяли звук, а на тестовом устройстве канал уже создан, и играет старый. Чистая установка помогает, но баг у пользователей при обновлении от этого не исчезает.
Тестируют только в фоне. В foreground на iOS уведомление вообще не прозвучит, пока делегат willPresent не вернёт опцию .sound.