undefined

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.

Code samples

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

Connect to chat

[CYBChat.instance connectWithUserID:2746 password:@"password" completion:^(NSError * _Nullable error) {

}];
Chat.instance.connect(withUserID: 2746, password: "password") { (error) in

}

Use CYBChatDelegate to handle different connection states:

@interface YourClass () <CYBChatDelegate>

@end

@implementation YourClass

- (instancetype)init {
    self = [super init];
    if (self) {
        [CYBChat.instance addDelegate:self];
    }
    return self;
}

//MARK: CYBChatDelegate

- (void)chatDidConnect {
}

- (void)chatDidReconnect {
}

- (void)chatDidDisconnectWithError:(NSError *)error {
}

- (void)chatDidNotConnectWithError:(NSError *)error {
}

- (void)chatDidFailWithStreamError:(NSError *)error {
}
class YourClass : NSObject {

    override init() {
        super.init()
        Chat.instance.addDelegate(self)
    }
}

//MARK: ChatDelegate

extension YourClass : ChatDelegate {

    func chatDidConnect() {
    }

    func chatDidReconnect() {
    }

    func chatDidDisconnectWithError(_ error: Error) {
    }

    func chatDidNotConnectWithError(_ error: Error) {
    }
}

Disconnect

[CYBChat.instance disconnectWithCompletionBlock:^(NSError * _Nullable error) {

}];
Chat.instance.disconnect { (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:

CYBSettings.autoReconnectEnabled = NO;
Settings.autoReconnectEnabled = false

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.

@implementation AppDelegate
...
- (void)applicationWillTerminate:(UIApplication *)application {
    [CYBChat.instance disconnectWithCompletionBlock:^(NSError * _Nullable error) {
    }];
}

- (void)applicationDidEnterBackground:(UIApplication *)application {
    [CYBChat.instance disconnectWithCompletionBlock:^(NSError * _Nullable error) {
    }];
}

- (void)applicationWillEnterForeground:(UIApplication *)application {
    [CYBChat.instance connectWithUserID:2746 password:@"password" completion:^(NSError * _Nullable error) {
    }];
}
...
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
...
func applicationWillTerminate(_ application: UIApplication) {
    Chat.instance.disconnect { (error) in
    }
}

func applicationDidEnterBackground(_ application: UIApplication) {
    Chat.instance.disconnect { (error) in
    }
}

func applicationWillEnterForeground(_ application: UIApplication) {
    Chat.instance.connect(withUserID: 2746, password: "password") { (error) in
    }
}
...

Dialogs

All chats between users are organized in dialogs. The are 3 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.

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

CYBChatDialog *dialog = [[CYBChatDialog alloc] initWithDialogID:nil type:CYBChatDialogTypePrivate];
dialog.occupantIDs = @[@34]; // an ID of opponent

[CYBRequest createDialog:dialog successBlock:^(CYBChatDialog * _Nonnull dialog) {

} errorBlock:^(NSError * _Nonnull error) {

}];
let dialog = ChatDialog(dialogID: nil, type: .private)
dialog.occupantIDs = [34]  // an ID of opponent

Request.createDialog(dialog, successBlock: { (dialog) in

}) { (error) in

}

Create group chat

CYBChatDialog *dialog = [[CYBChatDialog alloc] initWithDialogID:nil type:CYBChatDialogTypeGroup];
dialog.name = @"Group dialog name";
dialog.occupantIDs = @[@34, @45, @55];
// dialog.photo = @"...";
// dialog.dialogDescription = @"...";

[CYBRequest createDialog:dialog successBlock:^(CYBChatDialog * _Nonnull dialog) {

} errorBlock:^(NSError * _Nonnull error) {

}];
let dialog = ChatDialog(dialogID: nil, type: .group)
dialog.name = "New group dialog"
dialog.occupantIDs = [34, 45, 55]
// dialog.photo = "...";
// dialog.dialogDescription = "...";

Request.createDialog(dialog, successBlock: { (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.

CYBChatDialog *dialog = [[CYBChatDialog alloc] initWithDialogID:nil type:CYBChatDialogTypePublic];
dialog.name = @"Public dialog name";
dialog.dialogDescription = @"Public dialog description";
// dialog.photo = @"...";

[CYBRequest createDialog:dialog successBlock:^(CYBChatDialog * _Nonnull dialog) {

} errorBlock:^(NSError * _Nonnull error) {

}];
let dialog = ChatDialog(dialogID: nil, type: .public)
dialog.name = "Public dialog name"
dialog.dialogDescription = "Public dialog description"
// dialog.photo = "...";

Request.createDialog(dialog, successBlock: { (dialog) in

}) { (error) in

}

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

[CYBRequest subscribeToPublicDialogWithID:@"5b8d30d1ca8bf43f8b9df3d9" successBlock:^{

} errorBlock:^(NSError *error) {

}];
Request.subscribeToPublicDialog(withID: "5b8d30d1ca8bf43f8b9df3d9", successBlock: {

}) { (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:

[CYBRequest ubsubscribeFromPublicDialogWithID:@"5b8d30d1ca8bf43f8b9df3d9" successBlock:^{

} errorBlock:^(NSError *error) {

}];
Request.ubsubscribeFromPublicDialog(withID: "5b8d30d1ca8bf43f8b9df3d9", successBlock: {

}) { (error) in

}

Retrieve list of dialogs

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

[CYBRequest dialogsWithPaginator:[CYBPaginator limit:50 skip:100]
                 extendedRequest:nil
                    successBlock:^(NSArray<CYBChatDialog *> * _Nonnull dialogs, NSSet<NSNumber *> * _Nonnull dialogsUsersIDs, CYBPaginator * _Nonnull paginator) {

                    } errorBlock:^(NSError * _Nonnull error) {

                    }];
Request.dialogs(with: Paginator.limit(50, skip: 100),
                extendedRequest: nil,
                successBlock: { (dialogs, usersIDs, paginator) in

}) { (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:

CYBUpdateChatDialogParameters *parameters = [[CYBUpdateChatDialogParameters alloc] init];
parameters.name = @"New dialog name";
parameters.dialogDescription = @"New dialog description";
parameters.photo = @"https://new_photo_url"; // or it can be an ID to some file in Storage module

[CYBRequest updateDialogWithID:@"5356c64ab35c12bd3b108a41" updateParameters:parameters successBlock:^(CYBChatDialog * _Nonnull dialog) {

} errorBlock:^(NSError * _Nonnull error) {

}];
let parameters = UpdateChatDialogParameters()
parameters.name = "New dialog name"
parameters.dialogDescription = "New dialog description"
parameters.photo = "https://new_photo_url" // or it can be an ID to some file in Storage module

Request.updateDialog(withID: "5356c64ab35c12bd3b108a41", update: parameters, successBlock: { (updatedDialog) in

}) { (error) in

}

Add/Remove occupants

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

CYBUpdateChatDialogParameters *parameters = [[CYBUpdateChatDialogParameters alloc] init];
parameters.occupantsIDsToAdd = @[@10056, @75432];
//parameters.occupantsIDsToRemove = @[@10023];

[CYBRequest updateDialogWithID:@"5356c64ab35c12bd3b108a41" updateParameters:parameters successBlock:^(CYBChatDialog *dialog) {

} errorBlock:^(NSError * _Nonnull error) {

}];
let updateParameters = UpdateChatDialogParameters()
updateParameters.occupantsIDsToAdd = [10056, 75432]
//updateParameters.occupantsIDsToRemove = [10023]

Request.updateDialog(withID: "5356c64ab35c12bd3b108a41", update: updateParameters, successBlock: { (updatedDialog) in

}) { (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:

[CYBRequest addAdminsToDialogWithID:@"5356c64ab35c12bd3b108a41" adminsUserIDs:@[@10056, @75432] successBlock:^{

} errorBlock:^(NSError * _Nonnull error) {

}];
Request.addAdminsToDialog(withID: "5356c64ab35c12bd3b108a41", adminsUserIDs: [10056, 75432], successBlock: {

}) { (error) in

}

and remove:

[CYBRequest removeAdminsFromDialogWithID:@"5356c64ab35c12bd3b108a41" adminsUserIDs:@[@75435] successBlock:^{

} errorBlock:^(NSError * _Nonnull error) {

}];
Request.removeAdminsFromDialog(withID: "5356c64ab35c12bd3b108a41", adminsUserIDs: [75435], successBlock: {

}) { (error) in

}

Pin messages

Pinning a message allows users to easily store messages which are important and have a quick access to them. The following code pins some messages to a particular group dialog:

CYBUpdateChatDialogParameters *parameters = [[CYBUpdateChatDialogParameters alloc] init];
parameters.pinnedMessagesIDsToAdd = @[@"5356c64ab35c12bd3b10ba32", @"5356c64ab35c12bd3b10wa65"];
//parameters.pinnedMessagesIDsToRemove = @[@"5356c64ab35c12bd3b10ba31", @"5356c64ab35c12bd3b10wa64"];

[CYBRequest updateDialogWithID:@"5356c64ab35c12bd3b108a41" updateParameters:parameters successBlock:^(CYBChatDialog * _Nonnull dialog) {

} errorBlock:^(NSError * _Nonnull error) {

}];
let updateParameters = UpdateChatDialogParameters()
updateParameters.pinnedMessagesIDsToAdd = ["5356c64ab35c12bd3b10ba32", "5356c64ab35c12bd3b10wa65"]
//updateParameters.pinnedMessagesIDsToRemove = ["5356c64ab35c12bd3b10ba31", "5356c64ab35c12bd3b10wa64"]
Request.updateDialog(withID: "5356c64ab35c12bd3b108a41", update: updateParameters, successBlock: { (updatedDialog) in

}) { (error) in

}

Remove dialog

[CYBRequest deleteDialogsWithIDs:[NSSet setWithArray:@[@"5356c64ab35c12bd3b108a41", @"d256c64ab35c12bd3b108bc5"]]
                     forAllUsers:NO
                    successBlock:^(NSArray<NSString *> * _Nonnull deletedObjectsIDs,
                                   NSArray<NSString *> * _Nonnull notFoundObjectsIDs,
                                   NSArray<NSString *> * _Nonnull wrongPermissionsObjectsIDs) {

                    } errorBlock:^(NSError * _Nonnull error) {

                    }];
Request.deleteDialogs(withIDs: Set<String>(["5356c64ab35c12bd3b108a41", "d256c64ab35c12bd3b108bc5"]),
                      forAllUsers: false,
                      successBlock: { (deletedObjectsIDs, notFoundObjectsIDs, wrongPermissionsObjectsIDs) in

}) { (error) in

}

This request will remove this conversation for current user, but other users still will be able to chat there. The forAllUsers 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:

[CYBRequest messagesWithDialogID:@"5356c64ab35c12bd3b108a41"
                 extendedRequest:@{@"date_sent[gt]" : @"1455098137"}
                       paginator:[CYBPaginator limit:20 skip:0]
                    successBlock:^(NSArray<CYBChatMessage *> * _Nonnull messages, CYBPaginator * _Nonnull paginator) {

                    } errorBlock:^(NSError * _Nonnull error) {

                    }];
Request .messages(withDialogID: "5356c64ab35c12bd3b108a41",
                  extendedRequest: ["date_sent[gt]":"1455098137"],
                  paginator: Paginator.limit(20, skip: 0),
                  successBlock: { (messages, paginator) in

}) { (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"};

Send/Receive chat messages

1-1 Chat

CYBChatMessage *message = [[CYBChatMessage alloc] init];
message.text = @"How are you today?";

CYBChatDialog *privateDialog = ...;
[privateDialog sendMessage:message completionBlock:^(NSError * _Nullable error) {

}];
let message = ChatMessage()
message.text = "How are you today?"

let privateDialog = ...
privateDialog.send(message) { (error) in

}

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.

CYBChatDialog *groupDialog = ...;
[groupDialog joinWithCompletionBlock:^(NSError * _Nullable error) {

}];
let groupDialog = ...
groupDialog.join { (error) in

}

Then you are able to send/receive messages:

CYBChatMessage *message = [[CYBChatMessage alloc] init];
message.text = @"How are you today?";

CYBChatDialog *groupDialog = ...;
[groupDialog sendMessage:message completionBlock:^(NSError * _Nullable error) {

}];

//MARK: CYBChatDelegate

- (void)chatDidReceiveMessage:(CYBChatMessage *)message {

}
let message = ChatMessage()
message.text = "How are you today?"

let groupDialog = ...
groupDialog.send(message) { (error) in

}

//MARK: ChatDelegate

func chatDidReceive(_ message: ChatMessage) {

}

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

CYBChatDialog *groupDialog = ...;
[groupDialog leaveWithCompletionBlock:^(NSError * _Nullable error) {

}];
let groupDialog = ...
groupDialog.leave { (error) in

}

'Sent' status

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

The completionBlock is used to track the status:

CYBChatDialog *chatDialog = ...;
[chatDialog sendMessage:message completionBlock:^(NSError * _Nullable error) {
    if(!error) {
        //Status - 'sent'
    }
}];
chatDialog.send(message) { (error) in
    if error == nil {
        //Status - 'sent'
    }
}

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

CYBChatMessage *message = [CYBChatMessage new];
message.markable = YES;
message.text = @"How are you today?";

[chatDialog sendMessage:message completionBlock:^(NSError * _Nullable error) {

}];
let message = ChatMessage()
message.markable = true
message.text = "How are you today?"

chatDialog.send(message) { (error) in

}

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

[CYBChat.instance markAsDelivered:message completion:^(NSError * _Nullable error) {

}];
Chat.instance.mark(asDelivered: message) { (error) in

}

and via REST

[CYBRequest markMessagesAsDelivered:[NSSet setWithArray:@[@"5b23aa4f5d0b0be0900041aa"]]
                           dialogID:@"5b23a9f38b518248d4fd7625"
                       successBlock:^{

} errorBlock:^(NSError * _Nonnull error) {

}];
Request.markMessages(asDelivered: Set<String>(["5b23aa4f5d0b0be0900041aa"]),
                     dialogID: "5b23a9f38b518248d4fd7625", successBlock: {

}) { (error) in

}

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

...
[CYBChat.instance addDelegate:self];
...

//MARK: CYBChatDelegate
- (void)chatDidDeliverMessageWithID:(NSString *)messageID dialogID:(NSString *)dialogID toUserID:(NSUInteger)userID {

}
...
Chat.instance.addDelegate(self)
...

//MARK: ChatDelegate
func chatDidDeliverMessage(withID messageID: String, dialogID: String, toUserID userID: UInt) {

}

'Read' status

Send 'read' status:

[CYBChat.instance readMessage:message completion:^(NSError * _Nullable error) {

}
Chat.instance.read(message) { (error) in

}

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

//MARK: CYBChatDelegate
- (void)chatDidReadMessageWithID:(NSString *)messageID dialogID:(NSString *)dialogID readerID:(NSUInteger)readerID {

}
//MARK: ChatDelegate
func chatDidReadMessage(withID messageID: String, dialogID: String, readerID: UInt) {

}

'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:

[chatDialog sendUserIsTyping];
chatDialog.sendUserIsTyping()

Send 'stop typing' status:

[chatDialog sendUserStoppedTyping];
chatDialog.sendUserStopTyping()

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

chatDialog.onUserIsTyping = ^(NSUInteger userID) {

};
chatDialog.onUserIsTyping = { (userID: UInt) in

}

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

chatDialog.onUserStoppedTyping = ^(NSUInteger userID) {

};
chatDialog.onUserStoppedTyping = { (userID: UInt) in

}

Edit Message

The following snippet is used to edit chat message:

CYBChatDialog *dialog = ...
[dialog editMessageWithID:@"5356c64ab35c12bd3b10wa64" text:@"New message text" last:YES completion:^(NSError * _Nullable error) {

}];

//MARK: CYBChatDelegate
- (void)chatDidReceiveMessage:(CYBChatMessage *)message {
    //Handle edited message
    if (message.edited) {
    }
}
let dialog = ...
dialog.editMessage(withID: "5356c64ab35c12bd3b10wa64", text: "New message text", last: true) { (error) in

}

//MARK: CYBChatDelegate
func chatDidReceive(_ message: ChatMessage) {
    //Handle edited message
    if (message.edited) {
    }
}

Delete chat messages

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

[CYBRequest deleteMessagesWithIDs:[NSSet setWithArray:@[@"5b23aa4f5d0b0be0900041aa", @"bc23aa4f5d0b0be0900041ad"]]
                      forAllUsers:NO
                     successBlock:^{

} errorBlock:^(NSError * _Nonnull error) {

}];
Request.deleteMessages(withIDs: Set(["5b23aa4f5d0b0be0900041aa", "bc23aa4f5d0b0be0900041ad"]),
                       forAllUsers: false,
                       successBlock: {

}) { (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:

CYBChatDialog *dialog = ...
[dialog removeMessageWithID:@"5356c64ab35c12bd3b10wa64" completion:^(NSError * _Nullable error) {

}];

//MARK: CYBChatDelegate
- (void)chatDidReceiveMessage:(CYBChatMessage *)message {
    //Handle removed message
    if (message.removed) {
    }
}
let dialog = ...
dialog.removeMessage(withID: "5356c64ab35c12bd3b10wa64") { (error) in

}

//MARK: CYBChatDelegate
func chatDidReceive(_ message: ChatMessage) {
    //Handle removed message
    if (message.removed) {
    }
}

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.

CYBChatMessage *message = [[CYBChatMessage alloc] init];
message.text = @"Self destroy message";
message.destroyAfterInterval = 10 // in seconds

CYBChatDialog *privateDialog = ...;
[privateDialog sendMessage:message completionBlock:^(NSError * _Nullable error) {

}];

//MARK: CYBChatDelegate
- (void)chatDidReceiveMessage:(CYBChatMessage *)message {
    //Handle destroyAfterInterval
    if (message.destroyAfterInterval > 0) {
        // setup a timer
    }
}
let message = ChatMessage()
message.text = "Self destroy message"
message.destroyAfterInterval = 10 // in seconds

let privateDialog = ...
privateDialog.send(message) { (error) in

}

//MARK: CYBChatDelegate
func chatDidReceive(_ message: ChatMessage) {
    //Handle destroyAfterInterval
    if (message.destroyAfterInterval > 0) {
        // setup a timer
    }
}

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 link to the file (file UID). Then you need to include this UID into chat message and send it.

NSURL *fileUrl = [NSURL fileURLWithPath:@"file_path"]; //Local file url
[CYBRequest uploadFileWithUrl:fileUrl fileName:@"image.png" contentType:@"image/png" isPublic:YES progressBlock:^(float progress) {
    //Update UI with upload progress
} successBlock:^(CYBBlob * _Nonnull blob) {
    //Create attachment
    CYBChatAttachment *attachment = [[CYBChatAttachment alloc] init];
    attachment.ID = blob.UID;
    attachment.type = @"image/png";
    attachment.url = blob.publicUrl;
    //Create message
    CYBChatMessage *message = [[CYBChatMessage alloc] init];
    message.text = @"Image attachment";
    //Set attachment
    message.attachments = @[attachment];
    //Send message with attachment
    [chatDialog sendMessage:message completionBlock:^(NSError * _Nullable error) {

    }];
} errorBlock:^(NSError * _Nonnull error) {

}];
let url = URL(fileURLWithPath:"file_path")

Request.uploadFile(with: url,
                   fileName: "image.png",
                   contentType: "image/png",
                   isPublic: true,
                   progressBlock: { (progress) in
                    //Update UI with upload progress
}, successBlock: { (blob) in
    let attachment = ChatAttachment()
    attachment.type = "image/png"
    attachment.url = blob.publicUrl()
    attachment.id = blob.uid
    //Create message
    let message = ChatMessage()
    message.text = "Image Attachment"
    //Set attachment
    message.attachments = [attachment]
    //Send message with attachment
    chatDialog.send(message, completionBlock: { (error) in

    })

}) { (error) 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 download the file from the cloud storage.

- (void)chatDidReceiveMessage:(CYBChatMessage *)message {
    [message.attachments enumerateObjectsUsingBlock:^(CYBChatAttachment * _Nonnull attachment, NSUInteger idx, BOOL * _Nonnull stop) {
        [CYBRequest downloadFileWithUID:attachment.ID progressBlock:^(float progress) {
            //Update UI with dowonload progress
        } successBlock:^(NSData * _Nonnull data) {
             //process file data
        } errorBlock:^(NSError * _Nonnull error) {

        }];
    }];
}
func chatDidReceive(_ message: ChatMessage) {
    if let attachment = message.attachments {
        attachment.forEach { (attachment) in
            if let uid = attachment.id {
                Request.downloadFile(withUID: uid, progressBlock: { (progress) in
                    //Update UI with dowonload progress
                }, successBlock: { (data) in
                    //process file data
                }, errorBlock: { (error) in

                })
            }
        }
    }
}

Contact

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

CYBChatAttachment *attachment = [[CYBChatAttachment alloc] init];

NSDictionary *contactData = @{@"phone" : @"180032323223", @"name": @"Samuel Johnson"};
NSData *contactJsonData = [NSJSONSerialization dataWithJSONObject:contactData options:NSJSONWritingPrettyPrinted error:nil];
NSString *contactString = [[NSString alloc] initWithData:contactJsonData encoding:NSUTF8StringEncoding];

attachment.data = contactString;

// attach a contact
CYBChatMessage *message = [[CYBChatMessage alloc] init];
message.text = @"Contact attachment";
message.attachments = @[attachment];

// send a chat message
// ...
let attachment = ChatAttachment()

let contactData = ["phone" : "180032323223", "name": "Samuel Johnson"]
if let theJSONData = try? JSONSerialization.data(withJSONObject: contactData, options: .prettyPrinted) {
    attachment.data = String(data: theJSONData, encoding: .utf8)
}

//Create message
let message = ChatMessage()
message.text = "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:

- (void)chatDidReceiveMessage:(CYBChatMessage *)message {
    [message.attachments enumerateObjectsUsingBlock:^(CYBChatAttachment * _Nonnull attachment, NSUInteger idx, BOOL * _Nonnull stop) {
        NSData *jsonData = [attachment.data dataUsingEncoding:NSUTF8StringEncoding];
        NSDictionary *contactData = [NSJSONSerialization JSONObjectWithData:jsonData options:kNilOptions error:nil];
        NSString *phone = contactData[@"phone"];
        NSString *name = contactData[@"name"];
    }];
}
func chatDidReceive(_ message: ChatMessage) {
    if let attachment = message.attachments {
        attachment.forEach { (attachment) in
            if let data = attachment.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:

[CYBRequest totalUnreadMessageCountForDialogsWithIDs:[NSSet setWithArray:@[@"8b23aa4f5d0b0be0900041aa", @"1c23aa4f5d0b0be0900041ad"]]
                                        successBlock:^(NSUInteger count, NSDictionary<NSString *,id> * _Nonnull dialogs) {

                                        } errorBlock:^(NSError * _Nonnull error) {

                                        }];
Request.totalUnreadMessageCountForDialogs(withIDs: Set(["8b23aa4f5d0b0be0900041aa","1c23aa4f5d0b0be0900041ad"]),
                                          successBlock: { (count, dialogs) in

}) { (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

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

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:

// array of accepted contacts
CYBChat.instance.contactList.contacts;

// array of pending requests
CYBChat.instance.contactList.pendingApproval;
// array of accepted contacts
let contacts = Chat.instance.contactList?.contacts

// array of pending requests
let pendingRequests = Chat.instance.contactList?.pendingApproval

Add user to your contact list

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

NSUInteger userID = 34;
[CYBChat.instance addUserToContactListRequest:userID
                                   completion:^(NSError * _Nullable error) {

}];
let userID: UInt = 34
Chat.instance.addUser(toContactListRequest: userID) { (error) in

}

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:


//MARK: CYBChatDelegate
- (void)chatDidReceiveContactAddRequestFromUser:(NSUInteger)userID {

}
//MARK: ChatDelegate
func chatDidReceiveContactAddRequest(fromUser userID: UInt) {

}

Confirm the contact request

To confirm the request use the following method:

[CYBChat.instance confirmAddContactRequest:userID completion:^(NSError * _Nullable error) {

}];
Chat.instance.confirmAddContactRequest(userID) { (error) in

}

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

//MARK: CYBChatDelegate
- (void)chatDidReceiveAcceptContactRequestFromUser:(NSUInteger)userID {

}
//MARK: ChatDelegate
func chatDidReceiveAcceptContactRequest(fromUser userID: UInt) {

}

Reject the contact request

To reject the request use the following method:

[CYBChat.instance rejectAddContactRequest:userID completion:^(NSError * _Nullable error) {

}];
Chat.instance.rejectAddContactRequest(userID) { (error) in

}

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

//MARK: CYBChatDelegate
- (void)chatDidReceiveRejectContactRequestFromUser:(NSUInteger)userID {

}
//MARK: ChatDelegate
func chatDidReceiveRejectContactRequest(fromUser userID: UInt) {

}

Remove user from the contact list

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

[CYBChat.instance removeUserFromContactList:34 completion:^(NSError * _Nullable error) {

}];
Chat.instance.removeUser(fromContactList: 34) { (error) in

}

Contact list updates

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

//MARK: CYBChatDelegate
- (void)chatContactListDidChange:(CYBContactList *)contactList {

}
//MARK: ChatDelegate
func chatContactListDidChange(_ contactList: ContactList) {

}

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

//MARK: CYBChatDelegate
- (void)chatDidReceiveContactItemActivity:(NSUInteger)userID isOnline:(BOOL)isOnline status:(NSString *)status {

}
//MARK: ChatDelegate
func chatDidReceiveContactItemActivity(_ userID: UInt, isOnline: Bool, status: String?) {

}

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.

NSUInteger userID = 34;

CYBPrivacyItem *privateChatPrivacyItem =
[[CYBPrivacyItem alloc] initWithPrivacyType:CYBPrivacyTypeUserID
                                     userID:userID
                                      allow:NO];
privateChatPrivacyItem.mutualBlock = YES;
CYBPrivacyItem *groupChatPrivacyItem =
[[CYBPrivacyItem alloc] initWithPrivacyType:CYBPrivacyTypeGroupUserID
                                     userID:userID
                                      allow:NO];
CYBPrivacyList *privacyList =
[[CYBPrivacyList alloc] initWithName:@"PrivacyList"
                               items:@[privateChatPrivacyItem,groupChatPrivacyItem]];
//Setting privacy list
[CYBChat.instance setPrivacyList:privacyList];
let userID: UInt = 34

let privateChatPrivacyItem = PrivacyItem.init(privacyType: .userID,
                                              userID: userID,
                                              allow: false)
privateChatPrivacyItem.mutualBlock = true

let groupChatPrivacyItem = PrivacyItem.init(privacyType: .groupUserID,
                                            userID: userID,
                                            allow: false)
let privacyList = PrivacyList.init(name: "PrivacyList",
                                   items: [privateChatPrivacyItem, groupChatPrivacyItem])
//Setting privacy list
Chat.instance.setPrivacyList(privacyList)

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

//MARK: CYBChatDelegate
- (void)chatDidSetPrivacyListWithName:(NSString *)name {

}
//MARK: ChatDelegate
func chatDidSetPrivacyList(withName name: String) {

}

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

//MARK: CYBChatDelegate
- (void)chatDidNotSetPrivacyListWithName:(NSString *)name error:(NSError *)error {

}
//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:

[CYBChat.instance setDefaultPrivacyListWithName:@"PrivacyList"];
Chat.instance.setDefaultPrivacyListWithName("PrivacyList")

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

//MARK: CYBChatDelegate
- (void)chatDidSetDefaultPrivacyListWithName:(NSString *)name {

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

}

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

//MARK: CYBChatDelegate
- (void)chatDidNotSetDefaultPrivacyListWithName:(NSString *)name error:(NSError *)error {

}
//MARK: ChatDelegate
func chatDidNotSetDefaultPrivacyList(withName name: String, error: Error) {

}

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.
//Deactivating privacy list before update
[CYBChat.instance setDefaultPrivacyListWithName:nil];
//Some updates here
//....
//Activating privacy list
[CYBChat.instance setDefaultPrivacyListWithName:@"PrivacyList"];
//Deactivating privacy list before update
Chat.instance.setDefaultPrivacyListWithName(nil)
//Some updates here
//....
//Activating privacy list
Chat.instance.setDefaultPrivacyListWithName("PrivacyList")

Retrieve privacy list names

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

[CYBChat.instance retrievePrivacyListNames];
Chat.instance.retrievePrivacyListNames()

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

- (void)chatDidReceivePrivacyListNames:(NSArray<NSString *> *)listNames {

}
func chatDidReceivePrivacyListNames(_ listNames: [String]) {

}

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

- (void)chatDidNotReceivePrivacyListNamesDueToError:(NSError *)error {

}
func chatDidNotReceivePrivacyListNamesDue(toError error: Error) {

}

Retrieve privacy list with name

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

[CYBChat.instance retrievePrivacyListWithName:@"PrivacyList"];
Chat.instance.retrievePrivacyList(withName: "PrivacyList")

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

- (void)chatDidReceivePrivacyList:(CYBPrivacyList *)privacyList {

}
func chatDidReceive(_ privacyList: PrivacyList) {

}

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

- (void)chatDidNotReceivePrivacyListWithName:(NSString *)name
                                       error:(NSError *)error {

}
func chatDidNotReceivePrivacyList(withName name: String, error: Error) {

}

Remove privacy list

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

[CYBChat.instance removePrivacyListWithName:@"PrivacyList"];
Chat.instance.removePrivacyList(withName: "PrivacyList")

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

- (void)chatDidRemovedPrivacyListWithName:(NSString *)name {

}
func chatDidRemovedPrivacyList(withName name: String) {

}

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:

chatDialog.onBlockedMessage = ^(NSError * _Nullable error) {

};
chatDialog.onBlockedMessage = { (error) in

}