I'm building an Android app with chat functionalities using Amazon IVS Chat Client Messaging SDK and I stucked with handling lifecycle of the chat room and web socket connection.
According to the documentation Disconnect from a Chat Room:
Because the WebSocket connection will stop working after a short time when the application is in a background state, we recommend that you manually connect/disconnect when transitioning from/to a background state. To do so, match the room.connect() call in the onResume() lifecycle method, on Android Activity or Fragment, with a room.disconnect() call in the onPause() lifecycle method.
So I implemented that way, but I never get connected state back again (I need to close activity and open it again, then all works fine):
🟢 Room 58a2b001-7c9c-4c2b-935b-ef07e74cc2c3 (CONNECTING) Changed state: DISCONNECTED -> CONNECTING
🟤 Room 58a2b001-7c9c-4c2b-935b-ef07e74cc2c3 (CONNECTING) Calling onConnecting
🟤 Room 58a2b001-7c9c-4c2b-935b-ef07e74cc2c3 (CONNECTING) Requesting token
🟤 Room 58a2b001-7c9c-4c2b-935b-ef07e74cc2c3 (CONNECTING) Did receive token: ChatToken(token=CHAT_TOKEN_HERE#1, sessionExpirationTime=Fri Sep 08 13:20:24 GMT+02:00 2023, tokenExpirationTime=Fri Sep 08 13:20:24 GMT+02:00 2023)
🟤 Room 58a2b001-7c9c-4c2b-935b-ef07e74cc2c3 (CONNECTING) Connecting to web socket wss://edge.ivschat.us-east-1.amazonaws.com
🟢 Room 58a2b001-7c9c-4c2b-935b-ef07e74cc2c3 (CONNECTED) Changed state: CONNECTING -> CONNECTED
🟤 Room 58a2b001-7c9c-4c2b-935b-ef07e74cc2c3 (CONNECTED) Calling onConnected
🟢 Room 58a2b001-7c9c-4c2b-935b-ef07e74cc2c3 (CONNECTED) Connected
// App moves to ON_PAUSE state
🟢 Room 58a2b001-7c9c-4c2b-935b-ef07e74cc2c3 (DISCONNECTED) Changed state: CONNECTED -> DISCONNECTED
🟤 Room 58a2b001-7c9c-4c2b-935b-ef07e74cc2c3 (DISCONNECTED) Calling onDisconnected
🟢 Room 58a2b001-7c9c-4c2b-935b-ef07e74cc2c3 (DISCONNECTED) Did receive socket onClosing event: disconnect reason CLIENT_DISCONNECT, socket code 1000, socket reason:
🟢 Room 58a2b001-7c9c-4c2b-935b-ef07e74cc2c3 (DISCONNECTED) Reconnect not needed: disconnect reason CLIENT_DISCONNECT
// APP moves to ON_RESUME state
🟢 Room 58a2b001-7c9c-4c2b-935b-ef07e74cc2c3 (CONNECTING) Changed state: DISCONNECTED -> CONNECTING
🟤 Room 58a2b001-7c9c-4c2b-935b-ef07e74cc2c3 (CONNECTING) Calling onConnecting
🟤 Room 58a2b001-7c9c-4c2b-935b-ef07e74cc2c3 (CONNECTING) Requesting token
I keep seeing Requesting token
. For the demo app I found here, I noticed that you didn't execute disconnect method explicitly when app lifecycle changes state to Pause/Stop. Was it implemented on purpose?
Please take a look on implementation of wrapper for ChatRoom
class. Did I miss something?.:
internal class ChatRemoteApiImpl @Inject constructor(
private val webinarRemoteApi: WebinarRemoteApi,
private val chatClientStateMapper: ChatClientStateMapper,
private val chatMessageRemoteMapper: ChatMessageRemoteMapper,
) : ChatRemoteApi {
private var _chatRoom: ChatRoom? = null
set(value) {
field = value
if (value != null) {
mutableChatRoomFlow.tryEmit(value)
}
}
private val isConnected: Boolean
get() {
return chatRoom.state == ChatRoom.State.CONNECTED
}
private val mutableChatRoomFlow = bufferedFlow<ChatRoom>(replay = 1)
private val chatRoom: ChatRoom
get() {
return checkNotNull(_chatRoom) { "Chat Room need to be initialized" }
}
override val stateChange: Flow<State>
get() = mutableChatRoomFlow.take(1)
.flatMapLatest { chatRoom ->
chatRoom.stateChanges()
.map(chatClientStateMapper::map)
}
override val messages: Flow<ChatMessageResponse>
get() = mutableChatRoomFlow.take(1)
.flatMapLatest { chatRoom ->
chatRoom.receivedMessages()
.map(chatMessageRemoteMapper::map)
}
override suspend fun createClient(params: ChatClientParams) {
val chatTokenProvider: suspend () -> ChatToken = suspend {
val response = webinarRemoteApi.createChatToken(params.webinarId, params.userId)
with(response) {
ChatToken(
token,
tokenExpirationTime.toDate(),
sessionExpirationTime.toDate(),
)
}
}
_chatRoom = ChatRoom(
regionOrUrl = params.region,
tokenProvider = chatTokenProvider,
)
}
override fun connect() { // call onResume
if (!isConnected) {
chatRoom.connect()
}
}
override fun disconnect() { // call onPause
chatRoom.disconnect()
}
}
I see two solutions:
- Never call disconnect, just keep the connection no matter of lifecycle. (Only disconnect before killing the activity). - But from the documentation I see that if app stays in background for long time then the socket connection stops. So that solution may not work well.
- Second options is to re-create new chat room every time the app comes back from background.