Skip to main content
Version: 5.21.0

Known limitations 5.x

This page describes public SDK API parameters that are not applied — or are applied with restrictions — in the current version (5.x), along with behavioral notes that you should keep in mind when integrating. Parameters not listed here work as documented.

Parameters overridden by the server

The ChatConfig properties listed below are marked @Deprecated. They are applied at runtime as a fallback — only if no value arrived from the server for the corresponding setting. The pattern in code is: serverValue ?: clientValue — the server setting always wins.

For production, do not rely on client-side values: the server configuration can override them without an app update.

ParameterBehaviorNotes
ChatConfig.keepWebSocketActiveFalls back to the client value if the server does not send keepSocketActiveSubject to standard Android background limitations (Doze, App Standby) — there is no specific WebSocket behavior change on Android 15
ChatConfig.keepSocketActiveDuringOperatorSessionFalls back to the client value
ChatConfig.searchEnabledFalls back to the client value; controls the visibility of UI history search
ChatConfig.linkPreviewEnabledFalls back to the client value; enables link previews (OpenGraph)
ChatConfig.voiceRecordingEnabledFalls back to the client value; controls the visibility of the voice recording button
ChatConfig.autoScrollToLatestFalls back to the client value; mapped to the server field scrollToLatestClient and server field names differ
ChatConfig.surveyCompletionDelayFalls back to the client value; defaults to 3 s if neither client nor server provides a value
ChatConfigCore.historyLoadingCountThe field is declared as val — it cannot be overridden via ChatConfig. Used as a fallback in the absence of a server settingThe value can only be changed by rebuilding ChatConfigCore entirely

Fields with no effect in the current version

ParameterBehaviorNotes
ChatFlow.fullScreenModeMarked @Deprecated ("since targetSdk = 35, ChatCenterUI no longer uses this parameter — it is always true"), not read at runtime. Edge-to-edge mode is determined by Android's behavior in the integrating app at targetSdk = 35 and your Activity themeSetting a value has no effect
ChatTexts (entire class)All fields are marked @Deprecated. To localize UI strings, override ecc_* keys in strings.xmlSee Localization

WebSocket disconnect behavior

Starting with version 5.21.0, the SDK supports automatic WebSocket reconnect. It is disabled by default and enabled via the isReconnectEnabled parameter in WSConfig — see Network config.

When automatic reconnect is disabled

When isReconnectEnabled = false (the default), after a WebSocket disconnect the socket is closed, new messages are not sent or received, and queued messages remain in PENDING / FAILED status until the session is restored.

What to do on the app side:

  • Subscribe to ConnectivityManager.NetworkCallback to track network restoration;
  • When the network is restored, re-call chatCenterUI.authorize(user, auth). Add a guard on the app side against repeated calls with identical parameters — the SDK does not perform an early-return and re-establishes the internal connection on identical arguments;
  • Show an offline indicator to the user until the session is restored;
  • Handle the disconnect via ChatCenterUIListener.networkErrorReceived(error) — see Methods → Errors. This callback is not delivered on the main thread — see the recommended switching idiom and the full thread table in Delegates → Callback threads.

State restoration screen

If SDK screens (chat, attachment gallery, SDK dialogs) are opened by the system before the app has called init(...) / initAsync(...), the SDK protects the integration from crashes:

  • a full-screen placeholder with the text "Restoring state…" (string ecc_restoring_state) is shown over ChatFragment;
  • the attachment gallery (ImagesActivity) and SDK dialogs (BottomSheet, Dialog) close automatically.

This scenario occurs, for example, during system activity recreation (Activity recreation, low memory), when the user process was killed and Android restored the last screen before your Application.onCreate had a chance to initialize the SDK.

What to do on the app side:

  • Call init(...) / initAsync(...) as early as possible — in Application.onCreate, not in Activity.onCreate. This minimizes the time the placeholder is shown.
  • If your launcher activity performs additional work before init(...), consider switching to asynchronous initialization with initAsync(...) so that the app's UI does not depend on heavy SDK operations.
  • The placeholder colors and text can be overridden — see Design system → Colors → State restoration screen and Localization.

SSL

Do not enable allowUntrustedCertificates = true in a production build

This parameter is intended only for development builds against a local test server. Setting it to true fully disables TLS validation and leaves the connection vulnerable to MITM. The flag's value does not depend on the build type — if you accidentally leave it enabled, it will take effect in release as well.

What to do before release:

  • Explicitly set SSLPinningConfig(allowUntrustedCertificates = false) in the production configuration;
  • Do not read the value from a remote-config / env source that could be flipped in production;
  • Do not override the value via BuildType overrides in the release build.

See also: Network config and Troubleshooting.

Behavioral notes

Race condition on parallel ChatCenterUI calls

Call ChatCenterUI methods only from the main thread

ChatCenterUI methods (init(), authorize(), logout(), send(), etc.) must be called only from the main thread. Parallel calls from multiple threads are not supported and may lead to undesired effects — for example, duplicate push-token registration or desynchronization between the WebSocket session and the local state.

What to do on the app side:

  • Call ChatCenterUI methods only from the main thread; if you need to invoke them from a background thread, wrap the call with runOnUiThread { ... } or Handler(Looper.getMainLooper()).post { ... };
  • If your app has several entry points that may call authorize(...) (e.g., a push handler and a splash screen), add your own guard / serialization on the app side;
  • Do not call authorize(...) again "just in case" — with identical parameters, the SDK re-establishes the internal connection (see also the WebSocket disconnect behavior section).
ChatConfig.equals() is unstable across API levels

The equals() implementation for ChatConfig only compares the notificationImportance field starting from Android 7.0 (API 24, Build.VERSION_CODES.N). On older APIs, two configs with different notificationImportance are considered equal; on API ≥ 24, they are not.

Symptom: ChatConfig instances cannot be reliably used as keys in HashMap/Set or compared via == in conditional logic, especially if your codebase's minimum API is below 24. Keep a single config instance and check identity with ===.

UnreadMessagesController is an enum singleton

UnreadMessagesController is available as an INSTANCE-singleton. This simplifies controller access in production but complicates unit tests: you cannot substitute INSTANCE with a test double without reflection.

What to do on the app side: wrap UnreadMessagesController in your own interface/facade and inject that facade into the code that requires unit testing.

ChatAuthType.COOKIES — no reference example

The ChatAuthType enum class has a COOKIES value, but only HEADERS is documented publicly. COOKIES works but lacks examples and regression coverage; use it only after prior alignment with edna support.

ChatUpdateProcessor coroutine scopes

Subscriptions to the advanced ChatUpdateProcessor bus may arrive on any thread

In ChatUpdateProcessor, every postX(...) method emits an event from a new CoroutineScope(Dispatchers.Unconfined) — therefore the collector may receive an event on the OkHttp WebSocket thread or any other arbitrary thread.

Do not use flowOn(Dispatchers.Main) — this operator changes the context of the upstream emitter, not your collector, and in this case will not switch anything.

Correct alternatives:

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) {
// safe UI calls
}
}
}
}

lifecycleScope starts on Dispatchers.Main.immediate, so without withContext you'll already be on main if your collect block does not perform background work.

Which callbacks on which thread. unreadMessageCountChanged, exceptionReceived, urlClicked are delivered on the main thread. networkErrorReceived is always delivered from a background thread. A thread summary and the recommended switching idiom are in the canonical section Delegates → Callback threads.

For more on subscribing to this bus, see Methods → Delegates → Advanced scenarios.