Skip to content

In‐app chat

Francisco Fortes edited this page Nov 12, 2024 · 27 revisions

Find more info about Live chat product on Infobip docs.

Prerequisites

InAppChat is the mobile component for connecting and interacting with Infobip's LiveChat product. Built on top of Mobile Messaging SDK, InAppChat requires from you a careful setup, both in your mobile app and in Infobip's portal. The following steps must be prepared in order to ensure the chat communication:

Step 1:

You must include and setup the Mobile Messaging SDK in your application. If you haven't already, please follow its quick start guide carefully. Only by being able to receive a pushRegistrationId in your device (it is a good idea to enable and check the console debug logs for its response), you'll be able to successfully connect to InAppChat in the next steps.

Step 2:

You need to create a LiveChat Widget, and assign to it the exact same mobile push profile you defined in Step1. Because Mobile Messaging uses different Push Certificates for sandbox (debug) and production (testflight/app store), InAppChat also has this distinction. Make sure to follow the correct setup: a sandbox certificates will work while debugging the SDK/InAppchat, while a production one needs to be use for the Apple Store.

Step 3:

Notice

If you'd like to use Swift Package Manager, check Integration via Swift Package Manager guide

Now you can add InAppChat as a dependency into your iOS app, just by adding the following line in your Podfile:

pod 'MobileMessaging/InAppChat'

and indicating you want to use it by adding withInAppChat() to the MobileMessaging initialization chain:

