Skip to content

Messaging

ConnectyCube Chat (messaging) API is built on top of Real-time(XMPP) protocol. In order to use it you need to setup real-time connection with ConnectyCube Chat server and use it to exchange data.

By default Real-time Chat works over secure TLS connection.

Get started with SDK

Follow the Getting Started guide on how to connect ConnectyCube SDK and start building your first app.

Code samples

There are ready-to-go FREE code samples to help you better understand how to integrate messaging capabilities in your apps:

  • TextChat code sample, Swift request

Connect to chat

let user = ConnectycubeUser()
user.id = 2746
user.password = "password"
ConnectyCube().chat.login(user: user, successCallback:{
}, errorCallback: { error in
}, resource: ConnectycubeSettings().chatDefaultResource)

Use CYBChatDelegate v1 or ConnectycubeConnectionListener v2 to handle different connection states:

class YourClass : NSObject {
override init() {
super.init()
ConnectyCube().chat.addConnectionListener(listener: self)
}
}
extension YourClass : ConnectycubeConnectionListener {
func onConnected() {
}
func onDisconnected() {
}
}

Connect to chat using custom authentication providers

In some cases we don’t have a user’s password, for example when login via:

  • Facebook
  • Twitter
  • Firebase phone authorization
  • Custom identity authentication
  • etc.

In such cases ConnectyCube API provides possibility to use ConnectyCube session token as a password for chat connection:

let user = ConnectycubeUser()
user.id = 2746
user.password = ConnectycubeSessionManager().getToken()
ConnectyCube().chat.login(user: user, successCallback:{
}, errorCallback: { error in
}, resource: ConnectycubeSettings().chatDefaultResource)

Disconnect

ConnectyCube().chat.logout(successCallback: {
}) { (error) in
}

Reconnection

SDK reconnects automatically when connection to Chat server is lost.

There is a way to disable it and then manage it manually:

//coming soon

Chat in background

As iOS doesn’t provide ‘true’ background mode, we can’t have a persistent Chat connection while iOS application is in the background.

The better way to handle chat offline messages correctly is to do: Chat disconnect when an app goes to background and do Chat connect when an app goes to the foreground.

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
...
func applicationWillTerminate(_ application: UIApplication) {
ConnectyCube().chat.logout(successCallback: {
})
}
func applicationDidEnterBackground(\_ application: UIApplication) {
ConnectyCube().chat.logout(successCallback: {
})
}
func applicationWillEnterForeground(\_ application: UIApplication) {
ConnectyCube().chat.login(user: user, successCallback:{
}, errorCallback: { error in
}, resource: ConnectycubeSettings().chatDefaultResource)
}

Dialogs

All chats between users are organized in dialogs. The are 4 types of chat dialogs:

  • 1-1 chat - a conversation between 2 users.
  • group chat - a conversation between specified list of users.
  • public group chat - an open conversation. Any user from your app can subscribe to it.
  • broadcast - chat where a message is sent to all users within application at once. All the users from the application are able to join this group. Broadcast dialogs can be created only via Admin panel.

You need to create a new dialog and then use it to chat with other users. You also can obtain a list of your existing dialogs.

Create new dialog

Create 1-1 chat

let dialog = ConnectycubeDialog()
dialog.type = ConnectycubeDialogType.companion.PRIVATE
dialog.occupantsIds = [34] // an ID of opponent
ConnectyCube().createDialog(connectycubeDialog: dialog, successCallback: {(dialog) in
}) { (error) in
}

Create group chat

let dialog = ConnectycubeDialog()
dialog.type = ConnectycubeDialogType.companion.GROUP
dialog.name = "New group dialog"
dialog.occupantsIds = [34, 45, 55]
//dialog.photo = "..."
//dialog.dialogDescription = "..."
ConnectyCube().createDialog(connectycubeDialog: dialog, successCallback: {(dialog) in
}) { (error) in
}

Create public chat

It’s possible to create a public chat, so any user from your application can subscribe to it.

