In‐app chat - infobip/mobile-messaging-sdk-android GitHub Wiki
Find out more about the Live Chat product in the Infobip docs.
- Intro
- Requirements
- Permissions
- Quick-start guide
- Example application
- Display an In-app chat screen
- Customer's Chat History
- Advanced
- Customize an In-app chat
- Push notifications
- In-app chat events
- Attachments
- Changing localization
- Sending Contextual Data / Metadata
- Multiple chat threads
- Authenticated chat
- Livechat Widget API
- Troubleshooting
In-app chat is a mobile component for connecting and interacting with the Infobip's Livechat product. In-app chat is built on top of the Mobile Messaging SDK and that's why Mobile Messaging should be included in your application and properly configured.
- Android Studio
- Supported API Levels: 21 (Android 5.0 - Lollipop) - 34 (Android 14.0 - Upside Down Cake)
- AndroidX
- In-app chat SDK source and target compatibility set to Java 8
- Infobip account
The In-app chat SDK declares the following as dangerous
permissions:
WRITE_EXTERNAL_STORAGE
CAMERA
-
READ_MEDIA_IMAGES
- required up to version 13.8.0 -
READ_MEDIA_VIDEO
- required up to version 13.8.0 -
READ_MEDIA_AUDIO
- required up to version 13.8.0
Runtime check and request for all dangerous permissions is handled by library UI components. There is also one more normal
permission ACCESS_NETWORK_STATE
declared in library.
In-app chat requires from you a careful setup, both in your mobile app and in your Infobip account. The following steps must be prepared in order to ensure the chat communication:
-
Include and set up the Mobile Messaging SDK in your application. If you haven't already, follow its Quick start guide carefully. Only by being able to receive a
pushRegistrationId
in your device, you'll be able to successfully connect to the In-app chat, which we explain in the next steps. -
Create a Livechat Widget and connect it with the Mobile Messaging application profile you've created in step 1 to the widget configuration.
-
Add dependencies to your app's
build.gradle
file:
dependencies {
...
implementation "com.infobip:infobip-mobile-messaging-android-chat-sdk:12.+@aar"
implementation 'androidx.exifinterface:exifinterface:1.1.0' // can be any 1.+ version, 1.1.0 is an example
//since version 8.0.0 you need to add following depencies (if you do not have them already)
implementation 'org.jetbrains.kotlin:kotlin-stdlib:+'
implementation 'androidx.databinding:viewbinding:+'
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:+'
}
Version 4.0.0 onwards requires you to call the method that activates an in-app chat service after initializing the MobileMessaging SDK.
InAppChat.getInstance(context).activate()
expand to see Java code
InAppChat.getInstance(context).activate();
Now, you can start sending messages.
The In-app chat SDK provides a built-in chat view which you can quickly embed into your own application. You can initialize a chat view with just one line of code:
InAppChat.getInstance(context).inAppChatScreen().show()
expand to see Java code
InAppChat.getInstance(context).inAppChatScreen().show();
It will immediately open a chat activity on top of a current activity. It is quick and simple to integrate full screen end-to-end chat solution.
In-app chat SDK provides also another more flexible and customizable ways to show chat. To prepare tailor-made chat read Advanced section. Together with chat customization options you can integrate In-app chat to perfectly fit all your design needs.
Once your app is installed, it is assigned a set of IDs for receiving push notifications and connecting to Livechat. Additionally, a mostly empty "person" entity is automatically created on the Infobip side as part of the installation. For more details, see another page explaining users and installations terminology.
While having an anonymous customer/person fits some use cases, most likely you'll have an authenticated customer you can/want to identify (for example, by their email, phone number, or some other unique ID). To do so, use the Personalize feature of the Mobile messaging SDK. You can link your customer to your app installation and also you'll be able to recover a chat history with that customer.
Once your app has received the push registration, personalize your customer. Next time the chat shows up, previously sent messages will be present, recovering the open conversation.
There is also an option to depersonalize a customer. This reverts the customer to its original, anonymous state emptying the chat history. This is a common/suggested practice for log-out flows.
In-app chat screen consists of a 3 UI components: navigation toolbar, messages list and message input. In-app chat SDK provides 3 approaches to display a chat. Every approach allows you different level of difficulty to integrate and control over the chat. It is up to you to choose the approach matching your needs:
-
InAppChatScreen
- It is easiest and fastest way how to integrate and show chat. It shows activity - full screen chat with all 3 UI components. You don't need to handle anything. All UI components works together smoothly. To show the activity see Display an In-app chat screen section. -
InAppChatFragment
- If you want to show chat in own activity, you can embed the chat fragment. The fragment shows chat with all 3 UI components by default. There is an option to hide default navigation toolbar or message input and implement own one. To integrate the fragment see Display an in-app chat as fragment section. -
InAppChatView
- It is just messages list UI component, without navigation toolbar and message input. It is Android view, you can place it in a screen as you wish. You have full control over the chat. To integrate the view see Display an in-app chat as view section.
There are 2 options how to show InAppChatFragment
:
-
[DEPRECATED] Assisted approach - Fragment instance is created and managed by In-app chat SDK. You can only show and hide fragment. It is similar solution as
InAppChatScreen
, only difference is you can embed fragment into your custom activity. Fragment shows navigation toolbar with logic for internal navigation in chat with multiple thread. Fragment shows also message input with logic required to send messages and attachments, including permissions requests. You have no option hide UI components. To show fragment see assisted approach section. - Full ownership - You create and show instance of
InAppChatFragment
. Fragment offers many public properties and functions what provides you significant flexibility. You can control visibility of chat UI components. To show fragment see Full ownership section.
We have deprecated assisted approach and it will be removed in near future, use full ownership approach instead.
It is supported from version 4.3.0 onwards.
To set up your Activity for using InAppChatFragment
follow the steps below. Full code can be checked in the ChatExample).
- Create a layout in your
activity.xml
to use it as a container for the fragment. ForMainActivity
from the ChatExample we usedFrameLayout
- activity_main.xml
<android.support.design.widget.CoordinatorLayout>
...
<FrameLayout
android:id="@+id/fragmentContainer"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</android.support.design.widget.CoordinatorLayout>
- Use the following method to show an in-app chat as Fragment.
containerId
- ID of the fragment container which was added in the previous step;fragmentManager
-FragmentManager
an instance to make interaction with Fragment. You can get it from activity, callinggetSupportFragmentManager()
;
InAppChat.getInstance(context).showInAppChatFragment(fragmentManager, containerId);
- Implement the
InAppChatFragment.InAppChatActionBarProvider
interface in your Activity.
class MainActivity: AppCompatActivity(), InAppChatFragment.InAppChatActionBarProvider {
/* InAppChatActionBarProvider */
/**
* Provide the original ActionBar to give the in-app chat ability to hide it and use its own ActionBar.
* It will be hidden when an in-app Chat fragment is shown and returned back when an in-app Chat fragment hidden.
*/
override val originalSupportActionBar: ActionBar?
get() = supportActionBar
/**
* Implement a back button behaviour.
* Call the following method with a corresponding parameter:
* {@link InAppChat#hideInAppChatFragment(FragmentManager)}
*/
override fun onInAppChatBackPressed() {
InAppChat.getInstance(this).hideInAppChatFragment(supportFragmentManager)
//you can pass "true" as second argument to disconnect chat when fragment is hidden to receive push notifications
//InAppChat.getInstance(this).hideInAppChatFragment(supportFragmentManager, true)
}
...
}
expand to see Java code
public class MainActivity extends AppCompatActivity implements InAppChatFragment.InAppChatActionBarProvider {
/* InAppChatActionBarProvider */
/**
* Provide the original ActionBar to give the in-app chat ability to hide it and use its own ActionBar.
* It will be hidden when an in-app Chat fragment is shown and returned back when an in-app Chat fragment hidden.
*/
@Nullable
@Override
public ActionBar getOriginalSupportActionBar() {
return getSupportActionBar();
}
/**
* Implement a back button behaviour.
* Call the following method with a corresponding parameter:
* {@link InAppChat#hideInAppChatFragment(FragmentManager)}
*/
@Override
public void onInAppChatBackPressed() {
InAppChat.getInstance(MainActivity.this).hideInAppChatFragment(getSupportFragmentManager());
//you can pass "true" as second argument to disconnect chat when fragment is hidden to receive push notifications
//InAppChat.getInstance(this).hideInAppChatFragment(supportFragmentManager, true);
}
...
}
Full code of example integration of InAppChatFragment
can be checked in the ChatExample application.
Version 12.8.0 onwards introduces many new public properties and functions in InAppChatFragment
class.
You can control visibility of navigation toolbar and message input. You can decide to hide it if you want to implement custom replacement. Although you have a full control over the chat screen
content, there are steps we recommend you to follow:
- Create instance
InAppChatFragment
instance and set UI components visibility. - Set
InAppChatFragment.EventsListener
chat events listener. Interface provides various useful callbacks. It is required when you implement custom navigation toolbar, and you want to support multiple chat threads feature. You can useDefaultInAppChatFragmentEventsListener
to override only necessary methods. - Handle InAppChat's errors on your own by implementing the
InAppChatFragment.ErrorsHandler
interface. TheInAppChatFragment.defaultErrorHandler
property exposes its default error handler.
class MainActivity: AppCompatActivity() {
lateinit var fragment: InAppChatFragment
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
//1. Create instance and set UI components visibility
fragment = InAppChatFragment()
fragment.withInput = false
fragment.withToolbar = true
//2. Set events listener
fragment.eventsListener = object : InAppChatFragment.EventsListener {
override fun onChatLoadingFinished(result: LivechatWidgetResult<Unit>) {
//Chat has been loaded and connection established.
}
override fun onChatConnectionPaused(result: LivechatWidgetResult<Unit>) {
//Chat connection has been paused.
}
override fun onChatConnectionResumed(result: LivechatWidgetResult<Unit>) {
//Chat connection has been resumed.
}
override fun onChatContextualDataSent(result: LivechatWidgetResult<String?>) {
//Called when chat contextual data are sent.
}
override fun onChatSent(result: LivechatWidgetResult<LivechatWidgetMessage?>) {
//Called when chat message was sent.
}
override fun onChatThreadsReceived(result: LivechatWidgetResult<LivechatWidgetThreads>) {
//Called when chat threads were requested.
}
override fun onChatThreadCreated(result: LivechatWidgetResult<LivechatWidgetMessage?>) {
//Called when chat thread was created.
}
override fun onChatActiveThreadReceived(result: LivechatWidgetResult<LivechatWidgetThread?>) {
//Called when chat active thread was requested.
//Success result can contains null if there is no existing thread for current user session or current widget destination is not [LivechatWidgetView.THREAD].
}
override fun onChatThreadShown(result: LivechatWidgetResult<LivechatWidgetThread>) {
//Called when chat thread is shown.
}
override fun onChatThreadListShown(result: LivechatWidgetResult<Unit>) {
//Called when chat thread list is shown.
}
override fun onChatLanguageChanged(result: LivechatWidgetResult<String?>) {
//Called when chat language has been changed.
}
override fun onChatWidgetThemeChanged(result: LivechatWidgetResult<String?>) {
//Called when chat theme has been changed.
}
override fun onChatControlsVisibilityChanged(isVisible: Boolean) {
//Chat controls visibility has changed.
}
override fun onChatViewChanged(widgetView: LivechatWidgetView) {
//Chat view has changed.
}
override fun onChatWidgetInfoUpdated(widgetInfo: WidgetInfo) {
//Chat [WidgetInfo] has been updated.
}
override fun onChatRawMessageReceived(rawMessage: String) {
//Chat message has been received.
}
override fun onChatAttachmentPreviewOpened(
url: String?,
type: String?,
caption: String?
): Boolean {
//Called when attachment from chat has been interacted.
//It allows you to handle attachment preview on your own. Return true if you handled attachment preview.
//Return false to let [InAppChatFragment] handle attachment preview.
return false
}
override fun onExitChatPressed() {
//Called by default InAppChat's Toolbar back navigation logic to exit chat. You are supposed to hide/remove [InAppChatFragment].
supportFragmentManager
.beginTransaction()
.remove(fragment)
.commit()
}
}
//3. Set errors handler
fragment.errorsHandler = object : InAppChatFragment.ErrorsHandler {
override fun handlerError(error: String) {
//Your custom handling of general error or use a default handler
fragment.defaultErrorsHandler.handlerError(error)
}
override fun handlerWidgetError(error: String) {
//Your custom handling of Livechat widget error or use default handler
fragment.defaultErrorsHandler.handlerWidgetError(error)
}
override fun handlerNoInternetConnectionError(hasConnection: Boolean) {
//Your custom handling of missing network connection error or use default handler
fragment.defaultErrorsHandler.handlerNoInternetConnectionError(hasConnection)
}
}
//4. Add fragment to your activity
supportFragmentManager
.beginTransaction()
.replace(R.id.yourFragmentContainer, fragment, "chatFragmentTag")
.commit()
}
}
expand to see Java code
class MainActivity extends AppCompatActivity {
private InAppChatFragment fragment = null;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//1. Create instance and set UI components visibility
fragment = new InAppChatFragment();
fragment.setWithToolbar(true);
fragment.setWithInput(false);
//2. Set events listener
fragment.setEventsListener(new InAppChatFragment.EventsListener() {
@Override
public void onChatLoadingFinished(@NonNull LivechatWidgetResult<Unit> result) {
//Called once chat has been loaded and connection established.
}
@Override
public void onChatConnectionPaused(@NonNull LivechatWidgetResult<Unit> result) {
//Chat connection has been paused.
}
@Override
public void onChatConnectionResumed(@NonNull LivechatWidgetResult<Unit> result) {
//Chat connection has been resumed.
}
@Override
public void onChatSent(@NonNull LivechatWidgetResult<? extends LivechatWidgetMessage> result) {
//Called when chat message was sent.
}
@Override
public void onChatContextualDataSent(@NonNull LivechatWidgetResult<String> result) {
//Called when chat contextual data was sent.
}
@Override
public void onChatThreadCreated(@NonNull LivechatWidgetResult<? extends LivechatWidgetMessage> result) {
//Called when chat thread was created.
}
@Override
public void onChatThreadsReceived(@NonNull LivechatWidgetResult<LivechatWidgetThreads> result) {
//Called when chat threads were requested.
}
@Override
public void onChatActiveThreadReceived(@NonNull LivechatWidgetResult<LivechatWidgetThread> result) {
//Called when chat active thread was requested.
//Success result can contains null if there is no existing thread for current user session or current widget destination is not [LivechatWidgetView.THREAD].
}
@Override
public void onChatThreadShown(@NonNull LivechatWidgetResult<LivechatWidgetThread> result) {
//Called when chat thread is shown.
}
@Override
public void onChatThreadListShown(@NonNull LivechatWidgetResult<Unit> result) {
//Called when chat thread list is shown.
}
@Override public void onChatLanguageChanged(@NonNull LivechatWidgetResult<String> result) {
//Called when chat language has been changed.
}
@Override
public void onChatWidgetThemeChanged(@NonNull LivechatWidgetResult<String> result) {
//Called when chat theme has been changed.
}
@Override
public void onChatControlsVisibilityChanged(boolean isVisible) {
//Chat controls visibility has changed.
}
@Override
public void onChatViewChanged(@NonNull LivechatWidgetView widgetView) {
//Chat view has changed.
}
@Override
public void onChatWidgetInfoUpdated(@NonNull WidgetInfo widgetInfo) {
//Chat [WidgetInfo] has been updated.
}
@Override
public void onChatRawMessageReceived(@NonNull String rawMessage) {
//Chat message has been received.
}
@Override
public boolean onChatAttachmentPreviewOpened(@Nullable String url, @Nullable String type, @Nullable String caption) {
//Called when attachment from chat has been interacted.
//It allows you to handle attachment preview on your own. Return true if you handled attachment preview.
//Return false to let [InAppChatFragment] handle attachment preview.
return false;
}
@Override
public void onExitChatPressed() {
// Called by default InAppChat's Toolbar back navigation logic to exit chat. You are supposed to hide/remove [InAppChatFragment].
getSupportFragmentManager()
.beginTransaction()
.remove(fragment)
.commit();
}
});
//3. Set errors handler
fragment.setErrorsHandler(new InAppChatFragment.ErrorsHandler() {
@Override
public void handlerError(@NonNull String error) {
//Your custom handling of general error or use a default handler
fragment.getDefaultErrorsHandler().handlerError(error);
}
@Override
public void handlerWidgetError(@NonNull String error) {
//Your custom handling of Livechat widget error or use default handler
fragment.getDefaultErrorsHandler().handlerWidgetError(error);
}
@Override
public void handlerNoInternetConnectionError(boolean hasConnection) {
//Your custom handling of missing network connection error or use default handler
fragment.getDefaultErrorsHandler().handlerNoInternetConnectionError(hasConnection);
}
});
//4. Add fragment to your activity
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.yourFragmentContainer, fragment, "chatFragmentTag")
.commit();
}
}
class InAppChatFragment {
/**
* Returns true if chat is loaded and multithread feature is enabled, otherwise returns false.
*/
val isMultiThread: Boolean
/**
* [InAppChatFragment] events listener allows you to listen to chat related events.
* Your in-app chat events listener set using [InAppChat.setEventsListener] is used as initial default value.
*/
var eventsListener: InAppChatFragment.EventsListener? = InAppChat.getInstance(context).eventsListener
/**
* Allows you to set custom [InAppChatFragment.ErrorsHandler] handler to process chat errors on your own.
*/
var errorsHandler: InAppChatFragment.ErrorsHandler
val defaultErrorHandler: InAppChatFragment.ErrorsHandler
/**
* Allows you to control presence of InAppChatFragment's Toolbar.
* If you want to use your own Toolbar, set it to false. Default value is true.
*
* When you use own Toolbar it is up to you to handle back navigation logic.
* You can use [InAppChatFragment.navigateBackOrCloseChat] for default back navigation logic,
* what handles internal multithread widget navigation together with android native navigation.
* In case you want to handle back navigation on your own, there is [InAppChatFragment.showThreadList]
* to navigate from [LivechatWidgetView.THREAD] back to [LivechatWidgetView.THREAD_LIST] in multithread widget.
*/
var withToolbar: Boolean = true
/**
* Allows you to control presence of InAppChatFragment's message input.
* If you want to use your own message input, set it to false. Default value is true.
*
* When you use own message input it is up to you to handle message and attachment sending logic
* including request Android permissions for attachment picker.
* You can reuse provided [InAppChatInputView] or create custom UI.
* Use [InAppChatFragment.sendChatMessage] to send message.
* Use [InAppChatFragment.sendChatMessageDraft] to send draft message.
*/
var withInput: Boolean = true
/**
* Allows to stop chat connection when fragment is hidden.
* Chat is reconnected automatically once fragment is shown again.
* Default value is false.
*
* By chat connection you can control push notifications.
* Push notifications are active only when chat connection is not active.
*
* It calls [InAppChatView.stopConnection] when fragment is hidden and [InAppChatView.restartConnection] once fragment is visible again.
*/
var disconnectChatWhenHidden: Boolean = false
/**
* Allows to enable/disable back press handling logic.
* If true, it triggers default back navigation logic [navigateBackOrCloseChat], useful especially for multithread widgets.
* If false, back press events are not handled.
* It does not affect ActionBar back button.
*
* Default value is true.
*/
var handleBackPress: Boolean = true
/**
* Set the language of the Livechat Widget.
*
* Does nothing if [InAppChatFragment] not attached.
*
* @param locale locale's language is used by Livechat Widget and native parts
*/
@Deprecated("Use setLanguage(LivechatWidgetLanguage) instead")
fun setLanguage(locale: Locale)
/**
* Set InAppChat language
*
* Does nothing if [InAppChatFragment] not attached.
*
* @param language language is used by Livechat Widget and InAppChat native parts
*/
fun setLanguage(language: LivechatWidgetLanguage)
/**
* Returns current in-app chat language
*
* @return current in-app chat language or default LivechatWidgetLanguage.ENGLISH
*/
fun getLanguage(): LivechatWidgetLanguage
/**
* Set contextual data of the Livechat Widget.
*
* If the function is called when [InAppChatFragment] is attached and the chat is loaded,
* data will be sent immediately, otherwise they will be sent to the chat once it is loaded.
*
* Every function invocation will overwrite the previous contextual data.
*
*
* @param data contextual data in the form of JSON string
* @param allMultiThreadStrategy multithread strategy flag, true -> ALL, false -> ACTIVE
* @see [InAppChatFragment.EventsListener.onChatLoaded] to detect if chat is loaded
*/
@Deprecated(message = "Use sendContextualData(@Nullable String data, @Nullable MultithreadStrategy flag) instead")
fun sendContextualData(data: String, allMultiThreadStrategy: Boolean)
/**
* Set contextual data of the Livechat Widget.
*
* If the function is called when [InAppChatFragment] is attached and the chat is loaded,
* data will be sent immediately, otherwise they will be sent to the chat once it is loaded.
*
* Every function invocation will overwrite the previous contextual data.
*
* @param data contextual data in the form of JSON string
* @param flag multithread strategy [MultithreadStrategy]
* @see [InAppChatFragment.EventsListener.onChatLoaded] to detect if chat is loaded
*/
fun sendContextualData(data: String, strategy: MultithreadStrategy)
/**
* Sends draft message to be show in chat to peer's chat.
*
* Does nothing if [InAppChatFragment] not attached.
*
* @param draft message
*/
@Deprecated("Use send(payload: MessagePayload) with MessagePayload.Draft() instead")
fun sendChatMessageDraft(draft: String)
/**
* Sends message to the chat with optional [InAppChatMobileAttachment].
*
* Does nothing if [InAppChatFragment] not attached.
*
* @param message message to be sent, max length allowed is 4096 characters
* @param attachment to create attachment use [InAppChatMobileAttachment]'s constructor where you provide attachment's mimeType, base64 and filename
*/
@Deprecated("Use send(payload: MessagePayload) with MessagePayload.Basic() instead")
fun sendChatMessage(message: String?, attachment: InAppChatMobileAttachment? = null)
/**
* Sends a message defined by [payload] data with optional [threadId].
*
* You can observe result by [InAppChatFragment.EventsListener.onChatSent] event.
*
* @param payload data defining message to be sent
* @param threadId id of existing thread to send message into, if not provided, it will be sent to the active thread
*/
fun send(payload: MessagePayload, threadId: String? = null)
/**
* Set the theme of the Livechat Widget.
* You can define widget themes in <a href="https://portal.infobip.com/apps/livechat/widgets">Live Chat widget setup page</a> in Infobip Portal, section `Advanced customization`.
* Please check widget <a href="https://www.infobip.com/docs/live-chat/widget-customization">documentation</a> for more details.
*
* Function allows to change widget theme while chat is shown - in runtime.
* If you set widget theme before [InAppChatFragment] is shown the theme will be used once chat is loaded.
*
* Does nothing if [InAppChatFragment] not attached.
*
* @param widgetThemeName unique theme name, empty or blank value is ignored
*/
fun setWidgetTheme(widgetThemeName: String)
/**
* Returns current livechat widget theme.
*
* @return applied theme name of livechat widget
*/
fun getWidgetTheme(): String?
/**
* Executes back navigation. In multithread widget it handles internal navigation
* from [LivechatWidgetView.THREAD] back to [LivechatWidgetView.THREAD_LIST] using
* [InAppChatFragment.showThreadList], otherwise it triggers [InAppChatFragment.EventsListener.onExitChatPressed] event
* and [InAppChatFragment.InAppChatActionBarProvider.onInAppChatBackPressed].
*
* It is default InAppChatFragment back navigation logic.
*/
fun navigateBackOrCloseChat()
/**
* Creates a new thread with an initial message defined by the given [payload].
*
* You can observe the result via the [InAppChatFragment.EventsListener.onChatThreadCreated] event.
*
* @param payload The message payload used to start the new thread.
*/
fun createThread(payload: MessagePayload)
/**
* Requests current threads from livechat widget.
*
* Does nothing if [InAppChatFragment] not attached.
*
* You can observe result by [InAppChatFragment.EventsListener.onChatThreadsReceived] event.
*/
fun getThreads()
/**
* Requests shown thread - active from livechat widget.
*
* Does nothing if [InAppChatFragment] not attached.
*
* You can observe result by [InAppChatFragment.EventsListener.onChatActiveThreadReceived] event.
*/
fun getActiveThread()
/**
* Navigates livechat widget to thread specified by provided [threadId].
*
* Does nothing if [InAppChatFragment] not attached.
*
* You can observe result by [InAppChatFragment.EventsListener.onChatThreadShown] event.
*
* @param threadId thread to be shown
*/
fun showThread(threadId: String)
/**
* Navigates Livechat widget from [LivechatWidgetView.THREAD] back to [LivechatWidgetView.THREAD_LIST]
* destination in multithread widget. Does nothing if livechat widget not multithread.
*
* Does nothing if [InAppChatFragment] not attached.
*/
fun showThreadList()
}
expand to see Java code
public class InAppChatFragment {
public boolean isMultiThread();
public void setEventListener(@Nullable InAppChatFragment.EventListener eventListener);
@Nullable public InAppChatFragment.EventListener getEventListener();
public void setErrorsHandler(@NotNull InAppChatFragment.ErrorsHandler errorsHandler);
@NotNull public InAppChatFragment.ErrorsHandler getErrorsHandler();
@NotNull public InAppChatFragment.ErrorsHandler getDefaultErrorsHandler();
public void setWithToolbar(@NotNull Boolean withToolbar);
@NotNull public Boolean getWithToolbar();
public void setWithInput(@NotNull Boolean withInput);
@NotNull public Boolean getWithInput();
public void setDisconnectChatWhenHidden(@NotNull Boolean disconnect);
@NotNull public Boolean getDisconnectChatWhenHidden();
public void setHandleBackPress(@NotNull Boolean handleBackPress);
@NotNull public Boolean getHandleBackPress();
@Deprecated public void setLanguage(@NotNull Locale locale);
public void setLanguage(@NotNull LivechatWidgetLanguage language);
@NotNull public LivechatWidgetLanguage getLanguage();
@Deprecated public void sendContextualData(@NotNull String data, @NotNull Boolean allMultiThreadStrategy);
public void sendContextualData(@NotNull String data, @NotNull MultithreadStrategy flag);
@Deprecated public void sendChatMessageDraft(@NotNull String draft);
@Deprecated public void sendChatMessage(@Nullable String message);
@Deprecated public void sendChatMessage(@Nullable String message, @Nullable InAppChatMobileAttachment attachment);
public void send(@NotNull MessagePayload payload, @Nullable String threadId);
public void send(@NotNull MessagePayload payload);
public void setWidgetTheme(@NotNull String widgetThemeName);
@Nullable public String getWidgetTheme();
public void createThread(@NotNull MessagePayload payload);
public void getThreads();
public void getActiveThread();
public void showThread(@NotNull String threadId);
public void showThreadList();
public void navigateBackOrCloseChat();
}
Full code of example integration of InAppChatView
can be checked in the ChatExample application.
Version 8.0.0 onwards introduces an InAppChatView
which you can embed into your Activity or Fragment. It allows you to use the InAppChat with your custom-made toolbar, message input, and whatever you wish to have in the chat screen. To customize the InAppChatView
see the chat style section. Although you have a full control over the chat screen content, there are mandatory set-up steps you have to follow:
- Add the
InAppChatView
into your layout.
<androidx.constraintlayout.widget.ConstraintLayout>
...
<org.infobip.mobile.messaging.chat.view.InAppChatView
android:id="@+id/inAppChatView"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
...
</androidx.constraintlayout.widget.ConstraintLayout>
- Inject Activity/Fragment's
Lifecycle
intoInAppChatView
.
- To get Activity's Lifecycle, call
getLifecycle()
- To get Fragment's Lifecycle, call
getViewLifecycleOwner().getLifecycle()
- To support multiple chat threads feature, implement the
InAppChatView.EventsListener
interface where you will obtain multiple useful callbacks except anothervoid onChatViewChanged(LivechatWidgetView widgetView)
, important for handling the InAppChat internal navigation. You can useDefaultInAppChatViewEventsListener
to override only necessary methods. - (Optional) Handle InAppChat's errors on your own by implementing the
InAppChatView.ErrorsHandler
interface. TheInAppChatView
exposes its default error handler by callinginAppChatView.getDefaultErrorsHandler()
.
class MainActivity: AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
//1. Injects activity's lifecycle
val inAppChatView: InAppChatView = findViewById(R.id.inAppChatView)
inAppChatView.init(lifecycle)
//2. Sets InAppChatView.EventsListener to handle multithread internal navigation
inAppChatView.eventsListener = object : InAppChatView.EventsListener {
override fun onChatLoadingFinished(result: LivechatWidgetResult<Unit>) {
//Chat has been loaded and connection established.
}
override fun onChatConnectionPaused(result: LivechatWidgetResult<Unit>) {
//Chat connection has been paused.
}
override fun onChatConnectionResumed(result: LivechatWidgetResult<Unit>) {
//Chat connection has been resumed.
}
override fun onChatSent(result: LivechatWidgetResult<LivechatWidgetMessage?>) {
//Called when chat message was sent.
}
override fun onChatContextualDataSent(result: LivechatWidgetResult<String?>) {
//Called when chat contextual data are sent.
}
override fun onChatThreadCreated(result: LivechatWidgetResult<LivechatWidgetMessage?>) {
//Called when chat thread was created.
}
override fun onChatThreadsReceived(result: LivechatWidgetResult<LivechatWidgetThreads>) {
//Called when chat threads were requested.
}
override fun onChatActiveThreadReceived(result: LivechatWidgetResult<LivechatWidgetThread?>) {
//Called when chat active thread was requested.
//Success result can contains null if there is no existing thread for current user session or current widget destination is not [LivechatWidgetView.THREAD].
}
override fun onChatThreadShown(result: LivechatWidgetResult<LivechatWidgetThread>) {
//Called when chat thread is shown.
}
override fun onChatThreadListShown(result: LivechatWidgetResult<Unit>) {
//Called when chat thread list is shown.
}
override fun onChatLanguageChanged(result: LivechatWidgetResult<String?>) {
//Called when chat language has been changed.
}
override fun onChatWidgetThemeChanged(result: LivechatWidgetResult<String?>) {
//Called when chat theme has been changed.
}
override fun onChatControlsVisibilityChanged(isVisible: Boolean) {
//Chat controls visibility has changed.
}
override fun onChatViewChanged(widgetView: LivechatWidgetView) {
//Chat view has changed.
//Handles navigation in multithread livechat widget
when (widgetView) {
LivechatWidgetView.LOADING,
LivechatWidgetView.THREAD_LIST,
LivechatWidgetView.SINGLE_MODE_THREAD -> {
//no need to handle internal navigation
}
LivechatWidgetView.LOADING_THREAD,
LivechatWidgetView.THREAD,
LivechatWidgetView.CLOSED_THREAD -> {
//to navigate back to THREAD_LIST, use inAppChatView.showThreadList();
}
}
//Handles message input in multithread livechat widget
when (widgetView) {
LivechatWidgetView.LOADING,
LivechatWidgetView.THREAD_LIST,
LivechatWidgetView.LOADING_THREAD,
LivechatWidgetView.CLOSED_THREAD -> {
//it is prohibited to send messages
}
LivechatWidgetView.SINGLE_MODE_THREAD,
LivechatWidgetView.THREAD -> {
//you can send messages
}
}
}
override fun onChatWidgetInfoUpdated(widgetInfo: WidgetInfo) {
//Chat [WidgetInfo] has been updated.
}
override fun onChatRawMessageReceived(rawMessage: String) {
//Chat message has been received.
}
override fun onChatAttachmentPreviewOpened(
url: String?,
type: String?,
caption: String?
) {
//Called when attachment from chat has been interacted.
}
}
//3. Sets InAppChatView.ErrorsHandler to handle InAppChatView errors on your own
inAppChatView.errorsHandler = object : InAppChatView.ErrorsHandler {
override fun handlerError(error: String) {
//Your custom handling of general error or use a default handler
inAppChatView.defaultErrorsHandler.handlerError(error);
}
override fun handlerWidgetError(error: String) {
//Your custom handling of Livechat widget error or use default handler
inAppChatView.defaultErrorsHandler.handlerWidgetError(error);
}
override fun handlerNoInternetConnectionError(hasConnection: Boolean) {
//Your custom handling of missing network connection error or use default handler
inAppChatView.defaultErrorsHandler.handlerNoInternetConnectionError(hasConnection);
}
}
}
}
expand to see Java code
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//1. Injects activity's lifecycle
InAppChatView inAppChatView = findViewById(R.id.inAppChatView);
inAppChatView.init(getLifecycle());
//2. Set InAppChatView.EventsListener to handle multithread internal navigation
inAppChatView.setEventsListener(new InAppChatView.EventsListener() {
@Override
public void onChatLoadingFinished(@NonNull LivechatWidgetResult<Unit> result) {
//Called once chat has been loaded and connection established.
}
@Override
public void onChatConnectionPaused(@NonNull LivechatWidgetResult<Unit> result) {
//Chat connection has been paused.
}
@Override
public void onChatConnectionResumed(@NonNull LivechatWidgetResult<Unit> result) {
//Chat connection has been resumed.
}
@Override
public void onChatSent(@NonNull LivechatWidgetResult<? extends LivechatWidgetMessage> result) {
//Called when chat message was sent.
}
@Override
public void onChatContextualDataSent(@NonNull LivechatWidgetResult<String> result) {
//Called when chat contextual data are sent.
}
@Override
public void onChatThreadCreated(@NonNull LivechatWidgetResult<? extends LivechatWidgetMessage> result) {
//Called when chat thread was created.
}
@Override
public void onChatThreadsReceived(@NonNull LivechatWidgetResult<LivechatWidgetThreads> result) {
//Called when chat threads were requested.
}
@Override
public void onChatActiveThreadReceived(@NonNull LivechatWidgetResult<LivechatWidgetThread> result) {
//Called when chat active thread was requested.
//Success result can contains null if there is no existing thread for current user session or current widget destination is not [LivechatWidgetView.THREAD].
}
@Override
public void onChatThreadShown(@NonNull LivechatWidgetResult<LivechatWidgetThread> result) {
//Called when chat thread is shown.
}
@Override
public void onChatThreadListShown(@NonNull LivechatWidgetResult<Unit> result) {
//Called when chat thread list is shown.
}
@Override public void onChatLanguageChanged(@NonNull LivechatWidgetResult<String> result) {
//Called when chat language has been changed.
}
@Override
public void onChatWidgetThemeChanged(@NonNull LivechatWidgetResult<String> result) {
//Called when chat theme has been changed.
}
@Override
public void onChatControlsVisibilityChanged(boolean isVisible) {
//Chat controls visibility has changed.
}
@Override
public void onChatViewChanged(@NonNull LivechatWidgetView widgetView) {
//Chat view has changed.
//Handles navigation in multithread livechat widget
switch (widgetView) {
case LOADING:
case THREAD_LIST:
case SINGLE_MODE_THREAD:
//no need to handle internal navigation
break;
case LOADING_THREAD:
case THREAD:
case CLOSED_THREAD:
//to navigate back to THREAD_LIST use inAppChatView.showThreadList();
break;
}
//Handles message input in multithread livechat widget
switch (widgetView) {
case LOADING:
case THREAD_LIST:
case LOADING_THREAD:
case CLOSED_THREAD:
//it is prohibited to send messages
break;
case SINGLE_MODE_THREAD:
case THREAD:
//you can send messages
break;
}
}
@Override
public void onChatWidgetInfoUpdated(@NonNull WidgetInfo widgetInfo) {
//Chat [WidgetInfo] has been updated.
}
@Override
public void onChatRawMessageReceived(@NonNull String rawMessage) {
//Chat message has been received.
}
@Override
public void onChatAttachmentPreviewOpened(@Nullable String url, @Nullable String type, @Nullable String caption) {
//Called when attachment from chat has been interacted.
}
});
//3. Sets your own InAppChatView.ErrorsHandler to handle InAppChatView errors
inAppChatView.setErrorsHandler(new InAppChatView.ErrorsHandler() {
@Override
public void handlerError(@NonNull String error) {
//Your custom handling of general error or use default handler
inAppChatView.getDefaultErrorsHandler().handlerError(error);
}
@Override
public void handlerWidgetError(@NonNull String error) {
//Your custom handling of Livechat widget error or use default handler
inAppChatView.getDefaultErrorsHandler().handlerWidgetError(error);
}
@Override
public void handlerNoInternetConnectionError(@NonNull Boolean hasConnection) {
//Your custom handling of missing network connection error or use default handler
inAppChatView.getDefaultErrorsHandler().handlerNoInternetConnectionError(hasConnection);
}
});
}
}
The InAppChatView
provides you with options to set a language, create a message with an attachment, send a message draft, send contextual data, execute internal chat navigation in case you use multiple chat threads and much more.
class InAppChatView {
/**
* Returns true if a chat is synchronized and multithread feature is enabled; otherwise returns false
*/
val isMultiThread: Boolean
/**
* [InAppChatView] event listener to listen to Livechat widget events.
*/
var eventsListener: EventsListener?
/**
* Sets a custom [InAppChatView.ErrorsHandler] handler to process [InAppChatView] errors on your own.
*/
var errorsHandler: ErrorsHandler
val defaultErrorsHandler: ErrorsHandler
/**
* Initialize [InAppChatView] with enclosing android component [Lifecycle].
*
* Loads chat and establish connection to be able to receive real time updates - new messages.
* Chat connection is established and stopped based on provided [Lifecycle].
* Chat connection is active only when [Lifecycle.State] is at least [Lifecycle.State.STARTED].
*
* @param lifecycle lifecycle of android Activity or Fragment
*/
fun init(lifecycle: Lifecycle)
/**
* Pauses chat connection.
*
* It is not needed to use it in most cases as chat connection is established and paused based on [Lifecycle] provided in [init].
* Chat connection is paused when [Lifecycle.State] is below [Lifecycle.State.STARTED].
*
* By chat connection you can control push notifications.
* Push notifications are active only when chat connection is not active.
*
* Can be used to enable chat's push notifications when [InAppChatView] is not visible.
* Use [resumeChatConnection] to reestablish chat connection.
*
* To detect if chat connection is paused use [EventsListener.onChatConnectionPaused] event from [EventsListener].
*/
fun pauseChatConnection()
/**
* Stops chat connection.
*
* It is not needed to use it in most cases as chat connection is established and stopped based on [Lifecycle] provided in [init].
* Chat connection is stopped when [Lifecycle.State] is below [Lifecycle.State.STARTED].
*
* By chat connection you can control push notifications.
* Push notifications are active only when chat connection is not active.
*
* Can be used to enable chat's push notifications when [InAppChatView] is not visible.
* Use [restartConnection] to reestablish chat connection.
*
* To detect if chat connection is stopped use [EventsListener.onChatDisconnected] event from [EventsListener].
*/
@Deprecated("Use pauseChatConnection() instead")
fun stopConnection()
/**
* Use it to resume chat connection when you previously called [pauseChatConnection].
*
* It is not needed to use it in most cases as chat connection is established and stopped based on [Lifecycle] provided in [init].
* Chat connection is active only when [Lifecycle.State] is at least [Lifecycle.State.STARTED].
*
* By chat connection you can control push notifications.
* Push notifications are suppressed while the chat connection is active.
*
* To detect if chat connection was resumed use [EventsListener.onChatConnectionResumed] event from [EventsListener].
*/
fun resumeChatConnection()
/**
* Use it to re-establish chat connection when you previously called [stopConnection].
*
* It is not needed to use it in most cases as chat connection is established and stopped based on [Lifecycle] provided in [init].
* Chat connection is active only when [Lifecycle.State] is at least [Lifecycle.State.STARTED].
*
* By chat connection you can control push notifications.
* Push notifications are suppressed while the chat connection is active.
*
* To detect if chat connection was re-established use [EventsListener.onChatReconnected] event from [EventsListener].
*/
@Deprecated("Use resumeChatConnection() instead")
fun restartConnection()
/**
* Sets the language of a Livechat Widget
* @param locale locale's language is used by Livechat Widget and native parts
*/
@Deprecated("Use setLanguage(LivechatWidgetLanguage) instead",)
fun setLanguage(locale: Locale)
/**
* Set InAppChat language
* @param language language is used by Livechat Widget and InAppChat native parts
*/
fun setLanguage(language: LivechatWidgetLanguage)
/**
* Returns current in-app chat language
*
* @return current in-app chat language or default LivechatWidgetLanguage.ENGLISH
*/
fun getLanguage(): LivechatWidgetLanguage
/**
* Set contextual data of the Livechat Widget.
*
* If the function is called when the chat is loaded,
* data will be sent immediately, otherwise they will be sent to the chat once it is loaded.
*
* Every function invocation will overwrite the previous contextual data.
*
* @param data contextual data in the form of JSON string
* @param allMultiThreadStrategy multithread strategy flag, true -> ALL, false -> ACTIVE
* @see [InAppChatView.EventsListener.onChatLoaded] to detect if chat is loaded
*/
@Deprecated("Use sendContextualData(data: String, strategy: MultithreadStrategy) instead")
fun sendContextualData(data: String, allMultiThreadStrategy: Boolean)
/**
* Set contextual data of the Livechat Widget.
*
* If the function is called when the chat is loaded,
* data will be sent immediately, otherwise they will be sent to the chat once it is loaded.
*
* Every function invocation will overwrite the previous contextual data.
*
* @param data contextual data in the form of JSON string
* @param flag multithread strategy [MultithreadStrategy]
* @see [InAppChatView.EventsListener.onChatLoaded] to detect if chat is loaded
*/
fun sendContextualData(data: String, strategy: MultithreadStrategy)
/**
* Sends draft message to be show in chat to peer's chat.
* @param draft message
*/
@Deprecated("Use send(payload: MessagePayload) with MessagePayload.Draft() instead")
fun sendChatMessageDraft(draft: String)
/**
* Sends a message to the chat with optional [InAppChatMobileAttachment].
* @param message message to be sent
* @param attachment to create an attachment, use [InAppChatMobileAttachment]'s constructor where you provide attachment's mimeType, base64, and filename
*/
@Deprecated("Use send(payload: MessagePayload) with MessagePayload.Basic() instead")
fun sendChatMessage(message: String?, attachment: InAppChatMobileAttachment? = null)
/**
* Sends a message defined by the given [payload] to the specified [threadId], if provided.
* Otherwise, the message will be sent to the currently active thread.
*
* You can observe the result via the [InAppChatView.EventsListener.onChatSent] event.
*
* @param payload The message payload to send.
* @param threadId The ID of the existing thread to send the message to. If `null`, the active thread will be used.
*/
fun send(payload: MessagePayload, threadId: String? = null)
/**
* Set the theme of the Livechat Widget.
* You can define widget themes in <a href="https://portal.infobip.com/apps/livechat/widgets">Live Chat widget setup page</a> in Infobip Portal, section `Advanced customization`.
* Please check widget <a href="https://www.infobip.com/docs/live-chat/widget-customization">documentation</a> for more details.
*
* Function allows to change widget theme while chat is shown - in runtime.
* If you set widget theme before chat is initialized by [InAppChatView.init] the theme will be used once chat is loaded.
*
* @param widgetThemeName unique theme name, empty or blank value is ignored
*/
fun setWidgetTheme(widgetThemeName: String)
/**
* Get current livechat widget theme.
*
* @return applied theme name of livechat widget
*/
fun getWidgetTheme(): String?
/**
* Creates a new thread with an initial message defined by the given [payload].
*
* You can observe the result via the [InAppChatView.EventsListener.onChatThreadCreated] event.
*
* @param payload The message payload used to start the new thread.
*/
fun createThread(payload: MessagePayload)
/**
* Requests current threads from livechat widget.
*
* You can observe result by [InAppChatView.EventsListener.onChatThreadsReceived] event.
*/
fun getThreads()
/**
* Requests shown thread - active from livechat widget.
*
* You can observe result by [InAppChatView.EventsListener.onChatActiveThreadReceived] event.
*/
fun getActiveThread()
/**
* Navigates livechat widget to thread specified by provided [threadId].
*
* You can observe result by [InAppChatView.EventsListener.onChatThreadShown] event.
*
* @param threadId thread to be shown
*/
fun showThread(threadId: String)
/**
* Navigates livechat widget from [LivechatWidgetView.THREAD] back to [LivechatWidgetView.THREAD_LIST] destination in multithread widget. It does nothing if widget is not multithread.
*/
fun showThreadList()
}
expand to see Java code
public class InAppChatView {
public void init(@NotNull Lifecycle lifecycle);
@Deprecated public void restartConnection();
public void resumeChatConnection();
@Deprecated public void stopConnection();
public void pauseChatConnection();
@Deprecated public void setLanguage(@NotNull Locale locale);
public void setLanguage(@NotNull LivechatWidgetLanguage language);
@NotNull public LivechatWidgetLanguage getLanguage();
@Deprecated public void sendContextualData(@NotNull String data, @NotNull Boolean allMultiThreadStrategy);
public void sendContextualData(@NotNull String data, @NotNull MultithreadStrategy flag);
@Deprecated public void sendChatMessageDraft(@NotNull String draft);
@Deprecated public void sendChatMessage(@Nullable String message);
@Deprecated public void sendChatMessage(@Nullable String message, @Nullable InAppChatMobileAttachment attachment);
public void send(@NotNull MessagePayload payload, @Nullable String threadId);
public void send(@NotNull MessagePayload payload);
public boolean isMultiThread();
public void setEventListener(@Nullable InAppChatView.EventListener eventListener);
@Nullable public InAppChatView.EventListener getEventListener();
public void setErrorsHandler(@NotNull InAppChatView.ErrorsHandler errorsHandler);
@NotNull public InAppChatView.ErrorsHandler getErrorsHandler();
@NotNull public InAppChatView.ErrorsHandler getDefaultErrorsHandler();
public void setWidgetTheme(@NotNull String widgetThemeName);
public @Nullable String getWidgetTheme();
public void createThread(@NotNull MessagePayload payload);
public void getThreads();
public void getActiveThread();
public void showThread(@NotNull String threadId);
public void showThreadList();
}
In-app chat consists of native Android views and Livechat widget presented in WebView
. Navigation toolbar and chat input are done using native Android views. Livechat widget shows messages list. You can customize native Android views and Livechat widget separately. To customize native parts of In-app chat you must provide Android theme. Read more about Livechat widget customization options in Livechat widget theme section. Using combination of both, Android theme and Livechat widget theme, you can fully customize In-app chat.
For higher integration flexibility over In-app chat, you can display In-app chat as view and avoid all not necessary native Android views and use only Livechat widget.
Version 8.0.0 onwards introduces a new approach to customizing the In-app chat with new attributes. The final value for every customizable attribute is resolved from multiple source-by-source priorities. The source with the highest priority defines the final attribute value. If a source does not define an attribute value, there is a fallback to the source with a lower priority.
Sources by priority:
-
InAppChatTheme
provided in runtime -
IB_AppTheme.Chat
Android theme defined in xml - Livechat widget theme
- In-app chat default theme
To customize the In-app chat you have to define your own custom theme. There are two ways to do that:
- In application's
styles.xml
with nameIB_AppTheme.Chat
. The In-app chat offers 4 theme attributes, each to customize separate part/view of the In-app chat screen.
<resources>
<style name="IB_AppTheme.Chat">
<item name="ibChatToolbarStyle">@style/InAppChat.Demo.Toolbar</item> <!-- In-app chat toolbar style -->
<item name="ibChatAttachmentToolbarStyle">@style/InAppChat.Demo.Toolbar</item> <!-- In-app chat attachment preview toolbar style -->
<item name="ibChatInputStyle">@style/InAppChat.Demo.Input</item> <!-- In-app chat message input style -->
<item name="ibChatStyle">@style/InAppChat.Demo.Chat</item> <!-- In-app chat style -->
</style>
<style name="Demo"/>
</resources>
- In code, you can pass
InAppChatTheme
toInAppChat.setTheme()
, which provides same customization as the xml approach.
InAppChat.getInstance(context).setTheme(
InAppChatTheme(
InAppChatToolbarStyle(), //chat toolbar
InAppChatToolbarStyle(), //attachment toolbar
InAppChatStyle(),
InAppChatInputViewStyle()
)
)
expand to see Java code
InAppChat.getInstance(context).setTheme(
new InAppChatTheme(
new InAppChatToolbarStyle(), //chat toolbar
new InAppChatToolbarStyle(), //attachment toolbar
new InAppChatStyle(),
new InAppChatInputViewStyle()
)
);
Both theme attributes ibChatToolbarStyle
and ibChatAttachmentToolbarStyle
support same toolbar style attributes. See also a list of supported attributes for
TextAppearance
.
<style name="InAppChat.Demo.Toolbar" parent="Demo">
<item name="ibChatToolbarBackgroundColor">@android:color/black</item>
<item name="ibChatStatusBarBackgroundColor">@android:color/black</item>
<item name="ibChatStatusBarIconsColorMode">light</item> <!-- Values light or dark, supported only for API >= 23 -->
<item name="ibChatNavigationIcon">@drawable/ic_chat_arrow_back</item>
<item name="ibChatNavigationIconTint">@android:color/white</item>
<item name="ibChatSaveAttachmentMenuItemIcon">@drawable/ic_chat_save</item> <!-- ibChatAttachmentToolbarStyle only -->
<item name="ibChatMenuItemsIconTint">@android:color/white</item>
<item name="ibChatTitleTextAppearance">@style/TextAppearance.MaterialComponents.Headline6</item>
<item name="ibChatTitleTextColor">@android:color/white</item>
<item name="ibChatTitleText">@null</item>
<item name="ibChatTitleCentered">false</item>
<item name="ibChatSubtitleTextAppearance">@null</item>
<item name="ibChatSubtitleTextColor">@android:color/white</item>
<item name="ibChatSubtitleText">@null</item>
<item name="ibChatSubtitleCentered">false</item>
</style>
ibChatTitleTextColor
value takes precedence overibChatTitleTextAppearance
'stextColor
attribute value. Same applies toibChatSubtitleTextColor
andibChatSubtitleTextAppearance
.
Theme attribute ibChatStyle
supports the following chat style attributes. See also a list of supported attributes for TextAppearance
.
<style name="InAppChat.Demo.Chat" parent="Demo">
<item name="ibChatBackgroundColor">@android:color/white</item>
<item name="ibChatProgressBarColor">@android:color/black</item>
<item name="ibChatNetworkConnectionErrorText">Your custom network connection error message</item>
<item name="ibChatNetworkConnectionErrorTextColor">@android:color/black</item>
<item name="ibChatNetworkConnectionErrorTextAppearance">@style/TextAppearance.MaterialComponents.Subtitle1</item>
<item name="ibChatNetworkConnectionErrorLabelBackgroundColor">@android:color/gray</item>
</style>
ibChatNetworkConnectionErrorTextColor
value takes precedence overibChatNetworkConnectionErrorTextAppearance
'stextColor
attribute value.
Theme attribute ibChatInputStyle
supports the following chat input style attributes. See also a list of supported attributes for TextAppearance
.
<style name="InAppChat.Demo.Input" parent="Demo">
<item name="ibChatInputTextAppearance">@style/TextAppearance.MaterialComponents.Body1</item>
<item name="ibChatInputTextColor">@android:color/black</item>
<item name="ibChatInputBackgroundColor">@android:color/white</item>
<item name="ibChatInputHintText">Your custom hint</item>
<item name="ibChatInputHintTextColor">@android:color/darker_gray</item>
<item name="ibChatInputAttachmentBackgroundColor">@android:color/white</item>
<item name="ibChatInputAttachmentBackgroundDrawable">@null</item>
<item name="ibChatInputAttachmentIcon">@null</item>
<item name="ibChatInputAttachmentIconTint">@android:color/black</item>
<item name="ibChatInputSendBackgroundColor">@android:color/white</item>
<item name="ibChatInputSendBackgroundDrawable">@null</item>
<item name="ibChatInputSendIcon">@null</item>
<item name="ibChatInputSendIconTint">@android:color/black</item>
<item name="ibChatInputSeparatorLineColor">@android:color/darker_gray</item>
<item name="ibChatInputSeparatorLineVisible">true</item>
<item name="ibChatInputCursorColor">@android:color/black</item>
</style>
ibChatInputTextColor
value takes precedense overibChatInputTextAppearance
'stextColor
attribute value.ibChatInputAttachmentIconTint
andibChatInputSendIconTint
support color state list resource type.
List of supported attributes for TextAppearance
:
<attr name="textColor" />
<attr name="textSize" />
<attr name="textStyle" />
<attr name="typeface" />
<attr name="fontFamily" />
<attr name="textColorHighlight" />
<attr name="textColorHint" />
<attr name="textColorLink" />
<attr name="textAllCaps" format="boolean" />
<attr name="shadowColor" format="color" />
<attr name="shadowDx" format="float" />
<attr name="shadowDy" format="float" />
<attr name="shadowRadius" format="float" />
<attr name="elegantTextHeight" format="boolean" />
<attr name="letterSpacing" format="float" />
<attr name="fontFeatureSettings" format="string" />
Quick migration to a new 8.0.0 customization approach
If you want to preserve the current color setup and migrate to a new customization approach, follow the section.
Deprecated approach:
<resources>
<style name="IB_AppTheme.Chat">
<item name="colorPrimary">@color/colorPrimary</item> <!-- DEPRECATED | color of toolbar background and send chat button tint -->
<item name="colorPrimaryDark">@color/colorPrimaryDark</item> <!-- DEPRECATED | color of status / notification bar -->
<item name="colorControlNormal">@android:color/white</item> <!-- DEPRECATED | color of navigation icon in toolbar -->
<item name="titleTextColor">@android:color/white</item> <!-- DEPRECATED | color of toolbar title text -->
</style>
</resources>
<resources>
<style name="IB_AppTheme.ChatAttach">
<item name="colorPrimary">@color/colorPrimary</item> <!-- DEPRECATED | color of toolbar background -->
<item name="colorPrimaryDark">@color/colorPrimaryDark</item> <!-- DEPRECATED | color of status / notification bar -->
<item name="colorControlNormal">@android:color/white</item> <!-- DEPRECATED | color of navigation icon in toolbar -->
<item name="titleTextColor">@android:color/white</item> <!-- DEPRECATED | color of toolbar title text -->
</style>
</resources>
is equals to a new approach
<resources>
<style name="IB_AppTheme.Chat">
<item name="ibChatToolbarStyle">@style/InAppChat.Demo.Toolbar</item> <!-- In-app chat toolbar style -->
<item name="ibChatAttachmentToolbarStyle">@style/InAppChat.Demo.Toolbar</item> <!-- In-app chat attachment preview toolbar style -->
</style>
<style name="Demo"/>
<style name="InAppChat.Demo.Toolbar" parent="Demo">
<item name="ibChatToolbarBackgroundColor">@color/colorPrimary</item> <!-- color of toolbar background and send chat button tint -->
<item name="ibChatStatusBarBackgroundColor">@color/colorPrimaryDark</item> <!-- color of status / notification bar -->
<item name="ibChatNavigationIconTint">@android:color/white</item> <!-- color of navigation icon in toolbar -->
<item name="ibChatTitleTextColor">@android:color/white</item> <!-- color of toolbar title text -->
</style>
</resources>
Customization approach before version 8.0.0
Certain attributes of a built-in chat view are customizable through resources.
You can supply your custom title for chat activity via ib_chat_view_title
string in strings.xml
:
<resources>
<string name="ib_chat_view_title">My Chat</string>
</resources>
You can define your own custom theme for the chat view in styles.xml
and change action bar/toolbar and notification bar colors, colorPrimary
and colorPrimaryDark
respectively. Use IB_AppTheme.Chat
name for a chat view theme and IB_AppTheme.ChatAttach
name for a chat attachments preview theme.
<resources>
<style name="IB_AppTheme.Chat">
<item name="colorPrimary">@color/colorPrimary</item> <!-- color of toolbar background and send chat button tint -->
<item name="colorPrimaryDark">@color/colorPrimaryDark</item> <!-- color of status / notification bar -->
<item name="colorControlNormal">@android:color/white</item> <!-- color of navigation icon in toolbar -->
<item name="titleTextColor">@android:color/white</item> <!-- color of toolbar title text -->
</style>
</resources>
<resources>
<style name="IB_AppTheme.ChatAttach">
<item name="colorPrimary">@color/colorPrimary</item> <!-- color of toolbar background -->
<item name="colorPrimaryDark">@color/colorPrimaryDark</item> <!-- color of status / notification bar -->
<item name="colorControlNormal">@android:color/white</item> <!-- color of navigation icon in toolbar -->
<item name="titleTextColor">@android:color/white</item> <!-- color of toolbar title text -->
</style>
</resources>
Version 12.4.0 onwards introduces a new option of setting a Livechat widget theme. Livechat widget themes are defined on the Live Chat widget setup page on Infobip Portal. You can define multiple custom themes and customize various widget attributes. Check out the Livechat documentation to learn about all possible widget customization options.
To set Livechat theme in In-app chat you must:
- Define the name and values of your theme(s) in a JSON format, under widget section Theme -> Advance Customisation, in Infobip Portal.
- Once you know the names of your themes, you can use following function in runtime, and the customisation will automatically be applied:
InAppChat.getInstance(context).setWidgetTheme("myThemeName")
expand to see Java code
InAppChat.getInstance(context).setWidgetTheme("myThemeName");
Mobile Messaging SDK triggers the NOTIFICATION_TAPPED
event when a user taps on a notification.
There are several types of in-app chat-related notifications:
- In-app chat message push notification - posted for each message the chat receives while not active or in the background
- Mobile push notification with on tap action Open chatbot in LiveChat
- Mirror push notification with primary button action Open chatbot in LiveChat
- In-app message with on tap action Open chatbot in LiveChat
Note that in-app chat-related notifications may be recognized by the provided Message
, in a following way:
You can register a broadcast receiver for the NOTIFICATION_TAPPED
event and process the corresponding message:
val tapReceiver = object: BroadcastReceiver() {
override fun onReceive(context:Context, intent: Intent) {
val message = Message.createFrom(intent)
val action = OpenLivechatAction.parseFrom(message)
if (message.isChatMessage()) {
// in-app chat message push notification tapped
} else if (action != null) {
// notification action "Open chatbot in LiveChat" triggered
}
}
}
LocalBroadcastManager.getInstance(context).registerReceiver(tapReceiver, IntentFilter(Event.NOTIFICATION_TAPPED.key))
expand to see Java code
private final BroadcastReceiver tapReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Message message = Message.createFrom(intent);
OpenLivechatAction action = OpenLivechatAction.parseFrom(message);
if (message.isChatMessage()) {
// in-app chat message notification tapped
} else if (action != null) {
// notification action "Open chatbot in LiveChat" triggered
}
}
};
LocalBroadcastManager.getInstance(context).registerReceiver(tapReceiver, new IntentFilter(Event.NOTIFICATION_TAPPED.getKey()));
In-app chat SDK implements default behaviour:
- in-app chat message push notification tap opens application's default launcher activity (can be changed in Notification settings)
- notification action Open chatbot in LiveChat interaction opens the in-app chat screen
You can define custom notification interaction handling by implementing InAppChatNotificationInteractionHandler
interface and passing the instance into the In-app chat SDK.
InAppChatNotificationInteractionHandler.onNotificationInteracted(message: Message)
is triggered every time in-app chat-related notification has been interacted with.
val notificationInteractionHandler = object: InAppChatNotificationInteractionHandler() {
override fun onNotificationInteracted(message: Message) {
val action = OpenLivechatAction.parseFrom(message)
if (message.isChatMessage()) {
// in-app chat message push notification tapped
} else if (action != null) {
// notification action "Open chatbot in LiveChat" triggered
}
}
}
InAppChat.getInstance(context).setNotificationInteractionHandler(notificationInteractionHandler)
expand to see Java code
private InAppChatNotificationInteractionHandler notificationInteractionHandler = new InAppChatNotificationInteractionHandler() {
@Override
public void onNotificationInteracted(@NonNull Message message) {
OpenLivechatAction action = OpenLivechatAction.parseFrom(message);
if (message.isChatMessage()) {
// in-app chat message notification tapped
} else if (action != null) {
// notification action "Open chatbot in LiveChat" triggered
}
}
};
InAppChat.getInstance(context).setNotificationInteractionHandler(notificationInteractionHandler);
Additionally, you can get a default handler. So whenever it is needed, you can inject a custom handler, pass the null
value to notification interactions that are not handled, or use a default handler again.
val currentHandler = InAppChat.getInstance(context).getNotificationInteractionHandler()
val defaultHandler = InAppChat.getInstance(context).getDefaultNotificationInteractionHandler()
InAppChat.getInstance(context).setNotificationInteractionHandler(defaultHandler)
Set a title and a message body in the in-app chat message notifications and override default values.
The default value for a title is Chat message
.
The default value for a body is the original message content from a push notification.
To use default values again, set setChatPushTitle(null)
and setChatPushBody(null)
.
InAppChat.getInstance(context).setChatPushTitle("Custom chat push title")
InAppChat.getInstance(context).setChatPushBody("Custom chat push body")
expand to see Java code
InAppChat.getInstance(context).setChatPushTitle("Custom chat push title");
InAppChat.getInstance(context).setChatPushBody("Custom chat push body");
Version 5.3.0 onwards includes a new API to get and reset current unread chat messages push counter. The counter increments each time the application receives a chat message push. This usually happens when a chat screen is inactive or the application is in the background/terminated state. To get a current counter value use the following API.
val messageCounter = InAppChat.getInstance(context).messageCounter
// use the count the way that suits you
expand to see Java code
int unreadChatMessagesCount = InAppChat.getInstance(context).getMessageCounter();
// use the count the way that suits you
In-app chat SDK automatically resets the counter to 0 whenever a user opens the chat screen. However, use the following API to manually reset the counter.
InAppChat.getInstance(context).resetMessageCounter()
expand to see Java code
InAppChat.getInstance(context).resetMessageCounter();
You can set up a broadcast receiver to get updates about the counter in runtime for the InAppChatEvent.UNREAD_MESSAGES_COUNTER_UPDATED
event with an extra broadcast parameter BroadcastParameter.EXTRA_UNREAD_CHAT_MESSAGES_COUNT
of the int
value. For example:
<receiver android:name=".UnreadMessagesCounterReceiver" android:exported="false">
<intent-filter>
<action android:name="org.infobip.mobile.messaging.chat.UNREAD_MESSAGES_COUNTER_UPDATED"/>
</intent-filter>
</receiver>
Receiver code:
override fun onReceive(context: Context?, intent: Intent) {
val unreadChatMessagesCounter = intent.getIntExtra(BroadcastParameter.EXTRA_UNREAD_CHAT_MESSAGES_COUNT)
}
expand to see Java code
@Override
public void onReceive(Context context, Intent intent) {
int unreadChatMessagesCounter = intent.getIntExtra(BroadcastParameter.EXTRA_UNREAD_CHAT_MESSAGES_COUNT);
}
In-app chat SDK provides you multiple useful chat related events. Based on the approach you use to display a chat, there are different ways to subscribe for chat events. If you display chat:
- as
InAppChatScreen
orInAppChatFragment
with assisted approach, you can observe the events usingInAppChatEventsListener
interface:InAppChat.getInstance(context).setEventsListener(InAppChatEventsListener)
- as
InAppChatFragment
with full ownership approach, you can observe the events usingInAppChatFragment.EventsListener
interface:InAppChatFragment.eventsListener = object : InAppChatFragment.EventsListener { //TODO override interface callbacks }
- as
InAppChatView
, you can observe the events usingInAppChatView.EventsListener
interface:InAppChatView.eventsListener = object : InAppChatView.EventsListener { //TODO override interface callbacks }
The In-app chat library supports all core SDK library events plus the following chat-specific events, which you can receive with intents in broadcast receivers:
Event | Parameters | Description |
---|---|---|
CHAT_CONFIGURATION_SYNCED |
Triggered when chat configuration is synchronized. | |
UNREAD_MESSAGES_COUNTER_UPDATED |
Unread messages count | Triggered when the number of unread messages is changed. |
CHAT_VIEW_CHANGED |
InAppChat view name | Triggered when the view in the InAppChat is changed. |
LIVECHAT_REGISTRATION_ID_UPDATED |
Livechat registration id | Triggered when livechat registration id is updated. |
CHAT_AVAILABILITY_UPDATED |
Boolean telling if chat is available | Triggered when chat availability is updated. |
You will need to register a receiver for each event of interest. In your receiver, you will be able to process parameters according to the table above, for example:
private val eventReceiver = object: BroadcastReceiver() {
override fun onReceive(context:Context, intent: Intent) {
// process event occurrence
}
}
LocalBroadcastManager.getInstance(context).registerReceiver(eventReceiver, IntentFilter(InAppChatEvent.CHAT_CONFIGURATION_SYNCED.key))
expand to see Java code
private final BroadcastReceiver eventReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
// process event occurrence
}
};
LocalBroadcastManager.getInstance(context).registerReceiver(eventReceiver, new IntentFilter(InAppChatEvent.CHAT_CONFIGURATION_SYNCED.getKey()));
Action name to subscribe to: org.infobip.mobile.messaging.chat.CHAT_CONFIGURATION_SYNCED
.
Action name to subscribe to: org.infobip.mobile.messaging.chat.UNREAD_MESSAGES_COUNTER_UPDATED
. Receiving event data in BroadcastReceiver:
override fun onReceive(context: Context, intent: Intent) {
val unreadMessagesCount = intent.getIntExtra(BroadcastParameter.EXTRA_UNREAD_CHAT_MESSAGES_COUNT)
}
expand to see Java code
@Override
public void onReceive(Context context, Intent intent) {
int unreadMessagesCount = intent.getIntExtra(BroadcastParameter.EXTRA_UNREAD_CHAT_MESSAGES_COUNT);
}
Action name to subscribe to: org.infobip.mobile.messaging.chat.CHAT_VIEW_CHANGED
. Receiving event data in BroadcastReceiver:
override fun onReceive(context: Context, intent: Intent) {
val view = intent.getStringExtra(BroadcastParameter.EXTRA_CHAT_VIEW)
val livechatWidgetView = LivechatWidgetView.valueOf(view)
}
expand to see Java code
@Override
public void onReceive(Context context, Intent intent) {
String view = intent.getStringExtra(BroadcastParameter.EXTRA_CHAT_VIEW);
LivechatWidgetView livechatWidgetView = LivechatWidgetView.valueOf(view);
}
Supported InAppChat view
values:
LOADING, THREAD_LIST, LOADING_THREAD, THREAD, CLOSED_THREAD, SINGLE_MODE_THREAD
Action name to subscribe to: org.infobip.mobile.messaging.chat.LIVECHAT_REGISTRATION_ID_UPDATED
. Receiving event data in BroadcastReceiver:
override fun onReceive(context: Context, intent: Intent) {
val livechatRegistrationId = intent.getStringExtra(BroadcastParameter.EXTRA_LIVECHAT_REGISTRATION_ID)
}
expand to see Java code
@Override
public void onReceive(Context context, Intent intent) {
String livechatRegistrationId = intent.getStringExtra(BroadcastParameter.EXTRA_LIVECHAT_REGISTRATION_ID);
}
Action name to subscribe to: org.infobip.mobile.messaging.chat.CHAT_AVAILABILITY_UPDATED
. Receiving event data in BroadcastReceiver:
override fun onReceive(context: Context, intent: Intent) {
val isChatAvailable = intent.getStringExtra(BroadcastParameter.EXTRA_IS_CHAT_AVAILABLE)
}
expand to see Java code
@Override
public void onReceive(Context context, Intent intent) {
String isChatAvailable = intent.getStringExtra(BroadcastParameter.EXTRA_IS_CHAT_AVAILABLE);
}
Version 3.1.0 onwards adds a feature to send and preview attachments. In order to capture a photo and a video In-app chat SDK declares CAMERA
permission in Manifest.xml
.
Media files captured from the camera are saved to the
/DCIM/Infobip
folder. Image files are scaled down to decrease the file size to match the attachment size limit, by default, if there is not custom setup in Livechat Widget it is 10MB .
By default, In-app chat supports the file types listed in the table below. If the Livechat widget is configured with custom attachment settings, In-app chat will follow that configuration instead.
Media type | File size limit | File format |
---|---|---|
image | 10MB | .jpg, .jpeg, .jpe, .bmp, .gif, .svg, .svgz, .png, .tiff, .tif |
video | 10MB | .avi, .mpeg, .mpg, .mpe, .m1v, .m2v, .qt, .mov, .mp4, .mp4v, .mpg4 |
audio | 10MB | .aac, .mpga, .mp2, .mp2a, .mp3, .m2a, .m3a, .oga, .ogg, .spx, .opus, .wav |
others | 10MB | .doc, .dot, .docx, .xls, .xlm, .xla, .xlc, .xlt, .xlw, .xlsx, .pdf, .txt, .text, .conf, .def, .list, .log, .in, .xml, .xsl |
Version 3.4.0 onwards introduces a new feature, attachments preview. In order to save an attachment In-app chat SDK declares WRITE_EXTERNAL_STORAGE
permission in Manifest.xml
.
Predefined messages prompted within the In-app chat (such as status updates, button titles, input field prompts) by default are localized in English, but can be changed by selecting a supported language listed in LivechatWidgetLanguage
enumerator.
InAppChat.getInstance(context).setLanguage(LivechatWidgetLanguage.SPANISH)
expand to see Java code
InAppChat.getInstance(context).setLanguage(LivechatWidgetLanguage.SPANISH);
It is possible to send contextual data / metadata to Infobip’s Conversations via the In-App chat SDK. Data can be sent several times but only last sent data are stored in conversation. Every sent data will overwrite the previously sent contextual data.
There are two possible scenarios:
- Contextual data is sent before chat is present and loaded. In-app chat SDK stores the data and automatically sends it once the chat is loaded.
- Contextual data is sent when chat is present and loaded. In a single thread, the data will be sent to an open conversation. In multi-thread, Livechat widget tracks a list of open conversations, and based on the strategy, it will either send it to a currently
ACTIVE
conversation orALL
conversations.
In-app chat supports having multiple conversations between an agent and a customer. Considering this, In-app chat needs to know to which conversations send contextual data:
-
ACTIVE
- sends metadata to a currently active conversation -
ALL
- sends metadata to all conversations between an agent and a customer (This field has no impact in case of a single-thread Livechat widget.) -
ALL_PLUS_NEW
- Sends metadata to all non-closed conversations for the widget and to any newly created conversations within the current session. If you send an event of a different type in the same session after usingALL_PLUS_NEW
, it will override the previous metadata settings, and newly created chats will no longer receive metadata from the earlier usage ofALL_PLUS_NEW
.
In-app chat SDK function to send contextual data has two parameters:
- The mandatory data, sent as string, in a format of JavaScript objects and values (for guidance, it must be accepted by JSON.stringify())
- Mandatory multithread strategy enum
MultithreadStrategy
flag. Possible values ACTIVE, ALL or ALL_PLUS_NEW.
Usage:
InAppChat chat = InAppChat.getInstance(context);
// Present and wait till the chat is loaded and ready, then simply call
chat.sendContextualData("{name: 'Robert'}");
// or with multithread flag
chat.sendContextualData("{name: 'Robert'}", ACTIVE);
If you use InAppChat as View you must use
InAppChatView
public function to send contextual data. If you use InAppChat as Fragment you must useInAppChatFragment
public function to send contextual data.
A default Livechat widget takes the name of a channel InAppChat uses in the backend and works with single chat threads: one customer can only have one conversation opened. You can customize this behavior and configure a Livechat widget to allow for multiple chat threads.

