crisp-im / crisp-sdk-android

:package: Crisp Android SDK, add a chat in any Android app and communicate with your users.
https://docs.crisp.chat/guides/chatbox-sdks/android-sdk/
Other
55 stars 17 forks source link

Disconnected if using two Crisp.configure with two differents Ids #143

Closed Pourfex closed 11 months ago

Pourfex commented 1 year ago

Hello, Wanted to use Crisp for both support and improving ideas chat.

In my android app I used

private fun contactSupport(improveIdeas: Boolean = false) {
        Crisp.configure(applicationContext, if (improveIdeas) BuildConfig.CRISP_ID_IDEAS else BuildConfig.CRISP_ID_SUPPORT)

        val user = ServiceLocator.databasePresenter.realm.query<User>("id == $0", preferencesPresenter.getLoggedUserId()).find().firstOrNull()
        user?.let {
            Crisp.setUserEmail(it.username)
            Crisp.setUserNickname(getString(R.string.profile_full_name, it.firstName.capitalize(Locale.getDefault()), it.lastName.capitalize(Locale.getDefault())))
        }

        val crispIntent = Intent(this, ChatActivity::class.java)
        startActivity(crispIntent)
    }

When I go to support and send a message, I'm connected and can chat. I can exit the chat and get back later. If I go tu support, send a few messages and close it, then go into the improving ideas (with another Crisp.Configure with another ID), send a few messages here, go back to support I lost my session with previous messages in support.

Do I need to configure something else to make it work ? Tried so set a TokenID based on some user id, but it didn't work at all.

If I'm missing something, I would be glad to hear it ! Thanks in advance,

Doc1faux commented 1 year ago

Hello @Pourfex and thank your for your feedback.

Indeed, the SDK currently maintains and preserves only one session at a time no matter the websiteId. As you switch between websiteIds, the previous session is destroyed. However, as you mentioned, setting a TokenId should do the job in order to retrieve the session.

If not, I let the Crisp support answer you. In the meanwhile, i will take a look at the SDK to be sure of this behavior ;)

Pourfex commented 1 year ago

On iOS this is not the actual behaviour, we can switch between two Crisp.configure with two differents Ids and we keep the sessions between each.

If I set a TokenID on the session, I loose the session once I exit it.

Doc1faux commented 1 year ago

we can switch between two Crisp.configure with two differents Ids and we keep the sessions between each.

Do you mean without setting a TokenID for each session? If that's the case, I will ask if this is the intended behavior and implement it if so :)

I have just tested and the Android SDK behaves as I described above. So you should be able to save/restore your session for a websiteId by setting a TokenID on it.

However, once you exit the chatbox and would re-enter it with the other websiteId, you would need to set both websiteId AND TokenId as switching of website via Crisp.configure() clears all cached data.

So it would end like this:

Crisp.configure(appContext, BuildConfig.CRISP_ID_WEBSITE);
Crisp.setTokenID(userToken)

Intent crispIntent = Intent(this, ChatActivity.class);
startActivity(crispIntent);
Pourfex commented 1 year ago

Implement your way of doing things like this :

private fun contactSupport(improveIdeas: Boolean = false) {
        Crisp.configure(applicationContext, if (improveIdeas) BuildConfig.CRISP_ID_IDEAS else BuildConfig.CRISP_ID_SUPPORT)

        val user = ServiceLocator.databasePresenter.realm.query<User>("id == $0", preferencesPresenter.getLoggedUserId()).find().firstOrNull()
        user?.let {
            Crisp.setTokenID(it.username + if (improveIdeas) BuildConfig.CRISP_ID_IDEAS else BuildConfig.CRISP_ID_SUPPORT)
            Crisp.setUserEmail(it.username)
            Crisp.setUserNickname(getString(R.string.profile_full_name, it.firstName.capitalize(Locale.getDefault()), it.lastName.capitalize(Locale.getDefault())))
        }

        val crispIntent = Intent(this, ChatActivity::class.java)
        startActivity(crispIntent)
    }

Switching from one website id to the other reset the previous session on the previous website id even if the token ID is different. I can give a bit more about the device I'm working with if that helps :

Samsung s20+ Exynos, Android 12