let dialog = ConnectycubeDialog()
dialog.type = ConnectycubeDialogType.companion.PUBLIC
dialog.name = "Public dialog name"
dialog.dialogDescription = "Public dialog description"
//dialog.photo = "..."
ConnectyCube().createDialog(connectycubeDialog: dialog, successCallback: {(dialog) in
}) { (error) in
}

With public dialog ID any user can subscribe to the public dialog via the following code:

ConnectyCube().subscribeToDialog(dialogId: "5b8d30d1ca8bf43f8b9df3d9", successCallback: {(dialog) in
}) { (error) in
}

After dialog subscription, this dialog will be listed in retrieve dialogs request and you also will be able to chat in it.

You also can unsubscribe if you do not want to be in this public dialog anymore:

ConnectyCube().unsubscribeFromDialog(dialogId: "5b8d30d1ca8bf43f8b9df3d9", successCallback: {
}) { (error) in
}

Retrieve list of dialogs

It’s common to request all your conversations on every app login:

let params = ["limit": 50, "skip": 100]
ConnectyCube().getDialogs(params: params, successCallback: { result in
let dialogs: [ConnectycubeDialog] = result.items as! [ConnectycubeDialog]
}, errorCallback: { error in
})

It will return all your 1-1 dialogs, group dialog and also public dialogs your are subscribed to.

Update dialog’s name, description, photo

User can update group chat name, description, photo:

let paramsToUpdate = UpdateDialogParams()
paramsToUpdate.newName = "New dialog name"
paramsToUpdate.newDescription = "New dialog description"
paramsToUpdate.newPhoto = "https://new_photo_url" // or it can be an ID to some file in Storage module
let parameters = paramsToUpdate.getUpdateDialogParams() as! [String : Any]
ConnectyCube().updateDialog(dialogId: "5356c64ab35c12bd3b108a41", params: parameters, successCallback: { dialog in
}, errorCallback: { error in
})

Add/Remove occupants

You can add/remove occupants in group and public dialogs:

let paramsToUpdate = UpdateDialogParams()
paramsToUpdate.addOccupantIds = [10056, 75432]
//paramsToUpdate.deleteOccupantIds = [10023]
let parameters = paramsToUpdate.getUpdateDialogParams() as! [String : Any]
ConnectyCube().updateDialog(dialogId: "5356c64ab35c12bd3b108a41", params: parameters, successCallback: { dialog in
}, errorCallback: { error in
})

!> Important note: Only group chat owner and admins can remove other users from group chat.

Add/Remove admins

Admins it’s a special role in chats. They have the same permissions as a dialog’s creator except add/remove other admins and remove dialog.

Owner of the group chat dialog can add admins:

ConnectyCube().addRemoveAdmins(dialogId: "5356c64ab35c12bd3b108a41", toAddIds: [10056, 75432], toRemoveIds: nil, successCallback: { dialog in
}, errorCallback: { error in
})

and remove:

ConnectyCube().addRemoveAdmins(dialogId: "5356c64ab35c12bd3b108a41", toAddIds: nil, toRemoveIds: [75435], successCallback: { dialog in
}, errorCallback: { error in
})

Pin messages

Pinning a message allows group owner or chat admins to easily store messages which are important, so that all users in chat have a quick access to them. The following code pins some messages to a particular group dialog:

let paramsToUpdate = UpdateDialogParams()
paramsToUpdate.addPinnedMsgIds = ["5356c64ab35c12bd3b10ba32", "5356c64ab35c12bd3b10wa65"]
//paramsToUpdate.deletePinnedMsgIds = ["5356c64ab35c12bd3b10ba31", "5356c64ab35c12bd3b10wa64"]
let parameters = paramsToUpdate.getUpdateDialogParams() as! [String : Any]
ConnectyCube().updateDialog(dialogId: "5356c64ab35c12bd3b108a41", params: parameters, successCallback: { dialog in
}, errorCallback: { error in
})

Remove dialog

ConnectyCube().deleteDialogs(dialogsIds: ["5356c64ab35c12bd3b108a41", "d256c64ab35c12bd3b108bc5"], force: false, successCallback: {(result) in
}) { (error) in
}
//or
ConnectyCube().deleteDialog(dialogId: "5356c64ab35c12bd3b108a41", force: false, successCallback: {
}) { (error) in
}