When the setting above is enabled, the InAppChat UI will automatically offer in mobile:
- A list (initially empty) of all unsolved conversation threads the user has opened.
- A button to "Start new chat" thread.
- Navigation to each conversation thread a user can open with a tap.

The functionality for multiple chat threads works out of the box. There is no need for extra implementation on the mobile integrator side. But there is something you may need to consider regarding navigation bar and the back button:
InAppChat, when multiple threads are in use, needs to take control over the back button to allow for a return to the threads list. In other words, InAppChat will handle the internal back navigation logic.
For this reason, if you show InAppChat as a fragment, it is mandatory to implement InAppChatFragment.InAppChatActionBarProvider
in your UI component, as shown in the example below.
If you show InAppChat as an activity, ignore this setup.
class MainActivity: AppCompatActivity(), InAppChatFragment.InAppChatActionBarProvider {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
//Shows in-app chat as Fragment
InAppChat.getInstance(applicationContext).showInAppChatFragment(supportFragmentManager, R.id.fragmentContainer)
}
override fun getOriginalSupportActionBar(): ActionBar? = supportActionBar
override fun onInAppChatBackPressed() {
InAppChat.getInstance(this).hideInAppChatFragment(supportFragmentManager)
//you can pass "true" as second argument to disconnect chat when fragment is hidden to receive push notifications
//InAppChat.getInstance(this).hideInAppChatFragment(supportFragmentManager, true)
}
}
expand to see Java code
public class MainActivity extends AppCompatActivity implements InAppChatFragment.InAppChatActionBarProvider {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Shows in-app chat as Fragment
InAppChat.getInstance(getApplicationContext()).showInAppChatFragment(getSupportFragmentManager(), R.id.fragmentContainer);
}
@Nullable
@Override
public ActionBar getOriginalSupportActionBar() {
return getSupportActionBar();
}
@Override
public void onInAppChatBackPressed() {
InAppChat.getInstance(MainActivity.this).hideInAppChatFragment(getSupportFragmentManager());
//you can pass "true" as second argument to disconnect chat when fragment is hidden to receive push notifications
//InAppChat.getInstance(MainActivity.this).hideInAppChatFragment(getSupportFragmentManager());
}
}
It is possible to authenticate a user before accesing InAppChat. To do so, you'll need to enable the following feature in a Livechat widget.

