Quickstart: Add chat with UI Library

Get started with Azure Communication Services UI Library to quickly integrate communication experiences into your applications. In this quickstart, learn how to integrate UI Library chat composites into an application and set up the experience for your app users.

Communication Services UI Library renders a full chat experience right in your application. It takes care of connecting to Azure Communication Services chat services, and updates participant's presence automatically. As a developer, you need to worry about where in your app's user experience you want the chat experience to launch and only create the Azure Communication Services resources as required.

Note

For detailed documentation and quickstarts about the Web UI Library visit the Web UI Library Storybook.

Prerequisites

You can access the following quickstarts

Important

This feature of Azure Communication Services is currently in preview.

Preview APIs and SDKs are provided without a service-level agreement. We recommend that you don't use them for production workloads. Some features might not be supported, or they might have constrained capabilities.

For more information, review Supplemental Terms of Use for Microsoft Azure Previews.

Get the sample Android application for this quickstart in the open source Azure Communication Services UI Library for Android.

Prerequisites

Set up the project

Complete the following sections to set up the quickstart project.

Create a new Android project

In Android Studio, create a new project:

  1. In the File menu, select New > New Project.

  2. In New Project, select the Empty Activity project template.

    Screenshot that shows the New Project dialog in Android Studio with Empty Activity selected.

  3. Select Next.

  4. In Empty Activity, name the project UILibraryQuickStart. For language, select Java/Kotlin. For the minimum SDK, select API 23: Android 6.0 (Marshmallow) or later.

  5. Select Finish.

    Screenshot that shows new project options and the Finish button selected.

Install the packages

Complete the following sections to install the required application packages.

Add a dependency

In your app-level UILibraryQuickStart/app/build.gradle file (in the app folder), add the following dependency:

dependencies {
    ...
    implementation 'com.azure.android:azure-communication-ui-chat:+'
    ...
}

Add Maven repositories

The Azure package repository is required to integrate the library:

To add the repository:

  1. In your project Gradle scripts, ensure that the following repositories are added. For Android Studio (2020.*), repositories is in settings.gradle, under dependencyResolutionManagement(Gradle version 6.8 or greater). For earlier versions of Android Studio (4.*), repositories is in the project-level build.gradle, under allprojects{}.

    // dependencyResolutionManagement
    repositories {
        ...
        maven {
            url "https://pkgs.dev.azure.com/MicrosoftDeviceSDK/DuoSDK-Public/_packaging/Duo-SDK-Feed/maven/v1"
        }
        ...
    }
    
  2. Sync your project with the Gradle files. To sync the project, on the File menu, select Sync Project With Gradle Files.

Add a button to activity_main.xml

In the app/src/main/res/layout/activity_main.xml layout file, add the following code to create a button to start the composite:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/startButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Launch"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

Initialize the composite

To initialize the composite:

  1. Go to MainActivity.

  2. Add the following code to initialize your composite components for calling. Replace the string values for properties (kotlin) or functions (java) for endpoint, acsIdentity, displayName, accessToken and ThreadId. Replace endpoint with the URL for your resource as provided by Azure Communication Services. Replace acsIdentity and accessToken with the values provided by Azure Communication Services when you created the access token and use a relevant displayName. Replace ThreadId with the value returned when you created the thread. Remember to add the user to the thread via REST API call, or the az command line interface client before you try to run the quick start sample or the client will be denied access to join the thread.

package com.example.uilibraryquickstart

import android.os.Bundle
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import com.azure.android.communication.common.CommunicationTokenCredential
import com.azure.android.communication.common.CommunicationTokenRefreshOptions
import com.azure.android.communication.common.CommunicationUserIdentifier
import com.azure.android.communication.ui.chat.ChatAdapter
import com.azure.android.communication.ui.chat.ChatAdapterBuilder
import com.azure.android.communication.ui.chat.presentation.ChatThreadView