This request will remove this conversation for current user, but other users still will be able to chat there. The forAllUsers or force parameter is used to completely remove the dialog. Only group chat owner can remove the group conversation for all users.

You can also delete multiple conversations in a single request.

Chat history

Every chat conversation stores its chat history which you can retrieve:

let params: GetMessagesParameters = GetMessagesParameters()
params.sorter = RequestSorter(fieldType: "1455098137", fieldName: "date_sent", sortType: "gt")
params.limit = 20
params.skip = 0
let parameters = params.getRequestParameters() as! [String : Any]
ConnectyCube().getMessages(dialogId: "5356c64ab35c12bd3b108a41", params: parameters, successCallback: { result in
let messages = result.items as! [ConnectycubeMessage]
}, errorCallback: { error in
})

!> Important note: All retrieved chat messages will be marked as read after the request. If you decide not to mark chat messages as read, then add the following parameter to your extendedRequest - @{@"mark_as_read" : @"0"}; or markAsRead = false

Send/Receive chat messages

1-1 Chat

let message = ConnectycubeMessage()
message.body = "How are you today?"
message.dialogId = "5356c64ab35c12bd3b108a41"
message.recipientId = 10056
ConnectyCube().chat.sendMessage(msg: message, successCallback: {
}) { (error) in
}
//MARK: ConnectycubeMessageListener
ConnectyCube().chat.addMessageListener(listener: self)
extension YourClass: ConnectycubeMessageListener {
func onMessage(message: ConnectycubeMessage) {
}
func onError(message: ConnectycubeMessage, ex: KotlinThrowable) {
}
}

Group/Public chat

Before you start chatting in a group/public conversation, you need to join it. When joined - you can send/receive messages in a real time.

//not supported, no need to join

Then you are able to send/receive messages:

let message = ConnectycubeMessage()
message.body = "How are you today?"
message.dialogId = "5356c64ab35c12bd3b108a41"
message.type = ConnectycubeMessageType.groupchat
ConnectyCube().chat.sendMessage(msg: message, successCallback: {
}) { (error) in
}
//MARK: ConnectycubeMessageListener
ConnectyCube().chat.addMessageListener(listener: self)
extension YourClass: ConnectycubeMessageListener {
func onMessage(message: ConnectycubeMessage) {
}
func onError(message: ConnectycubeMessage, ex: KotlinThrowable) {
}
}

When it’s done, you can leave the group conversation:

//not supported, no need to leave

‘Sent’ status

There is a ‘sent’ status to ensure that message is delivered to the server.

The completionBlock is used to track the status:

//MARK: ConnectycubeMessageSentListener
ConnectyCube().chat.addMessageSentListener(listener: self)
extension YourClass: ConnectycubeMessageSentListener {
func onMessageSent(message: ConnectycubeMessage) {
}
func onMessageSentFailed(message: ConnectycubeMessage) {
}
}

‘Delivered’ status

By default, SDK sends ‘delivered’ status automatically when the message is received by the recipient. This is controlled by message.markable parameter when you send a message.

let message = ConnectycubeMessage()
message.recipientId = 10056
message.markable = true
message.body = "How are you today?"
ConnectyCube().chat.sendMessage(msg: message, successCallback: {
}) { (error) in
}

If markable is false or omitted, you can send ‘delivered’ status manually via Chat:

ConnectyCube().chat.sendDeliveredStatus(msg: message, successCallback: {
}) { (error) in
}

and via REST

let updatedParams = UpdateMessageParameters()
updatedParams.delivered = true
ConnectyCube().updateMessage(messageId: "5b23aa4f5d0b0be0900041aa", dialogId: "5b23a9f38b518248d4fd7625", params: updatedParams.getRequestParameters(), successCallback: {
}) { (error) in
}

The following method of a delegate is used to track ‘delivered’ status:

