Известные ограничения 5.x
Эта страница описывает параметры публичного API SDK, которые в текущей версии (5.x) не применяются или применяются с ограничениями, а также поведенческие особенности, которые нужно учесть при интеграции. Параметры, не вошедшие в эту таблицу, работают как задокументировано.
Параметры с приоритетом серверной настройки
Перечисленные ниже свойства ChatConfig помечены @Deprecated. Они применяются рантаймом как fallback — если для соответствующей настройки не пришло значение с сервера. Формат применения в коде: serverValue ?: clientValue — серверная настройка всегда побеждает.
Для production не полагайтесь на клиентские значения: серверная конфигурация может переопределить их без обновления приложения.
| Параметр | Поведение | Замечания |
|---|---|---|
ChatConfig.keepWebSocketActive | Fallback к клиентскому значению, если сервер не прислал keepSocketActive | Подвержено стандартным ограничениям фоновой работы Android (Doze, App Standby) — конкретного behavior change для WebSocket в Android 15 нет |
ChatConfig.keepSocketActiveDuringOperatorSession | Fallback к клиентскому значению | — |
ChatConfig.searchEnabled | Fallback к клиентскому значению; управляет видимостью UI-поиска по истории | — |
ChatConfig.linkPreviewEnabled | Fallback к клиентскому значению; включает превью ссылок (OpenGraph) | — |
ChatConfig.voiceRecordingEnabled | Fallback к клиентскому значению; управляет видимостью кнопки записи голоса | — |
ChatConfig.autoScrollToLatest | Fallback к клиентскому значению; маппится на серверное поле scrollToLatest | Имена клиентского и серверного полей отличаются |
ChatConfig.surveyCompletionDelay | Fallback к клиентскому значению; дефолт 3 сек, если значение не задано ни клиентом, ни сервером | — |
ChatConfigCore.historyLoadingCount | Поле объявлено как val — переопределить через ChatConfig нельзя. Используется как fallback при отсутствии серверной настройки | Менять значение можно только пересборкой ChatConfigCore целиком |
Поля без эффекта в текущей версии
| Параметр | Поведение | Замечания |
|---|---|---|
ChatFlow.fullScreenMode | Помечено @Deprecated («с момента targetSdk = 35 в ChatCenterUI данный параметр более не используется — всегда true»), рантаймом не читается. Edge-to-edge режим определяется поведением Android в приложении-интеграторе при targetSdk = 35 и темой вашей Activity | Установка значения не оказывает эффекта |
ChatTexts (целиком) | Все поля помечены @Deprecated. Для локализации UI-строк переопределяйте ecc_*-ключи в strings.xml | См. Локализация |
Поведение при разрыве WebSocket-соединения
Начиная с версии 5.21.0 в SDK реализовано автоматическое переподключение к WebSocket. По умолчанию оно выключено и включается параметром isReconnectEnabled в WSConfig — см. Network config.
Когда isReconnectEnabled = false (значение по умолчанию), после разрыва WebSocket сокет закрывается, новые сообщения не отправляются и не приходят, а ожидающие в очереди остаются в статусе PENDING / FAILED до восстановления сессии.
Что нужно сделать на стороне приложения:
- Подпишитесь на
ConnectivityManager.NetworkCallback, чтобы отслеживать восстановление сети; - При восстановлении сети повторно вызовите
chatCenterUI.authorize(user, auth). Добавьте на стороне приложения guard от повторных вызовов с теми же параметрами — SDK не делает early-return и при идентичных аргументах переустанавливает внутреннее соединение; - Покажите пользователю офлайн-индикатор до восстановления сессии;
- Реакцию на разрыв обрабатывайте через
ChatCenterUIListener.networkErrorReceived(error)— см. Методы → Errors. Этот callback приходит не на main thread — рекомендуемый идиом переключения и полную таблицу потоков см. в Делегаты → Потоки callback'ов.
Экран восстановления состояния
Если экраны SDK (чат, галерея вложений, диалоги SDK) открываются системой до того, как приложение успело вызвать init(...) / initAsync(...), SDK защищает интеграцию от падений:
- поверх
ChatFragmentотображается полноэкранный плейсхолдер с надписью «Восстановление состояния…» (строкаecc_restoring_state); - галерея вложений (
ImagesActivity) и диалоги SDK (BottomSheet,Dialog) закрываются автоматически.
Сценарий возникает, например, при системном пересоздании активити (Activity recreation, low memory), когда пользовательский процесс был убит, а Android восстановил последний экран до того, как ваш Application.onCreate успел проинициализировать SDK.
Что нужно сделать на стороне приложения:
- Вызывайте
init(...)/initAsync(...)как можно раньше — вApplication.onCreate, а не вActivity.onCreate. Это сокращает время отображения плейсхолдера до минимума. - Если у вас лаунчер-активити выполняет дополнительные действия перед
init(...), рассмотрите переход на асинхронную инициализациюinitAsync(...), чтобы UI приложения не зависел от тяжёлых операций SDK. - Цвета плейсхолдера и текст можно переопределить — см. Дизайн-система → Цвета → Экран восстановления состояния и Локализация.
SSL
allowUntrustedCertificates = true в production-сборкеПараметр предназначен только для development-сборки против локального тестового сервера. При установке в true полностью отключается TLS-проверка и соединение становится уязвимым к MITM. Значение флага не зависит от типа сборки — если его случайно оставить, он сработает и в release.
Что нужно сделать перед релизом:
- Явно установите
SSLPinningConfig(allowUntrustedCertificates = false)в production-конфиге; - Не читайте значение из remote-config / env, который может быть переключён в продакшене;
- Не переопределяйте значение через BuildType-overrides в release-сборке.
См. также: Network config и Troubleshooting.
Поведенческие особенности
Гонка при параллельном вызове методов ChatCenterUI
ChatCenterUI только с главного потокаМетоды ChatCenterUI (init(), authorize(), logout(), send() и др.) необходимо вызывать только с главного потока. Параллельный вызов из нескольких потоков не поддерживается и может привести к нежелательным эффектам — например, к повторной регистрации push-токена или к рассинхронизации между WebSocket-сессией и локальным состоянием.
Что нужно сделать на стороне приложения:
- вызывайте методы
ChatCenterUIтолько с main thread; если требуется вызов из фонового потока — оборачивайте черезrunOnUiThread { ... }илиHandler(Looper.getMainLooper()).post { ... }; - если в приложении несколько точек, которые могут вызвать
authorize(...)(например, push-обработчик и splash screen), добавьте собственный guard / сериализацию вызовов на стороне приложения; - не вызывайте
authorize(...)повторно «на всякий случай» — при идентичных параметрах SDK переустанавливает внутреннее соединение (см. также раздел «Поведение при разрыве WebSocket-соединения»).
ChatConfig.equals() нестабилен между API levelsРеализация equals() для ChatConfig сравнивает поле notificationImportance только начиная с Android 7.0 (API 24, Build.VERSION_CODES.N). На более старых API два конфига с разными notificationImportance будут считаться равными, на API ≥ 24 — нет.
Симптом: объекты ChatConfig нельзя надёжно использовать как ключ в HashMap/Set или сравнивать через == в логических условиях, особенно если у вас в кодовой базе минимальный API ниже 24. Храните единственный экземпляр конфига и проверяйте идентичность по ===.
UnreadMessagesController — enum-singletonUnreadMessagesController доступен как INSTANCE-singleton. Это упрощает доступ к контроллеру в продакшене, но усложняет unit-тесты: подменить INSTANCE на тестовый double без рефлексии нельзя.
Что нужно сделать на стороне приложения: оборачивайте UnreadMessagesController в собственный интерфейс/фасад вашего приложения и инжектите этот фасад в код, который требует unit-тестирования.
ChatAuthType.COOKIES — без референс-примераВ enum-классе ChatAuthType есть значение COOKIES, но в публичной документации задокументирован только HEADERS. COOKIES рабочий, но без покрывающих примеров и регрессионных тестов; используйте только при предварительном согласовании с поддержкой edna.
ChatUpdateProcessor coroutine scopes
ChatUpdateProcessor могут прилетать на любой threadВ ChatUpdateProcessor каждый postX(...)-метод эмитит событие из нового CoroutineScope(Dispatchers.Unconfined) — поэтому коллектор может получить событие на потоке OkHttp WebSocket или ином произвольном.
Не используйте flowOn(Dispatchers.Main) — этот оператор меняет контекст upstream-эмиттера, а не вашего коллектора, и в данном случае ничего не переключит.
Корректные варианты:
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
chatUpdateProcessor.newMessageFlow.collect { item ->
withContext(Dispatchers.Main) {
// безопасные UI-вызовы
}
}
}
}
lifecycleScope стартует на Dispatchers.Main.immediate, поэтому без withContext уже корректно переключитесь на main, если ваш collect-блок не делает фоновую работу.
Какие callback'и на каком потоке. unreadMessageCountChanged, exceptionReceived, urlClicked доставляются на main thread. networkErrorReceived всегда приходит с фонового потока. Резюме потоков и рекомендуемый идиом переключения — в каноническом разделе Делегаты → Потоки callback'ов.
Подробнее о подписках на эту шину — Методы → Делегаты → Продвинутые сценарии.
Связанные разделы
- Дизайн-система: обзор — уровни кастомизации.
- Troubleshooting — диагностика и production-чеклист.
- Network config — допустимые сочетания SSL-параметров.
- Errors (методы) — обработка
networkErrorReceivedи retry-стратегия. - Доступность — отдельный раздел с a11y-ограничениями.
- Локализация — миграция с
ChatTextsнаecc_*-ключи вstrings.xml. - Темы —
ChatThemeи три формы конструктора. - Компоненты —
ChatComponents, гдеChatTextsисторически передавался как параметрtext. - Потоки (Flows) —
ChatFlow.fullScreenModeживёт здесь.