Doc1faux commented 1 year ago

Mmhh..

This is exactly what you should do to preserve sessions.

I only see 2 solutions now. Either the following code is async, so it could finally run after starting chat resulting in a tokenId not set before the session is being created/joined and unfortunately, it cannot be set after this, so the call is simply dropped (I do not know well Realm but via syntax, it does not seem async).

val user = ServiceLocator.databasePresenter.realm.query<User>("id == $0", preferencesPresenter.getLoggedUserId()).find().firstOrNull()
        user?.let {
            Crisp.setTokenID(it.username + if (improveIdeas) BuildConfig.CRISP_ID_IDEAS else BuildConfig.CRISP_ID_SUPPORT)
            Crisp.setUserEmail(it.username)
            Crisp.setUserNickname(getString(R.string.profile_full_name, it.firstName.capitalize(Locale.getDefault()), it.lastName.capitalize(Locale.getDefault())))
        }

Or, as I said above, while you have an existing session, you cannot set a tokenId to it, as the call will simply be dropped. So if you already have a previous session for which the tokenId was no set, you must reset it via the Crisp.resetChatSession(appCtx) call in order to create a new one for the next connection and set a tokenId to it.

However, this should happen only on your first switch if all your code is run sequentially. I enclose you a demo with this issue and the working case :)

https://user-images.githubusercontent.com/2175246/199559537-c3c6febb-80ce-4c60-96ef-45941af732b8.mp4

I am still waiting to know if I should keep the last session per website or only the last one (whatever the website), meaning that is you switch between websites, you will need to set tokenId.

Pourfex commented 1 year ago

It's indeed not async. I tried to called the Crisp.ResetChat session between 2 websiteID change, before each session, after the first one.. None worked on my phone. Wonder if this only works in a simulator and maybe not on phone ?

Can you give me the requirements for tokenID ? Maybe mine is too long or does not match the requirements, as I didn't find the requirements in your docs.

Thanks for helping us at !

Doc1faux commented 1 year ago

I have just tested on an Android 12 device (Google Pixel 3) in Debug & Release and it is still working :/

However, I have seen a strange behavior due to 1.0.13 change (see #133) to avoid multiple chat instances. After switching to another app and go back, I was not able anymore to access the host app with the device back button or gesture, which leading the app to display the incorrect session while switching between websiteIds and tokenIds... I've fixed that by switching the launchMode to singleTop which also prevents multiple chat instances by dropping any onNewIntent call, while keeping it in the same task as the host app to be able to go back to it (I presume that the previous task containing the app host is killed by the system...).

You can test if this fixes your issue by adding this to your AndroidManifest.xml:

<activity
    android:name="im.crisp.client.ChatActivity"
    android:launchMode="singleTop"
    tools:replace="android:launchMode" />

For the tokenId format, any string should work while it is unique for each customer of your website. However, it is not recommended to include user information in it for security reasons. We strongly recommend to generate them like a UUID V4 (see Session Continuity - Important Notes On Security).

On Android, it is pretty simple:

String tokenID = UUID.randomUUID().toString();
Doc1faux commented 1 year ago

@Pourfex Is this has fixed your issue?

You can test if this fixes your issue by adding this to your AndroidManifest.xml:

<activity
    android:name="im.crisp.client.ChatActivity"
    android:launchMode="singleTop"
    tools:replace="android:launchMode" />

If so, the last release 1.0.14 fixes it as ChatActivity is now declared singleTop.

Pourfex commented 1 year ago

Hello !

Sorry for late reply I didn't see November's message.

Unfortunately that does not have fix my bug. We've still release it in production (in fact we don't have many people going trought support and improving ideas chats in the same session). Same thing happening for all phones tested.

We'll look into future releases to see if this is fix !

Doc1faux commented 1 year ago

Hi @Pourfex,

I finally managed to reproduce your issue! That's a race condition issue between public API SDK calls and Crisp REST API... I'll fix it in the next release...

Pourfex commented 1 year ago

Thanks ! We'll test the 1.0.15 once released !

Doc1faux commented 11 months ago

Hi @Pourfex,

The 1.0.15 has just been release with this fix :)