Как будет работать пуш менеджер, который показывает уведомления при новых сообщениях из сокета
Что проверяют
Понимаете ли вы, что сокет живёт только вместе с процессом, а Android жёстко ограничивает фоновую работу. Главный уточняющий вопрос: что будет, когда приложение свёрнуто или выгружено системой.
Как отвечать
Разделите задачу на три части: соединение, решение «показывать или нет» и само уведомление.
- соединение: WebSocket через
OkHttpClient.newWebSocket()или Ktor-клиент в синглтоне уровня приложения, наружу отдаётсяSharedFlow<Message>. Жизненный цикл привязан кProcessLifecycleOwner: подключаемся, когда приложение на экране, отключаемся, когда оно ушло в фон; - переподключение: экспоненциальная задержка со случайным разбросом, состояние сети через
ConnectivityManager.NetworkCallback, keep-alive черезpingIntervalу OkHttp. После переподключения догружаем пропущенное по id последнего сообщения; - решение о показе: пользователь в этом чате, значит уведомления нет; открыт другой экран, значит баннер или уведомление; дубли отсекаются по id сообщения;
- уведомление:
NotificationChannel(с Android 8),NotificationCompat.MessagingStyle, свой id на каждый чат, чтобы обновлять, а не плодить уведомления, группировка черезsetGroup. С Android 13 нужно runtime-разрешениеPOST_NOTIFICATIONS, а при target 31 и вышеPendingIntentобязан иметьFLAG_IMMUTABLEилиFLAG_MUTABLE.
Фон: держать сокет постоянно можно только в foreground service с неубираемым уведомлением. С Android 14 для него нужно объявить тип сервиса, и Google Play такие случаи проверяет. Для мессенджера правильная схема другая: в фоне сервер отправляет высокоприоритетное сообщение FCM, приложение получает его в FirebaseMessagingService.onMessageReceived и показывает уведомление, а сокет работает, пока приложение открыто.
Где спотыкаются
Предлагают WorkManager для проверки новых сообщений. Минимальный интервал периодической задачи 15 минут, реальным временем это не назвать.
Держат сокет в обычном фоновом сервисе. В фоне система его останавливает, Doze режет сеть, и уведомления перестают приходить.
Используют один и тот же id в notify(). Каждое новое сообщение затирает предыдущее, и пользователь видит только последнее.