//MARK: ConnectycubeMessageStatusListener
ConnectyCube().chat.addMessageStatusListener(listener: self)
extension YourClass: ConnectycubeMessageStatusListener {
func onMessageDelivered(messageId: String, dialogId: String, userId: Int32) {
}
func onMessageRead(messageId: String, dialogId: String, userId: Int32) {
}
}

‘Read’ status

Send ‘read’ status:

ConnectyCube().chat.sendReadStatus(msg: message, successCallback: {
}) { (error) in
}

The following method of a delegate is used to track ‘read’ status:

//MARK: ConnectycubeMessageStatusListener
ConnectyCube().chat.addMessageStatusListener(listener: self)
extension YourClass: ConnectycubeMessageStatusListener {
func onMessageDelivered(messageId: String, dialogId: String, userId: Int32) {
}
func onMessageRead(messageId: String, dialogId: String, userId: Int32) {
}
}

‘Is typing’ status

The following ‘typing’ notifications are supported:

  • typing: The user is composing a message. The user is actively interacting with a message input interface specific to this chat session (e.g., by typing in the input area of a chat controller)
  • stopped: The user had been composing but now has stopped. The user has been composing but has not interacted with the message input interface for a short period of time (e.g., 30 seconds)

Send ‘is typing’ status:

ConnectyCube().chat.sendIsTypingStatus(dialog: dialog)

Send ‘stop typing’ status:

ConnectyCube().chat.sendStopTypingStatus(dialog: dialog)

The following block (closure) is used to track ‘is typing’ status:

//MARK: ConnectycubeChatTypingListener
ConnectyCube().chat.addTypingStatusListener(listener: self)
extension YourClass: ConnectycubeChatTypingListener {
func onUserIsTyping(dialogId: String?, userId: Int32) {
}
func onUserStopTyping(dialogId: String?, userId: Int32) {
}
}

The following block (closure) is used to track ‘stopped typing’ status:

//MARK: ConnectycubeChatTypingListener
ConnectyCube().chat.addTypingStatusListener(listener: self)
extension YourClass: ConnectycubeChatTypingListener {
func onUserIsTyping(dialogId: String?, userId: Int32) {
}
func onUserStopTyping(dialogId: String?, userId: Int32) {
}
}

Edit Message

The following snippet is used to edit chat message:

//coming soon

Delete chat messages

The following snippet is used to remove chat message via REST:

ConnectyCube().deleteMessages(messagesIds: ["5b23aa4f5d0b0be0900041aa", "bc23aa4f5d0b0be0900041ad"], force: false, successCallback: {(result) in
}) { (error) in
}

This request will remove the messages from current user history only, without affecting the history of other users. The forAllUsers parameter is used to completely remove messages.

The following snippet is used to remove chat message in a real time:

//coming soon

Self-destroy message

Self-destroy messages is used if you want to implement some sort of Secret Chat where messages are visible only for some limited amount of time.

It’s your responsibility to setup a timer in your app and remove messages from the client side.

Self-destroy messages are not stored in server history.

//not supported

Attachments

Image/Video

Chat attachments are supported with the cloud storage API. In order to send a chat attachment you need to upload the file to ConnectyCube cloud storage and obtain a file UID. Then you need to include this UID into chat message and send it.

let imageFilePath = ""
ConnectyCube().uploadFile(filePath: imageFilePath, public: false, successCallback: {(cubeFile) in
// create a message
let message = ConnectycubeMessage()
message.saveToHistory = true
message.recipientId = 10056
// attach a photo
let attachment = ConnectycubeAttachment()
attachment.type = "photo"
attachment.id = String(cubeFile.id)
message.attachments?.add(attachment)
// send a chat message
ConnectyCube().chat.sendMessage(msg: message)
}, errorCallback: { (error) in
}, progress: { (progress) in
})

The same flow is supported on the receiver’s side. When you receive a message, you need to get the file UID and then you can build a file URL:

// ConnectycubeMessageListener
func onMessage(message: ConnectycubeMessage) {
if let attachment = message.attachments {
attachment.forEach { (attachment) in
if let uid = (attachment as! ConnectycubeAttachment).id {
let privateAvatarUrl = ConnectycubeFileKt.getPrivateUrlForUID(uid: uid)
}
}
}
}