MobileMessaging
	.withApplicationCode(<# your application code #>, notificationType: <# your notifications types preferences #>)?
	.withInAppChat() // this line prepares In-app chat service to start
	.start()

Display In-app chat view

Mobile Messaging In-app chat SDK provides a built-in chat view which you can quickly embed into your own application. Key component to use is MMChatViewController. We support two ways of using it:

  • via Interface Builder: set "MMChatViewController" as Custom class name for your view controller object.
  • programmatically: by presenting the appropriate chat view controller instance from an arbitrary parent view controller, for example:

If you want it to be with top bar, it will have dismiss(x) button:

if let rootVC = UIApplication.shared.keyWindow?.rootViewController {
	let chatVC = MMChatViewController.makeRootNavigationViewController()
	rootVC.present(chatVC, animated: true)
}

or, if you have navigation controller, you can push chat view controller to it, navigation bar will have back button.

let vc = MMChatViewController.makeChildNavigationViewController()
navigationController?.pushViewController(vc, animated: true)

or, if you want view controller to be presented modally, it will be without top bar.

if let rootVC = UIApplication.shared.keyWindow?.rootViewController {
	let chatVC = MMChatViewController.makeModalViewController()
	rootVC.present(chatVC, animated: true)
}

Note on SwiftUI

If your app is based on SwiftUI, there are a couple of UIKit-based modifications you may want to opt out of before presenting the chat.

The first one is the NavigationBar appearance overwrite that our SDK applies automatically based on the main colour of your LiveChat widget. If after presenting the chat, you experience an unwanted navigation bar style across your app, you can stop this behaviour by setting the following variable to false after the SDK initialization:

    MMChatSettings.sharedInstance.shouldSetNavBarAppearance = false

The second change you may need to make is related to the automatic resizing of UIKit frames when keyboard appears and disappears. On SwiftUI, the logic for resizing due to keyboard events is different and you may end up with wrong frames as a result. To disable the changes on our end, set the following variable to false after the SDK initialization:

    MMChatSettings.sharedInstance.shouldHandleKeyboardAppearance = false

The third change should be applied if you want to define your chat input in SwiftUI (meaning, you only want the message list from SDK). In order to do so, just set the following to true:

	MMChatSettings.sharedInstance.shouldUseExternalChatInput = true

Alternatively, if you need a deeper control on the chatInput's view and chatMessages's view frames, you can find them in MMChatViewController's messagesViewFrame and chatInputViewFrame. The ChatExample project provides you an example on how to integrate on SwiftUI.

Customer's Chat History

When your app is installed, it is assigned a set of ids for receiving push notifications and connecting to LiveChat. And also a "person" entity is created on Infobip side, automatically, and mostly empty, for that installation.

While having an anonymous customer/person fits some use cases, most likely you have an authenticated customer you can/want to identify (for example by his/her email, phone number, or some other unique id). Fortunately, you can use the Personalize feature of Mobile messaging to not only to link your customer to your app installation, but also for recovering the chat history of that customer.

Once your app has received the push registration, personalize your customer and, next time the chat is shown, previously sent messages will be presented, recovering the open conversation.

There is also option to depersonalize, that reverts the customer to its original, anonymous state, emptying the chat history. This is a common/suggested practice in log-out flows.

Customize In-app chat view

InAppChat offer three levels of customisation, all of them optional, each level allowing more freedom (thus being more complex as result).

The first level is defined as "General Chat Settings", and consist of values that are shared with the chat web widget, but also can be modified in runtime through code. The way to access this general chat settings, and customising the basics of the chat appearance, is through the instance: MMChatSettings.settings, and consists of the following variables:

  • title (String) - title for navigation bar when using NavigationViewController
  • sendButtonTintColor (UIColor) - tint color for Send button
  • navBarItemsTintColor (UIColor) - tint color of navigation bar items when using NavigationViewController
  • navBarColor (UIColor) - color of navigation bar when using NavigationViewController
  • navBarTitleColor (UIColor) - color of title of navigation bar when using NavigationViewController

The second level is defined as "Advanced Chat Settings". It allows you to modify anything from our UI classes, with the implication of extra effort in terms of testing and design in your end. You can access the long list of exposed variables through the instance MMChatSettings.settings.advancedSettings, which includes all fonts, icons, frames and colours our chat compose bar uses. In the ChatExample project, included within the SDK, you can see its capabilities (search for setCustomSettings)

The third level is defined as "Custom Chat Replacement". It allows you to completely exclude the compose bar we offer for interacting with the chat, and use your own input instead. There are two possible ways to achieve this: simply create the MMChatViewController() and handle the input yourself, or follow the list of requirements below:

  1. Create your custom view implementing our MMChatComposer protocol.
  2. Use the MMComposeBarDelegate methods to interact with the chat.
  3. Inject your view in our chat view controller before it is loaded (for example, with the provided initialiser MMChatViewController.makeCustomViewController(with: yourCustomInputView).

In the ChatExample project, included within the SDK, you can see its capabilities (search for showReplacedChatInNavigation)

Note: If you want a full control on frames (i.e., due to keyboard events) and navigation bar styles, check the Note on SwiftUI section above.

Themes for messages

In a similar manner as you can customize in-app chat input view, navigation, etc., you can customise the appearance of the messages themselves by using "Themes". These themes are defined on the widget setup (so it applies to web, not only mobile), and the use is rather simple:

  1. Define the name and values of your theme(s) in a css, under widget theme's Advance Customisation, in web portal.
  2. Once you know the names of your themes, you can just call the setWidgetTheme("your_theme_name") method in runtime, and the customisation will automatically be applied.
let vc = MMChatViewController.makeModalViewController()
// This will allow you to change the widget theme in real time
vc.setWidgetTheme("your_theme_name") { error in
    print(">>>>Theme changed with: " + (error?.localizedDescription ?? "Success"))
}
// If you want to define the widget theme early, before having any view controller available, this will set the theme upon initialising the chat:
// MMChatSettings.settings.widgetTheme = "your_theme_name"

In the ChatExample project, included within the SDK, you can see how different settings are defined, and are dynamically applied, by searching for onChangeColorTheme.

Dark settings and auto-reversing of messages colours - (Deprecated)

The correct way to deal with dark and light mode is to modify the settings and the themes in run-time, as explained in previous section. This means, you are responsible for checking the system dark or auto modes, and apply the desired colours in your implementation. The old way of dealing with dark settings and auto-reversing of colours is now deprecated, and its use is not recommended. This affects the following properties, that will be removed in a future release:

  1. MMChatSettings.darkSettings
  2. MMChatSettings.colorTheme

Handle notification taps

You can retrieve the message details in such special scenario as user tapping on the notification alert/banner:

  1. Implement MMMessageHandlingDelegate protocol and it's method didPerform(action:forMessage:completion:):
class MyMessageHandlingDelegate : MMMessageHandlingDelegate {
    func didPerform(action: MMNotificationAction, forMessage message: MM_MTMessage?, notificationUserInfo: [String: Any]?, completion: @escaping () -> Void) {
    	// this way you may distinguish chat message from regular flow/broadcast push message:
        if message.isChatMessage { 
	    print("Chat message with text: \(message.text) was tapped")
	    <# your custom handling here #>
	}
        // don't forget to call `completion`, it's very important to tell the system that action handling is finished
        completion()
    }
}
  1. Pass the delegate object to MobileMessaging SDK:
MobileMessaging.messageHandlindDelegate = MyMessageHandlingDelegate()

Library events

Mobile Messaging SDK supports MMNotificationInAppChatAvailabilityUpdated event - Library-events, which is posted after the in-app chat availability status received from backend server. The userInfo dictionary contains the following key: MMNotificationKeyInAppChatEnabled - contains boolean value.

Additionally, and only in case you need to process the message content separately (for example, for doing text-to-speech), you can access the raw message data using the following callback:

public var onRawMessageReceived: ((Any) -> Void)?

Usage example (the callback must be initialized before InAppChat is loaded):

MobileMessaging.inAppChat?.onRawMessageReceived = { rawMessage in
    // You can use raw message for further processing on your side
}

Sending attachments

Starting from 8.1.0 SDK version, we added sending attachments feature. In order to be able to choose attachment, you application need to be able to open photo library to choose the file or use camera and microphone to capture photo and video. By the Apple policies you will need to add following keys with text descriptions to your App's Info.plist file:

  • NSPhotoLibraryUsageDescription
  • NSCameraUsageDescription
  • NSMicrophoneUsageDescription

To enable document picker, you will need to turn on the iCloud Documents capabilities in Xcode.

iCloud Capabilities

Attachments preview

Starting from 8.3.0 SDK version, we added attachments preview feature. Supported file types are Images, Videos and PDFs.

In order to be able to save attachment to photo library, by the Apple policies you will need to add following key with text description to your App's Info.plist file:

  • NSPhotoLibraryAddUsageDescription

Supported attachment types

Media type File size File format
image 10MB JPG, JPEG, PNG
audio 10MB M4A
video 10MB MP4
document 10MB PDF

Unread chat push messages counter

Starting from version 9.2, new API is available to get and reset current unread chat push messages counter. The counter increments each time the application receives chat push message (this usually happens when chat screen is inactive or the application is in background/terminated state). In order to get current counter value use following API:

if let count = MobileMessaging.inAppChat?.getMessageCounter {
//use the count the way that suits you
}

MobileMessaging SDK automatically resets the counter to 0 whenever user opens the chat screen. However, use the following API in case you need to manually reset the counter:

MobileMessaging.inAppChat?.resetMessageCounter()

You can setup an MMInAppChatDelegate in order to get updates of the counter in runtime, for example:

import MobileMessaging

class MyViewController: UIViewController, MMInAppChatDelegate {
    override func viewDidLoad() {
        super.viewDidLoad()
        MobileMessaging.inAppChat?.delegate = self
    }
    //...
    func didUpdateUnreadMessagesCounter(_ count: Int) {
        //use the count the way that suits you
    }
}

Changing localization

The predefined messages prompted within the In-app chat (such as status updates, button titles, input field prompt) by default are localized using the system locale settings, but you can easily change the language any time you need.

For example, before showing the chat view controller, you can provide your locale string, and it wil be used the next time chat is presented:

// These are all valid formats for "Spanish" locale
MobileMessaging.inAppChat?.setLanguage("es_ES")
MobileMessaging.inAppChat?.setLanguage("es-ES")
MobileMessaging.inAppChat?.setLanguage("es")

And if you have the chat presented and loaded, you can change the language directly into it in real time (using the predefined MMLanguage's values):

Notice

Localization in chat happens only within the app, not outside. This means, your push notification content won't be translated in real time: push notification will only reflect the default language of your Livechat widget, as defined in Infobip web portal. But there is a solution: you can entirely customise the title and body of the push notifications, including applying localizations, by using a Notification Service Extension as explained here.

let vc = MMChatViewController.makeModalViewController()
// chat is presented, loaded, and you need to change its language
vc.setLanguage(.es) { error in
// if error is nil, all went as expected or chat is not presented yet
}

Sending Contextual Data

It is possible to send contextual data / metadata to Infobip’s Conversations via In-App Chat SDK. The data can be send any time, several times, with only one restriction: the chat must be already loaded and presented, and the communication should have started (meaning, there are messages visible and not the initial “Start the chat” button). The data sent will be automatically linked to the conversationId and accountId internally.

There are two parameters:

  1. The mandatory data, sent as string, in the format of Javascript objects and values (for guidance, it must be accepted by JSON.stringify())
  2. And optionally, a multithread strategy that can be left empty, and will use ACTIVE as default. Possible values are: metadata sent to "ACTIVE" conversation for the widget, or "ALL" non closed conversations for the widget.

Usage:

// Having created your MMChatViewController instance
let vc = MMChatViewController(type: .back)
// Present and wait till the chat is loaded and ready, then simply call
vc.sendContextualData("{name: 'Robert'}") { error in ... }

Sending Contextual Data without presenting chat

It is possible to send contextual data without presenting or starting the chat. The method can be invoked many times, but only the last data will be stored in the conversation (the contextual data is always overwritten).

There are two possible scenarios:

  1. 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.
  2. 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 or ALL conversations.

Multi-thread strategy

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.)

In-app chat SDK function to send contextual data has two parameters:

  1. The mandatory data, sent as string, in a format of JavaScript objects and values.
  2. An optional parameter, a multithread strategy that can be omitted and will use ACTIVE as a default value. Possible values are:
  • ALL metadata sent to all non-closed conversations for a widget
  • ACTIVE metadata sent to active only conversation for a widget

Usage:

// Present and wait till the chat is loaded and ready, then simply call
MobileMessaging.inAppChat?.sendContextualData("{name: 'Robert'}");

// or with multithread flag
MobileMessaging.inAppChat?.sendContextualData("{name: Robert}", multiThreadStrategy: .ALL)

Multiple chat threads

Default LiveChat widget (name of the channel InAppChat uses) works with single chat threads: one customer can only have one single open conversation. But the LiveChat widget could be created, in Customer Portal, with support for multiple chat threads.

beSettingMT

When the setting above is enabled, the InAppChat UI will automatically offer in mobile:

  • A list (initially empty) of all the unsolved conversation threads the user has opened.
  • A button to "Start new chat" thread.
  • The capability to navigate to each specific chat thread upon tapping in them.
beSettingMT

Presenting and hiding the Chat Input on multi-thread widgets

If you are using the provided Chat Input offered by the SDK, the functionality for its presentation works out of the box: there is no need for you to take care of its hiding logic, as the SDK does it for you. But if you replaced our chat input with a view entirely of your own, you'll need to react to MMInAppChatDelegate's chatDidChange(to state: MMChatWebViewState) method (or the event MMNotificationInAppChatViewChanged). For example, hiding the chat input for any state that represents a "chatting unavailable" scenario, such as those containing "list", "loading" or "close" on its name. You can find further details in the definition of MMChatWebViewState.

Navigation Bar and Back Button on multi-thread widgets

When multiple threads functionality is enabled, the MMChatViewController may need to take control over the back button of the navigation bar to allow a return to the threads list. In other words: the chat view controller needs to replace the default back button and its logic if the internal state is "In Thread List". For this reason, it is recommended not to use InAppChat's multiple threads feature without a navigation bar (for example, when chat is presented as modal view) as the "return to thread list" would be impossible. Nevertheless, we allow to customise the style and intercept the actions of this back button, if you need so, as seen in the code below:

// Optional definition of a custom back button (but we recommend leaving the default one to handle the navigation for you)
let vc = MMChatViewController.makeRootNavigationViewController()
vc.initialLeftNavigationItem = UIBarButtonItem(image:style:target:action)

The chat will then decide to consume or propagate the 'action' added to the button based on the chat needs.

Authenticated chat

It is possible to authenticate an user before accesing the chat, given you have enabled this feature in the LiveChat widget. The authentication is accomplished by combining the SDK's Personalisation method with a JWT (JSON Web Token); a token that needs to be generated by your end (see instructions here). We recommend, due to the token expiration, that a new token is always generated and injected in the SDK before presenting the chat, each and every time.

The authentication will use a unique identifier for your user, that can be an email address, a phone number, or an external identifier. It is crucial for this identifier to be valid, and to match the identity defined in the Personalisation - there will be an authentication error otherwise.

The ChatExample provided within the Mobile Messaging SDK offers a functional interface for testing the authentication use case (you just need to set your own Ids, keys and secret keys for it to work). A simplified use would be as follows:

/*
1 - The customer authenticate in your system, and you recognise his/her unique identifier
2 - You call Personalise with this unique identifier (and optionally, with other attributes such as first name, second name, etc)
3 - Now you can display the chat as an authenticated user by doing the following:
*/
MobileMessaging.inAppChat?.jwt = jwt // freshly new generated token. See documentation linked above and/or ChatExample demo for more details
let vc = MMChatViewController.makeModalViewController() // Or your preferred presentation method/style. The chat will read the JWT automatically.
self.navigationController?.present(vc, animated: true, completion: nil)

Privacy Manifest

Apple requires from you to describe the reason for sharing your user's identity data. Before doing personalisation of your user with actual identity values (such as phone number, email address, name, etc.), remember to include the privacy category affected, as well as the purpose for the sharing, within your PrivacyInfo file, as described in the official documentation.

Chat and push notifications

In order to customise the content (title and text body) of the push notifications received for chat messages, you need to create a Notification Service Extension and apply your desired modifications as explained here.

It is important to note that InAppChat decides automatically when to display/receive push notifications for incoming messages events based on the following rules:

  • If Chat is not loaded/disconnected => Push notifications will be received
  • If your app is in the background or a device is locked regardless of its connection status => Push notifications will be received
  • If the app is in the foreground and chat is loaded/connected => Push notification will NOT be received

Given the fact that a chat could be loaded/connected but your app may have it hidden (e.g. behind another view) we provide you with the flexibility to control the logic above: You can still receive push notifications in the foreground with these methods: stopConnection and restartConnection. Usage example:

let vc = MMChatViewController.makeModalViewController() // Or your preferred presentation method/style
self.navigationController?.present(vc, animated: true, completion: nil)
// Hide the chat, e.g., by displaying a new modal on top of it
vc.stopConnection()
// Push notifications for new message events will start coming to the device
// When you detect that a chat is visible again to a user, you can reload the chat and stop push notifications by invoking: 
vc.restartConnection()

Also keep in mind that InAppChat cannot present itself: if needs the parent application (your app) to present it. So, when a push notification for a chat messages is tapped by the user, your app needs to recognise the 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 MMNotificationMessageTapped.

Chat badge count on app icon

Badge count logic (the count of unread messages, and its reset to zero), as a number seen in red, near your app's icon, needs to be adjusted to your app's needs, thus cannot be applied automatically by our SDK. In order to see the options and what's needed, please read the Notification Service Extension section and examples.

Troubleshooting

If you face any issue using the chat, specially on the first time integration, we encourage to try your application code/certificates in our ChatExample application, as this may give you a hint of potential mistakes. An example of the most common issues our integrators face:

  1. The chat content appears blank, and the text input fields is disabled.

Chat should only be presented once the MMInAppChatDelegate's inAppChatIsEnabled() method returns true. If you try to present it otherwise, the connection won't be establish, and chat will be disabled. There are many reasons for inAppChatIsEnabled() not returning true: from incorrect codes/ids in your setup, to badly defined livechat widget in Infobip's web portal. Usually, the console logs (if you enabled debug logs in our SDK) will give you a hint of the issue, and re-checking this guide, or comparing with our ChatExample, should be enough to successfully integrate InAppChat. But if the issue continues, don't exitate to contact our support or ask for help here in our repository's Issues section.

  1. I do receive inAppChatIsEnabled() as true, but the chat keeps appearing blank.

Please confirm, within the security and authentication (last) section of your widget setup (in Infobip's web portal), if "Mobile app customer authentication - Authenticate users on mobile using JSON Web Token" is enabled. If you enabled it by mistake, disable it. If you want to authenticate mobile users, make sure you are sending a correct JSON Web Token (otherwise, similar to the point #1, the chat will remain disabled).

  1. I get in the logs an error about no push registration id.

Please re-check the quick start guide and the steps mentioned above, specially the part about the difference between Sandbox and Production environments, and how they need different p12 files uploaded to Infobip's web portal for Apple push notification's to work.

  1. 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 MMNotificationMessageTapped.

Clone this wiki locally