Azure Communication Chat Service client library for iOS

This package contains the Chat client library for Azure Communication Services.

Source code | API reference documentation | Product documentation

Getting started

Prerequisites

Install the library

To install the Azure client libraries for iOS, we recommend you use Swift Package Manager. As an alternative, you may also integrate the libraries using CocoaPods.

Add a package dependency with Swift Package Manager

The Swift Package Manager is a tool for managing the distribution of Swift code. It’s integrated with the Swift build system to automate the process of downloading, compiling, and linking dependencies.

Xcode comes with built-in support for Swift Package Manager and source control accounts and makes it easy to leverage available Swift packages. Use Xcode to manage the versions of package dependencies and make sure your project has the most up-to-date code changes.

Xcode

Important: AzureCommunicationChat currently does not support arm64 for iOS Simulator. If you are developing on M1 please run Xcode with Rosetta. See #787

To add the library to your application, follow the instructions in Adding Package Dependencies to Your App:

In order to independently version packages with Swift Package Manager, we mirror the code from azure-sdk-for-ios into separate repositories. Your Swift Package Manager-based app should target these repositories instead of the azure-sdk-for-ios repo.

With your project open in Xcode 11 or later, select File > Swift Packages > Add Package Dependency… Enter the clone URL of the Swift Package Manager mirror repository: https://github.com/Azure/SwiftPM-AzureCommunicationChat.git and click Next. For the version rule, specify the exact version or version range you wish to use with your application and click Next. Finally, place a checkmark next to the library, ensure your application target is selected in the Add to target dropdown, and click Finish.

Swift CLI

To add the library to your application, follow the example in Importing Dependencies:

Open your project’s Package.swift file and add a new package dependency to your project’s dependencies section, specifying the clone URL of this repository and the version specifier you wish to use:

// swift-tools-version:5.3
    dependencies: [
        ...
        .package(name: "AzureCommunicationChat", url: "https://github.com/Azure/SwiftPM-AzureCommunicationChat.git", from: "1.3.1")
    ],

Next, for each target that needs to use the library, add it to the target’s array of dependencies:

    targets: [
        ...
        .target(
            name: "MyTarget",
            dependencies: ["AzureCommunicationChat", ...])
    ]
)

Integrate the client libraries with CocoaPods

CocoaPods is a dependency manager for Objective C and Swift projects. You can install it with the following command:

$ [sudo] gem install cocoapods

CocoaPods 1.5+ is required.

To integrate one or more client libraries into your project using CocoaPods, specify them in your Podfile, providing the version specifier you wish to use. To ensure compatibility when using multiple client libraries in the same project, use the same version specifier for all Azure SDK client libraries within the project:

platform :ios, '13.0'

# Comment the next line if you don't want to use dynamic frameworks
use_frameworks!

target 'MyTarget' do
  pod 'AzureCommunicationChat', '1.3.1'
  ...
end

Key concepts

User and User Access Tokens

User access tokens enable you to build client applications that directly authenticate to Azure Communication Services. Refer here to learn how to create a user and issue a User Access Token.

The id for the user created above will be necessary later to add said user as a participant of a new chat thread. The initiator of the create request must be in the list of participants of the chat thread.

Chat Thread

A chat conversation is represented by a chat thread. Each user in the thread is called a thread participant. Thread participants can chat with one another privately in a 1:1 chat or huddle up in a 1:N group chat.

Using the APIs, users can also send typing indicators when typing a message and read receipts for the messages they have read in a chat thread. To learn more, read about chat concepts here.

ChatClient

ChatClient is used for performing chat thread operations, listed below.

Initialization

To instantiate a ChatClient you will need the CommunicationServices resource endpoint, a CommunicationTokenCredential created from a User Access Token, and optional options to create the client with.

import AzureCommunicationCommon
import AzureCommunicationChat
import AzureCore

let endpoint = "<communication_resource_endpoint>"

let credential = try CommunicationTokenCredential(<"user_access_token>")

let options = AzureCommunicationChatClientOptions(
    logger: ClientLoggers.default,
    dispatchQueue: self.queue
)

let chatClient = ChatClient(endpoint: endpoint, credential: credential, withOptions: options)

Thread Operations

ChatClient supports the following methods, see the links below for examples.

ChatThreadClient

ChatThreadClient provides methods for operations within a chat thread, such as messaging and managing participants.

Initialization

ChatThreadClients should be created through the ChatClient. A ChatThreadClient is associated with a specific chat thread and is used to perform operations within the thread. See the list below for examples of each operation that ChatThreadClient supports.

Message Operations

Thread Participant Operations

Events Operations

Thread Update Operations