class MainActivity : AppCompatActivity() {
    private lateinit var chatAdapter: ChatAdapter

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val startButton = findViewById<Button>(R.id.startButton)
        startButton.setOnClickListener { l: View? ->
            val communicationTokenRefreshOptions =
                CommunicationTokenRefreshOptions(
                    { accessToken }, true
                )
            val communicationTokenCredential =
                CommunicationTokenCredential(communicationTokenRefreshOptions)
            chatAdapter = ChatAdapterBuilder()
                .endpoint(endpoint)
                .credential(communicationTokenCredential)
                .identity(CommunicationUserIdentifier(acsIdentity))
                .displayName(displayName)
                .threadId(threadId)
                .build()
            try {
                chatAdapter.connect(this@MainActivity).get()
                val chatView: View = ChatThreadView(this@MainActivity, chatAdapter)
                addContentView(
                    chatView,
                    ViewGroup.LayoutParams(
                        ViewGroup.LayoutParams.MATCH_PARENT,
                        ViewGroup.LayoutParams.MATCH_PARENT
                    )
                )
            } catch (e: Exception) {
                var messageCause: String? = "Unknown error"
                if (e.cause != null && e.cause!!.message != null) {
                    messageCause = e.cause!!.message
                }
                showAlert(messageCause)
            }
        }
    }

    /**
     *
     * @return String endpoint URL from Azure Communication Services Admin UI, "https://example.domain.com/"
     */
    private val endpoint: String?
        get() = "https://example.domain.com/"

    /**
     *
     * @return String identity of the user joining the chat
     * Looks like "8:acs:a6aada1f-0b1e-47ac-866a-91aae00a1c01_00000015-45ee-bad7-0ea8-923e0d008a89"
     */
    private val acsIdentity: String?
        get() = ""

    /**
     *
     * @return String display name of the user joining the chat
     */
    private val displayName: String?
        get() = ""

    /**
     *
     * @return String secure Azure Communication Services access token for the current user
     */
    private val accessToken: String?
        get() = ""

    /**
     *
     * @return String id of Azure Communication Services chat thread to join
     * Looks like "19:AVNnEll25N4KoNtKolnUAhAMu8ntI_Ra03saj0Za0r01@thread.v2"
     */
    private val threadId: String?
        get() = ""

    fun showAlert(message: String?) {
        runOnUiThread {
            AlertDialog.Builder(this@MainActivity)
                .setMessage(message)
                .setTitle("Alert")
                .setPositiveButton(
                    "OK"
                ) { _, i -> }
                .show()
        }
    }
}

Run the code

In Android Studio, build and start the application:

  1. Select Start Experience.
  2. The chat client will join the chat thread and you can start typing and sending messages
  3. If the client is not able to join the thread, and you see chatJoin failed errors, verify that your user's access token is valid and that the user has been added to the chat thread by REST API call, or by using the az command line interface.

GIF animation that shows an example of how the project runs on an Android device.

Important

This feature of Azure Communication Services is currently in preview.

Preview APIs and SDKs are provided without a service-level agreement. We recommend that you don't use them for production workloads. Some features might not be supported, or they might have constrained capabilities.

For more information, review Supplemental Terms of Use for Microsoft Azure Previews.

Get the sample iOS application for this quickstart in the open source Azure Communication Services UI Library for iOS.

Prerequisites

Set up the project

Complete the following sections to set up the quickstart project.

Create a new Xcode project

In Xcode, create a new project:

  1. In the File menu, select New > Project.

  2. In Choose a template for your new project, select the iOS platform and select the App application template. The quickstart uses the UIKit storyboards.

    Screenshot that shows the Xcode new project dialog, with iOS and the App template selected.

  3. In Choose options for your new project, for the product name, enter UILibraryQuickStart. For the interface, select Storyboard. The quickstart doesn't create tests, so you can clear the Include Tests checkbox.

    Screenshot that shows setting new project options in Xcode.

Install the package and dependencies

  1. (Optional) For MacBook with M1, install and enable Rosetta in Xcode.

  2. In your project root directory, run pod init to create a Podfile. If you encounter an error, update CocoaPods to the current version.

  3. Add the following code to your Podfile. Replace UILibraryQuickStart with your project name.

    platform :ios, '14.0'
    
    target 'UILibraryQuickStart' do
        use_frameworks!
        pod 'AzureCommunicationUIChat', '1.0.0-beta.4'
    end
    
  4. Run pod install --repo-update.

  5. In Xcode, open the generated xcworkspace file.