Contact

A contact profile can be send via chat attachments as well:

let customData = ["phone" : "180032323223", "name" : "Samuel Johnson"]
if let theJSONData = try? JSONSerialization.data(withJSONObject: customData, options: .prettyPrinted) {
let data = String(data: theJSONData, encoding: .utf8)
let attachment = ConnectycubeAttachment()
attachment.data = data
//Create message
let message = ConnectycubeMessage()
message.body = "Contact Attachment"
message.attachments = [attachment]
// send a chat message
// ...
}

On the receiver’s side, when you receive a message, you need to get a contact data from an attachment:

// ConnectycubeMessageListener
func onMessage(message: ConnectycubeMessage) {
if let attachment = message.attachments {
attachment.forEach { (attachment) in
if let data = (attachment as! ConnectycubeAttachment).data?.data(using: .utf8) {
if let contactData = try? JSONSerialization.jsonObject(with: data, options: []) as! [String : String] {
let phone = contactData["phone"]
let name = contactData["name"]
}
}
}
}
}

Unread messages count

You can request total unread messages count and unread count for particular conversation:

ConnectyCube().getUnreadMessagesCount(dialogsIds: ["8b23aa4f5d0b0be0900041aa","1c23aa4f5d0b0be0900041ad"], successCallback: {(result) in
NSLog("total unread messages= " + result["8b23aa4f5d0b0be0900041aa"]!.description)
NSLog("total unread messages= " + result["1c23aa4f5d0b0be0900041ad"]!.description)
}) { (error) in
}

Global search feature was developed to simplify search of dialogs, messages and users at the same time. Similar functionality is used in most popular messengers and you can implement it in your app using Connectycube SDK. Just use request from snippet below. SearchRequestBuilder is optional parameter and it can be null if you don’t need additional configs for search request (only v2).

let searchText = "dialog name" // String or word. Should be longer than 4 symbols. Performs 'or' search.
// For an exact search, you need to wrap the search phrase in quotes.
let dialogIds = ["8b23aa4f5d0b0be0900041aa","1c23aa4f5d0b0be0900041ad"]
let searchParams: GlobalSearchParams = GlobalSearchParams() //class-helper to simple config search request
searchParams.dialogIds = dialogIds // List of dialog ids. Max cam include 10 items. Optional parameter.
// searchParams.startDate = startDate // Closest date to now. Uses lte comparison. Optional parameter.
// searchParams.endDate = endDate // Shouldn't differ by more than 3 months from the start_date. Uses gte comparison. Optional parameter.
searchParams.limit = 3 // Maximum number of items returned from the server in the search results. Max value - 100. Optional parameter.
ConnectyCube().searchText(searchText: searchText, params: searchParams.getSearchParams() as? [String : Any], successCallback: {(result) in
let dialogs = result.dialogs // found dialogs
let messages = result.messages // found messages
let users = result.users // found users
}) { (error) in
}

Chat alerts

When you send a chat message and the recipient/recipients is offline, then automatic push notification will be fired.

In order to receive push notifications you need to subscribe for it. Please refer to Push Notifications guide.

To configure push template which users receive - go to Dashboard Console, Chat Alerts page

Also, here is a way to avoid automatically sending push notifications to offline recipient/recipients. For it add the silent parameter with value 1 to the properties field of the instance of a ConnectycubeMessage.

let message = ConnectycubeMessage()
message.properties["silent"] = "1"

After sending such a message, the server won’t create the push notification for offline recipient/recipients.

!> Note that currently push notifications are supported on mobile environment only.

Chat notifications settings

Update notifications settings

A user can turn on/off push notifications for offline messages in a dialog. By default push notification are turned ON, so offline user receives push notifications for new messages in a chat.

let dialogId = "8b23aa4f5d0b0be0900041aa"
let enabled = false //false - to disable push notification, true - to enable
ConnectyCube().updateDialogNotificationsSettings(dialogId: dialogId, enable: enabled, successCallback: {(result) in
NSLog("notification is enabled= " + result.description)
}) { (error) in
}

Get notifications settings