Examples

Thread Operations

Create a thread

Use the create method of ChatClient to create a new thread.

Thread creation may result in partial errors, meaning the thread was successfully created but certain participants failed to be added. Participants that failed to be added will be listed as part of the response.

  • CreateChatThreadRequest is the model to pass to this method. It contains the topic of the thread as well as the optional participants to create the thread with.

  • CreateChatThreadResult is the result returned from creating a thread.

  • chatThread is the ChatThreadProperties of the thread that was created.

  • invalidParticipants is an array of errors for any participants that failed to be added to the thread.

let thread = CreateChatThreadRequest(
    topic: "General"
)

chatClient.create(thread: thread) { result, _ in
    switch result {
    case let .success(chatThreadResult):
        // Take further action

    case let .failure(error):
        // Display error message
    }
}

Get a threads properties

Use the getProperties method of ChatThreadClient to retrieve a threads properties.

  • ChatThreadProperties is the type that is returned. It contains information about the thread including the thread ID, the topic, when it was created or deleted, and who created it.
chatThreadClient.getProperties { result, _ in
    switch result {
    case let .success(chatThreadProperties):
        // Take further action

    case let .failure(error):
        // Display error message
    }
}

List threads

Use the listThreads method to retrieve a list of threads.

PagedCollection<ChatThreadItem> is the response returned from listing threads. ChatThreadItem represents a summary of information about the thread including the thread ID, topic, time of deletion, and time of last message received, as applicable.

import AzureCore
let options = ListChatThreadsOptions(maxPageSize: 1)
chatClient.listThreads(withOptions: options) { result, _ in
    switch result {
    case let .success(listThreadsResponse):
        var iterator = listThreadsResponse.syncIterator
        while let threadItem = iterator.next() {
            // Take further action
        }

    case let .failure(error):
        // Display error message
    }
}

Delete a thread

Use the delete method of ChatClient to delete a thread.

  • thread is the unique ID of the thread.
chatClient.delete(thread: threadId) { result, httpResponse in
    switch result {
    case .success:
        // Take further action

    case let .failure(error):
        // Display error message
    }
}

Message Operations

Send a message

Use the send method of ChatThreadClient to send a message to a thread.

  • SendChatMessageRequest is the model to pass to this method.
  • content, required, is used to provide the chat message content.
  • senderDisplayName is used to specify the display name of the sender, if not specified, an empty name will be set.
  • type is the type of message being sent, the supported types are text and html.
  • metadata is any additional metadata you would like to send with the message.

SendChatMessageResult is the response returned from sending a message, it contains the unique ID of the message.

let message = SendChatMessageRequest(
    content: "Test message 1",
    senderDisplayName: "An Important person"
)

chatThreadClient.send(message: message) { result, _ in
    switch result {
    case let .success(createMessageResponse):
        // Take further action

    case let .failure(error):
        // Display error message
    }
}

Get a message

Use the get method of ChatThreadClient to retrieve a message in a thread.

  • message is the unique ID of the message to retrieve.

ChatMessage is the response returned from getting a message. This object contains information about the message type, content, sender, the sequence of the message in the conversation, as well as information around when the message was created, deleted or edited.

chatThreadClient.get(message: messageId) { result, _ in
    switch result {
    case let .success(message):
        // Take further action

    case let .failure(error):
        // Display error message
    }
}

List messages

Use the listMessages method of ChatThreadClient to retrieve messages in a thread.

<PagedCollection<ChatMessage> is the response returned from listing messages

let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ"

var options: ListChatMessagesOptions? = nil
if let date = dateFormatter.date(from: "2020-08-27T17:55:50Z") {
    options = ListChatMessagesOptions(
        startTime: date
    )
}

client.listMessages(withOptions: options) { result, _ in
    switch result {
    case let .success(listMessagesResponse):
        var iterator = listMessagesResponse.syncIterator
        while let message = iterator.next() {
            // Take further action
        }

    case let .failure(error):
        // Display error message
    }
}

Update a message

Use the update method of ChatThreadClient to update the content of a message.

  • message is the unique ID of the message.
  • parameters contains the message content to be updated.
let updatedContent = {
    content: "Updated message content"
}
chatThreadClient.update(message: messageId, parameters: updatedContent) { result, _ in
    switch result {
    case .success(_):
        // Take further action

    case let .failure(error):
        // Display error message
    }
}

Delete a message

Use the delete method of ChatThreadClient to delete a message in a thread.

  • message is the unique ID of the message.
chatThreadClient.delete(message: messageId) { result, _ in
    switch result {
    case .success:
        // Take further action

    case let .failure(error):
        // Display error message
    }
}