The authentication is accomplished by combining the Mobile Messaging SDK personalisation method with a JWT (JSON Web Token). The token needs to be generated at your end. For more details, see the instructions.
Authentication will use a unique identifier for your user, such as an email address, a phone number, or an external identifier. It is crucial that the identifier is valid and matches the identity defined in the UserIdentity
you've passed in the Mobile Messaging SDK personalisation call. Otherwise, you'll end up with an authentication error.
InAppChat contains a JwtProvider
interface to give InAppChat ability to authenticate. Implement the interface and pass the instance into InAppChat. The JwtProvider.provideJwt()
function can be
triggered multiple times during the InAppChat's lifetime due to various events like screen orientation change, internet re-connection, etc. If you can ensure JWT expiration time is more than the
InAppChat's lifetime, you can return a cached token. Otherwise, it is important to provide a fresh new token for each invocation.
/*
1 - A user authenticates in your system and you recognize their unique identifier.
2 - You call the `personalize()` function, pass in the unique identifier, and optionally, other attributes, such as first name, second name, etc.
3 - You can now display a chat as authenticated by doing the following:
*/
InAppChat.getInstance(context).widgetJwtProvider = JwtProvider {
//every invocation creates and returns a fresh token
"your JWT"
}
InAppChat.getInstance(context).inAppChatScreen().show()
expand to see Java code
/*
1 - A user authenticates in your system and you recognize their unique identifier.
2 - Your call is personalized with the unique identifier, and optionally, with other attributes, such as first name, second name, etc.
3 - You can now display a chat as authenticated by doing the following:
*/
InAppChat.getInstance(context).setWidgetJwtProvider(new JwtProvider() {
@Override
public String provideJwt() {
//every invocation creates and returns a fresh token
return "your JWT";
}
});
InAppChat.getInstance(context).inAppChatScreen().show();
An InAppChat demo application provided within the Mobile Messaging SDK offers a functional interface for
testing the authentication use case. For it to work, you need to set your WIDGET_ID
and WIDGET_SECRET_KEY_JSON
values in the MainActivity.java
- chat
flavour.
The In-app chat SDK provides LivechatWidgetApi
interface with comprehensive set of methods to interact with the Livechat widget. This API allows developers to perform various actions such as
managing the widget's state, sending messages, drafts or contextual data. It enables seamless interaction with the Livechat Widget without the need to display
the InAppChat in UI, making it ideal for applications that require only background operations.
To get Livechat Widget API follow:
val api: LivechatWidgetApi = InAppChat.getInstance(context).livechatWidgetApi
expand to see Java code
LivechatWidgetApi api = InAppChat.getInstance(context).getLivechatWidgetApi();
/**
* The `LivechatWidgetApi` interface provides methods to interact with the Livechat widget.
* It allows you to perform various actions such as sending messages, setting themes, and managing the widget's state.
* It creates queue for widget functions execution using Kotlin Mutex, single function is executed at a time.
*
* ### Using `LivechatWidgetEventsListener`
* To get the real return value from the Livechat widget, you should use the [LivechatWidgetEventsListener].
* This listener provides events that you can handle to get the actual data from the widget.
*
*/
interface LivechatWidgetApi {
/**
* Indicates if livechat widget is loaded.
*/
val isWidgetLoaded: Boolean
/**
* Listener for livechat widget events. It allows to observe widget loading state, widget events and widget functions results.
*/
var eventsListener: LivechatWidgetEventsListener?
/**
* [JwtProvider] gives livechat widget ability to authenticate.
* Must be set before calling [loadWidget] method. If not set, it will be taken from current `InAppChat` configuration.
*/
var jwtProvider: JwtProvider?
/**
* Livechat widget domain.
* Must be set before calling [loadWidget] method. If not set, it will be taken from current `InAppChat` configuration.
*/
var domain: String?
/**
* Timeout duration for loading the Livechat widget, in milliseconds.
*
* This value must be set **before** calling [loadWidget].
*
* - **Minimum allowed:** 5,000 ms (5 seconds)
* - **Maximum allowed:** 300,000 ms (5 minutes)
* - **Default value:** 10,000 ms (10 seconds)
*
* @throws IllegalStateException if the value is set outside the allowed range.
*/
@set:Throws(IllegalStateException::class)
var loadingTimeoutMillis: Long
/**
* Triggers livechat widget loading. Does nothing, if widget is already loaded.
* You can observe loading's result by [LivechatWidgetEventsListener.onLoadingFinished] event.
* If you want to force load widget again, you need to call [reset] first.
* If you want to load widget with current `InAppChat` configuration, you can call [loadWidget] without parameters.
* You can control widget loading timeout by setting [loadingTimeoutMillis] property.
*
* @param widgetId livechat widget id to be loaded, if not provided, it will be taken from current configuration
* @param jwt jwt token for authentication, if not provided, it will be taken from current `InAppChat` configuration
* @param domain domain for livechat widget, if not provided, it will be taken from current `InAppChat` configuration
* @param theme theme for livechat widget, if not provided, it will be taken from current `InAppChat` configuration
* @param language language for livechat widget, if not provided, it will be taken from current `InAppChat` configuration
*/
fun loadWidget(
widgetId: String? = null,
jwt: String? = null,
domain: String? = null,
theme: String? = null,
language: LivechatWidgetLanguage? = null,
)
/**
* Triggers livechat widget loading with current `InAppChat` configuration. Does nothing, if widget is already loaded.
* You can observe loading's result by [LivechatWidgetEventsListener.onLoadingFinished] event.
* If you want to force load widget again, you need to call [reset] first.
* You can control widget loading timeout by setting [loadingTimeoutMillis] property.
*
* @param widgetId livechat widget id to be loaded, if not provided, it will be taken from current configuration
*/
fun loadWidget(
widgetId: String? = null,
) = loadWidget(widgetId, jwt = null, domain = null, theme = null, language = null)
/**
* Triggers livechat widget loading with current `InAppChat` configuration. Does nothing, if widget is already loaded.
* You can observe loading's result by [LivechatWidgetEventsListener.onLoadingFinished] event.
* If you want to force load widget again, you need to call [reset] first.
* You can control widget loading timeout by setting [loadingTimeoutMillis] property.
*/
fun loadWidget() = loadWidget(widgetId = null, jwt = null, domain = null, theme = null, language = null)
/**
* Pauses livechat widget connection, but widget stay loaded in WebView.
* Widget connection and loaded state are independent.
*
* By the connection you can control push notifications.
* Push notifications are active only when the connection is not active.
*
* Use [resumeConnection] to reestablish connection.
*
* To detect if the connection is paused use [LivechatWidgetEventsListener.onConnectionPaused] event.
*/
fun pauseConnection()
/**
* Resumes livechat widget connection when you previously called [pauseConnection].
*
* By the connection you can control push notifications.
* Push notifications are active only when the connection is not active.
*
* Use [pauseConnection] to pause connection.
*
* To detect if the connection is resumed use [LivechatWidgetEventsListener.onConnectionResumed] event.
*/
fun resumeConnection()
/**
* Sends a message defined by the given [payload] to the specified [threadId], if provided.
* Otherwise, the message will be sent to the currently active thread.
*
* You can observe the result via the [LivechatWidgetEventsListener.onSent] event.
*
* @param payload The message payload to send.
* @param threadId The ID of the existing thread to send the message to. If `null`, the active thread will be used.
*/
fun send(payload: MessagePayload, threadId: String? = null)
/**
* Sends a message defined by the given [payload] to the currently active thread.
*
* You can observe the result via the [LivechatWidgetEventsListener.onSent] event.
*
* @param payload The message payload to send.
*/
fun send(payload: MessagePayload) = send(payload = payload, threadId = null)
/**
* Sends contextual data.
*
* You can observe result by [LivechatWidgetEventsListener.onContextualDataSent] event.
*
* @param data contextual data in JSON format
* @param multiThreadFlag multithread strategy flag
*/
fun sendContextualData(data: String, multiThreadFlag: MultithreadStrategy)
/**
* Creates a new thread with an initial message defined by the given [payload].
*
* You can observe the result via the [LivechatWidgetEventsListener.onThreadCreated] event.
*
* @param payload The message payload used to start the new thread.
*/
fun createThread(payload: MessagePayload)
/**
* Requests current threads from livechat widget.
*
* You can observe result by [LivechatWidgetEventsListener.onThreadsReceived] event.
*/
fun getThreads()
/**
* Requests shown thread - active from livechat widget.
*
* You can observe result by [LivechatWidgetEventsListener.onActiveThreadReceived] event.
*/
fun getActiveThread()
/**
* Navigates livechat widget to thread specified by provided [threadId].
*
* You can observe result by [LivechatWidgetEventsListener.onThreadShown] event.
*
* @param threadId thread to be shown
*/
fun showThread(threadId: String)
/**
* Navigates livechat widget from [LivechatWidgetView.THREAD] back to [LivechatWidgetView.THREAD_LIST] destination in multithread widget. It does nothing if widget is not multithread.
*
* You can observe result by [LivechatWidgetEventsListener.onThreadListShown] or [LivechatWidgetEventsListener.onWidgetViewChanged] event.
*/
fun showThreadList()
/**
* Sets a livechat widget's language.
*
* You can observe result by [LivechatWidgetEventsListener.onLanguageChanged] event.
*
* @param language language to be set
*/
fun setLanguage(language: LivechatWidgetLanguage)
/**
* Sets a livechat widget's theme.
*
* You can observe result by [LivechatWidgetEventsListener.onThemeChanged] event.
*
* You can define widget themes in <a href="https://portal.infobip.com/apps/livechat/widgets">Live Chat widget setup page</a> in Infobip Portal, section `Advanced customization`.
* Please check widget <a href="https://www.infobip.com/docs/live-chat/widget-customization">documentation</a> for more details.
*
* @param themeName theme name to be set
*/
fun setTheme(themeName: String)
/**
* Resets livechat widget state and loads blank page.
*/
fun reset()
}
expand to see Java code
public interface LivechatWidgetApi {
boolean isWidgetLoaded();
void setEventsListener(@Nullable LivechatWidgetEventsListener eventsListener);
@Nullable LivechatWidgetEventsListener getEventsListener();
void setJwtProvider(@Nullable JwtProvider jwtProvider);
@Nullable JwtProvider getJwtProvider();
void setDomain(@Nullable String domain);
@Nullable String getDomain();
@Throws(IllegalArgumentException) void setLoadingTimeoutMillis(@NotNull Long timeout);
@NotNull Long getLoadingTimeoutMillis();
void loadWidget(@Nullable String widgetId, @Nullable String jwt, @Nullable String domain, @Nullable String theme, @Nullable LivechatWidgetLanguage language);
void loadWidget(@Nullable String widgetId);
void loadWidget();
void pauseConnection();
void resumeConnection();
void send(@NotNull MessagePayload payload, @Nullable String threadId);
void send(@NotNull MessagePayload payload);
void sendContextualData(@NotNull String data, @NotNull MultithreadStrategy multiThreadFlag);
void createThread(@NotNull MessagePayload payload);
void getThreads();
void getActiveThread();
void showThread(@NotNull String threadId);
void showThreadList();
void setLanguage(@NotNull LivechatWidgetLanguage language);
void setTheme(@NotNull String themeName);
void reset();
}
To get the real return value from the Livechat widget, you should use the LivechatWidgetEventsListener
.
This listener provides events that you can handle to get the actual data from the widget.
/**
* Interface for listening to events from livechat widget.
*
* You can use [DefaultLivechatWidgetEventsListener] to override only necessary methods.
*/
interface LivechatWidgetEventsListener {
/**
* Called when livechat widget page starts loading.
*/
fun onPageStarted(url: String?)
/**
* Called when livechat widget page loading finished.
*/
fun onPageFinished(url: String?)
/**
* Called when the livechat widget has finished loading.
* A success result indicates that the loading process is complete.
* The boolean flag in the payload specifies whether the widget is fully loaded and ready for use.
* Typically, this flag will be true. However, there are scenarios where the loading completes successfully, but the widget is not loaded,
* such as when [LivechatWidgetApi.reset] is called.
*/
fun onLoadingFinished(result: LivechatWidgetResult<Boolean>)
/**
* Called when livechat widget connection is paused.
*/
fun onConnectionPaused(result: LivechatWidgetResult<Unit>)
/**
* Called when livechat widget connection is resumed.
*/
fun onConnectionResumed(result: LivechatWidgetResult<Unit>)
/**
* Called when any message payload is sent.
*/
fun onSent(result: LivechatWidgetResult<LivechatWidgetMessage?>)
/**
* Called when contextual data is sent.
*/
fun onContextualDataSent(result: LivechatWidgetResult<String?>)
/**
* Called when livechat widget threads were requested.
*/
fun onThreadsReceived(result: LivechatWidgetResult<LivechatWidgetThreads>)
/**
* Called when livechat widget active thread was requested.
* Success result can contain null if there is no existing thread for current user session or current widget destination is not [LivechatWidgetView.THREAD].
*/
fun onActiveThreadReceived(result: LivechatWidgetResult<LivechatWidgetThread?>)
/**
* Called when livechat widget thread was created.
*/
fun onThreadCreated(result: LivechatWidgetResult<LivechatWidgetMessage?>)
/**
* Called when livechat widget thread is shown.
*/
fun onThreadShown(result: LivechatWidgetResult<LivechatWidgetThread>)
/**
* Called when livechat widget thread list is shown.
*/
fun onThreadListShown(result: LivechatWidgetResult<Unit>)
/**
* Called when livechat widget language is changed.
*/
fun onLanguageChanged(result: LivechatWidgetResult<String?>)
/**
* Called when livechat widget theme is changed.
*/
fun onThemeChanged(result: LivechatWidgetResult<String?>)
/**
* Called when livechat widget controls visibility changes.
* It says when you can show or hide input field.
*/
fun onControlsVisibilityChanged(visible: Boolean)
/**
* Called when livechat widget attachment preview is interacted.
*/
fun onAttachmentPreviewOpened(url: String?, type: String?, caption: String?)
/**
* Called when livechat widget view changes.
*/
fun onWidgetViewChanged(view: LivechatWidgetView)
/**
* Called when raw message is received from livechat widget.
*/
fun onRawMessageReceived(message: String?)
}
There are three types of messages you can send:
- Drafts, which are seen only by the agents in Conversations.
- Basic, for sending either a text or an attachment.
- Custom Data, which allows you to send a structured custom data related to the conversation, and optionally messages only visible for the agents, or visible by both, the agent and your Livechat user.
MessagePayload
is base class of all message payload types of Livechat widget.
/**
* Base class for all message payload types of livechat widget.
*
* Each subclass represents a specific kind of message that can be sent, such as text, draft, attachment, or custom data.
*
* @property type The type identifier of the message, used to distinguish payload variants.
*/
sealed class MessagePayload(
val type: LivechatWidgetMessageType
) {
/**
* Represents a draft message.
*
* @property message The text content of the draft. Must be non-blank and no longer than
* [LivechatWidgetApi.MESSAGE_MAX_LENGTH] characters.
*
* @throws IllegalArgumentException If [message] is blank or exceeds the maximum allowed length.
*/
data class Draft @Throws(IllegalArgumentException::class) constructor(
val message: String
) : MessagePayload(LivechatWidgetMessageType.DRAFT)
/**
* Represents a basic text message, optionally containing an attachment.
*
* Either [message] or [attachment] must be provided.
*
* @property message The text content of the message. Must be non-blank and no longer than
* [LivechatWidgetApi.MESSAGE_MAX_LENGTH] characters, if present.
* @property attachment An optional attachment associated with the message. Must be valid if provided.
*
* @throws IllegalArgumentException If both [message] and [attachment] are null,
* if [message] is blank or too long, or if [attachment] is invalid.
*/
data class Basic @Throws(IllegalArgumentException::class) @JvmOverloads constructor(
val message: String?,
override val attachment: InAppChatMobileAttachment? = null,
) : MessagePayload(LivechatWidgetMessageType.BASIC)
/**
* Represents a message containing structured custom data related to the conversation.
*
* This type of message can optionally include contextual text from the agent and/or the user.
*
* @property customData A JSON string representing the custom data payload. Must be a valid JSON object.
* @property agentMessage An optional message visible only to the agent providing context for the custom data.
* @property userMessage An optional message visible only to the user and agent related to the custom data.
*/
data class CustomData @JvmOverloads constructor(
val customData: String,
val agentMessage: String? = null,
val userMessage: String? = null
) : MessagePayload(LivechatWidgetMessageType.CUSTOM_DATA)
}
If you face any issue using the InAppChat, specially on the first time integration, we encourage to try your Example application, as this may give you a hint of potential mistakes. An example of the most common issues our integrators face:
- The chat content appears blank, and the text input fields is disabled.
InAppChat should only be presented once it is activated using InAppChat.getInstance(context).activate()
and valid pushRegistrationId
is obtained. If you try to present it otherwise, the connection won't be established, and chat will be blank. There are also another reasons why InAppChat is not loaded, from incorrect/missing infobip_application_code
or Firebase setup, to badly defined Livechat widget in Infobip's web portal. Usually, the logs from Logcat will give you a hint of the issue, and re-checking this guide, or comparing with our Example application, should be enough to successfully integrate InAppChat. But if the issue continues, don't hesitate to contact our support or ask for help here in our repository's Issues section.
- My InAppChat is activated and I have
pushRegistrationId
, but the chat keeps appearing blank.
If your Livechat widget setup in Installation and Security tab has enabled Authenticate users on mobile using JSON Web Token, make sure you provided to InAppChat a correct JSON Web Token. If you enabled it by mistake, disable it.
- I get in the logs an error about no
pushRegistrationId
.
Please re-check the quick start guide and the steps mentioned above.
- When a chat push notification is tapped, the app is invoked, and remains wherever it previously was - but I want it to display the chat related to the push notification I tapped.
InAppChat cannot present itself: if needs the parent application (your app) to present it. So, when a push notification is tapped, your app needs to recognise that event, and present the chat if you wish so. You can detect when a push notification is tapped, its nature and content, by listening to our library-events. For this case, the event you are looking for is called NOTIFICATION_TAPPED
.