Check a status of notifications setting - either it is ON or OFF for a particular chat.

ConnectyCube().getDialogNotificationsSettings(dialogId: "8b23aa4f5d0b0be0900041aa", successCallback: {(result) in
NSLog("notification is enabled= " + result.description)
}) { (error) in
}

Contact list

The Contact List API is rather straightforward. User A sends a request to become “friends” with user B. User B accepts the friend request. And now user A and B appear in each other’s roster.

Access to the Contact list

To access contact list you should use the contactList property of CYBChat class:

//not supported

Add user to your contact list

To add user to the contact list use the following method:

//not supported

Note

Maximum number of contacts is 300.

The CYBChat instance will call its delegate’s chatDidReceiveContactAddRequestFromUser: method and this user will receive the request to be added to the contact list:

//not supported

Confirm the contact request

To confirm the request use the following method:

//not supported

The CYBChat instance will call its delegate’s chatDidReceiveAcceptContactRequestFromUser: method and this user will be informed that you have accepted the contact request:

//not supported

Reject the contact request

To reject the request use the following method:

//not supported

The CYBChat instance will call its delegate’s chatDidReceiveRejectContactRequestFromUser: method and this user will be informed that you have declined the contact request:

//not supported

Remove user from the contact list

To remove a previously added user from the contact list use the following method:

//not supported

Contact list updates

You can also track contact list updates in real time by using delegates:

//not supported

The following method is called in case online status of a user from contact list has been changed:

//not supported

Privacy (black) list

Privacy list API allows enabling or disabling communication with other users in a chat. You can create, modify, or delete privacy lists, define a default list.

The user can have multiple privacy lists, but only one can be active.

Create privacy list

A privacy list must have at least one element in order to be created. If no elements specified, then the list with given name will be deleted.

//coming soon

If the privacy list is set successfully, the CYBChat instance will call its delegate’s chatDidSetPrivacyListWithName: method:

//coming soon

In case of error the CYBChat instance will call its delegate’s chatDidNotSetPrivacyListWithName:error: method:

//coming soon
//MARK: ChatDelegate
func chatDidNotSetPrivacyList(withName name: String, error: Error) {
}

In order to be used the privacy list should be not only set, but also activated(set as default).

Activate privacy list

In order to activate rules from a privacy list you should set it as default:

//coming soon
Chat.instance.setDefaultPrivacyListWithName("PrivacyList")

If the privacy list is activated (set as default) successfully, the CYBChat instance will call its delegate’s chatDidSetDefaultPrivacyListWithName: method:

//coming soon
//MARK: ChatDelegate
func chatDidSetDefaultPrivacyList(withName name: String) {
}

Otherwise the CYBChat instance will call its delegate’s chatDidNotSetDefaultPrivacyListWithName:error: method:

//coming soon

Update privacy list

There are some rules you should follow to update a privacy list:

  • Include all of the desired items (not a “delta”).
  • If you want to update or set new privacy list instead of current one, you should decline current default list first.
//coming soon

Retrieve privacy list names

To get a list of all your privacy lists’ names use the following request:

//coming soon

If the privacy list names are retrieved successfully, the CYBChat instance will call its delegate’s didReceivePrivacyListNames: method:

//coming soon

Otherwise the CYBChat instance will call its delegate’s didNotReceivePrivacyListNamesDueToError: method:

//coming soon

Retrieve privacy list with name

To get the privacy list by name you should use the following method:

//coming soon

If the privacy list is retrieved successfully, the CYBChat instance will call its delegate’s chatDidReceivePrivacyList: method:

//coming soon

Otherwise the CYBChat instance will call its delegate’s chatDidNotReceivePrivacyListWithName:error: method

//coming soon

Remove privacy list

To delete a list you can call a method below or you can edit a list and set items to nil.

//coming soon

If the privacy list is removed successfully, the CYBChat instance will call its delegate’s chatDidRemovedPrivacyListWithName: method

//coming soon

Blocked user attempts to communicate with user

Blocked users will be receiving an error when trying to chat with a user in a 1-1 chat and will be receiving nothing in a group chat:

//coming soon