Turn off Bitcode

In the Xcode project, under Build Settings, set the Enable Bitcode option to No. To find the setting, change the filter from Basic to All or use the search bar.

Screenshot that shows the Build Settings option to turn off Bitcode.

Initialize the composite

To initialize the composite:

  1. Go to ViewController.

  2. Add the following code to initialize your composite components for a chat. Replace <USER_ID> with user identifier. Replace <USER_ACCESS_TOKEN> with your access token. Replace <ENDPOINT_URL> with your endpoint URL. Replace <THREAD_ID> with your chat thread ID. Replace <DISPLAY_NAME> with your name. (The string length limit for <DISPLAY_NAME> is 256 characters).

    import UIKit
    import AzureCommunicationCommon
    import AzureCommunicationUIChat
    
    class ViewController: UIViewController {
        var chatAdapter: ChatAdapter?
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            let button = UIButton()
            button.contentEdgeInsets = UIEdgeInsets(top: 10.0, left: 20.0, bottom: 10.0, right: 20.0)
            button.layer.cornerRadius = 10
            button.backgroundColor = .systemBlue
            button.setTitle("Start Experience", for: .normal)
            button.addTarget(self, action: #selector(startChatComposite), for: .touchUpInside)
    
            button.translatesAutoresizingMaskIntoConstraints = false
            self.view.addSubview(button)
            button.widthAnchor.constraint(equalToConstant: 200).isActive = true
            button.heightAnchor.constraint(equalToConstant: 50).isActive = true
            button.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
            button.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
        }
    
        @objc private func startChatComposite() {
            let communicationIdentifier = CommunicationUserIdentifier("<USER_ID>")
            guard let communicationTokenCredential = try? CommunicationTokenCredential(
                token: "<USER_ACCESS_TOKEN>") else {
                return
            }
    
            self.chatAdapter = ChatAdapter(
                endpoint: "<ENDPOINT_URL>", identifier: communicationIdentifier,
                credential: communicationTokenCredential,
                threadId: "<THREAD_ID>",
                displayName: "<DISPLAY_NAME>")
    
            Task { @MainActor in
                guard let chatAdapter = self.chatAdapter else {
                    return
                }
                try await chatAdapter.connect()
                let chatCompositeViewController = ChatCompositeViewController(
                    with: chatAdapter)
    
                let closeItem = UIBarButtonItem(
                    barButtonSystemItem: .close,
                    target: nil,
                    action: #selector(self.onBackBtnPressed))
                chatCompositeViewController.title = "Chat"
                chatCompositeViewController.navigationItem.leftBarButtonItem = closeItem
    
                let navController = UINavigationController(rootViewController: chatCompositeViewController)
                navController.modalPresentationStyle = .fullScreen
    
                self.present(navController, animated: true, completion: nil)
            }
        }
    
        @objc func onBackBtnPressed() {
            self.dismiss(animated: true, completion: nil)
            Task { @MainActor in
                self.chatAdapter?.disconnect(completionHandler: { [weak self] result in
                    switch result {
                    case .success:
                        self?.chatAdapter = nil
                    case .failure(let error):
                        print("disconnect error \(error)")
                    }
                })
            }
        }
    }
    
    
  3. If you choose to put chat view in a frame that is smaller than the screen size, the recommended minimum width is 250 and the recommended minimum height is 300.

Run the code

To build and run your app on the iOS simulator, select Product > Run or use the (⌘-R) keyboard shortcut. Then, try out the chat experience on the simulator:

  1. Select Start Experience.
  2. The chat client will join the chat thread and you can start typing and sending messages.
  3. If the client isn't able to join the thread, and you see chatJoin failed errors, verify that your user's access token is valid and that the user has been added to the chat thread by REST API call, or by using the az command line interface.

GIF animation that demonstrates the final look and feel of the quickstart iOS app.

Clean up resources

If you want to clean up and remove a Communication Services subscription, you can delete the resource or resource group.

Deleting the resource group also deletes any other resources associated with it.

Learn more about cleaning up resources.