Receive messages from a thread

With realtime notifications enabled you can receive events when messages are sent to the thread. To enable realtime notifications use the startRealtimeNotifications method of ChatClient. Starting notifications is an asynhronous operation.

chatClient.startRealTimeNotifications() { result in
    switch result {
    case .success:
        // Notifications started
    case let.failure(error):
        // Handle failure
    }
}

To receive messages for a thread, use the register method of ChatClient.

func handler (response: Any, eventId: ChatEventId) {
    // Handle chatMessageReceived event
}

chatClient.register(event: ChatEventId.chatMessageReceived, handler: handler)

Thread Participant Operations

Get thread participants

Use the listParticipants of ChatThreadClient method to retrieve the participants of the thread.

PagedCollection<ChatParticipant> is the response returned from listing participants. ChatParticipant contains the identifier which holds the unique ACS user ID for this participant, as well as optional display name and share history time.

chatThreadClient.listParticipants() { result, _ in
    switch result {
    case let .success(threadParticipants):
        var iterator = threadParticipants.syncIterator
        while let threadParticipants = iterator.next() {
            // Take further action
        }

    case let .failure(error):
        // Display error message
    }
}

Add thread participants

Use the add method to add one or more participants to a thread.

  • participants is an array of ChatParticipant‘s to add
  • AddChatParticipantsResult is the model returned, it contains an invalidParticipants property that has an array of ChatErrors describing any participants that failed to be added to the chat.
let threadParticipants = [ChatParticipant(
        id: userIdentifier,
        displayName: "a new participant"
    )]

chatThreadClient.add(participants: threadParticipants) { result, _ in
    switch result {
    case let .success(result):
        // Check for invalid participants

    case let .failure(error):
        // Display error message
    }
}

Remove a thread participant

Use the remove method of ChatThreadClient to remove a participant from a thread.

  • participant is the identifier of the participant to remove.
chatThreadClient.remove(participant: participantIdentifier) { result, _ in
    switch result {
    case .success:
        // Take further action

    case let .failure(error):
        // Display error message
    }
}

Events Operations

Send a typing notification

Use the sendTypingNotification method of ChatThreadClient to post a typing notification event to a thread, on behalf of a user.

chatThreadClient.sendTypingNotification() { result, _ in
    switch result {
    case .success:
        // Take further action

    case let .failure(error):
        // Display error message
    }
}

Send read receipt

Use the sendReadReceipt method of ChatThreadClient to post a read receipt event to a thread, on behalf of a user.

-forMessage refers to the unique ID of the message that the read receipt is for.


chatThreadClient.sendReadReceipt(forMessage: messageId) { result, _ in
    switch result {
    case .success:
        // Take further action

    case let .failure(error):
        // Display error message
    }
}

Get read receipts

Use the listReadReceipts method of ChatThreadClient to retrieve read receipts for a thread.

PagedCollection<ChatMessageReadReceipt> is the response returned from listing read receipts. ChatMessageReadReceipt contains the sender of the read receipt, the id of the message that was read, and the time that the message was read.

chatThreadClient.listReadReceipts() { result, _ in
    switch result {
    case let .success(readReceipts):
        var iterator = readReceipts.syncIterator
        while let readReceipt = iterator.next() {
            // Take further action
        }

    case let .failure(error):
        // Display error message
    }
}

Thread Update Operations

Update the thread’s topic

Use the update method of ChatThreadClient to update a thread’s topic.

  • topic is the thread’s new topic.
let newTopic = "My new thread topic"

chatThreadClient.update(topic: newTopic) { result, _ in
    switch result {
    case .success:
        // Take further action

    case let .failure(error):
        // Display error message
    }
}

Troubleshooting

When an error occurs, the client calls the callback, passing in a failure result. You can use the provided error to act upon the failure.

client.create(thread: thread) { result, _ in
    switch result {
    case let .failure(error):
        // Display error message
    }
}

If you run into issues while using this library, please feel free to file an issue.

Next steps

More sample code should go here, along with links out to the appropriate example tests.

Contributing

This project welcomes contributions and suggestions. All code contributions should be made in the Azure SDK for iOS repository.

Most contributions require you to agree to a Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us the rights to use your contribution. For details, visit https://cla.microsoft.com.

When you submit a pull request, a CLA-bot will automatically determine whether you need to provide a CLA and decorate the PR appropriately (e.g., label, comment). Simply follow the instructions provided by the bot. You will only need to do this once across all repositories using our CLA.

This project has adopted the Microsoft Open Source Code of Conduct. For more information see the Code of Conduct FAQ or contact opencode@microsoft.com with any additional questions or comments.

Impressions