Hyphenate Docs

Start Chatting with Hyphenate!

Welcome to the Hyphenate docs portal. Here you'll find comprehensive guides and technical documentation to help you integrate Hyphenate In-App Chat.

Get Started

Send and Receive Message

Add ChatManager delegate to receive callback

Receive callback methods like messagesDidDeliver: and messagesDidDeliver.

AppDelegate.m

@interface AppDelegate () <EMChatManagerDelegate>

@end

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    [self registerNotifications];
}

- (void)registerNotifications
{
    [self unregisterNotifications];
    [[EMClient sharedClient].chatManager addDelegate:self];
}

- (void)unregisterNotifications
{
    [[EMClient sharedClient].chatManager removeDelegate:self];
}

Send Message

ChatViewController.m

@interface ChatViewController() <EMChatManagerDelegate>

@end 

@implementation ChatViewController

- (void)viewDidLoad 
{
    [super viewDidLoad];
    [[EMClient sharedClient].chatManager addDelegate:self];
}

- (void)sendMessage
{
    EMTextMessageBody *messageBody = [[EMTextMessageBody alloc] initWithText:@"Hello Hyphenate!"];
    NSString *sender = [[EMClient sharedClient] currentUsername];
    NSString *receiver = @"hyphenate";

    EMMessage *message = [[EMMessage alloc] initWithConversationID:receiver
                                                              from:sender
                                                                to:receiver
                                                              body:messageBody
                                                               ext:nil];
    message.chatType = EMChatTypeChat; // chat type

    [[EMClient sharedClient].chatManager sendMessage:message progress:^(int progress) {
        NSLog(@"Progress: %d", progress);
    } completion:^(EMMessage *message, EMError *error) {
        if (error){
            NSLog(@"Send message failed");
        }
        else {
            NSLog(@"Message status: %d", message.status);
            NSLog(@"Send Message Success");
        }
    }];
}

- (void)messagesDidDeliver:(NSArray *)aMessages {
    NSLog(@"messages did deliver");
}

@end

Chat Type

message.chatType = EMChatTypeChat;      // one-to-one
message.chatType = EMChatTypeGroupChat; // group chat 
message.chatType = EMChatTypeChatRoom;  // chat room

Receive Messages

ChatViewController.m

@interface ChatViewController() <EMChatManagerDelegate>

@end 

@implementation ChatViewController

- (void)viewDidLoad 
{
    [super viewDidLoad];
    [[EMClient sharedClient].chatManager addDelegate:self];
}

- (void)messagesDidReceive:(NSArray *)aMessages
{
    NSLog(@"messages did receive");

    for (int i = 0; i < aMessages.count; i++) {
        EMMessage *message = aMessages[i];
        if ([message.from isEqualToString:@"fruitClub"] && message.chatType == EMChatTypeGroupChat) {
            EMTextMessageBody *body = (EMTextMessageBody *)message.body;
            NSLog(@"Conversation: %@ - text: %@", message.conversationId, body.text);
        }
    }
}

@end

Re-establish the long connection

If users re-enter the app, then call the method applicationWillEnterForeground: to re-establish the long connection in order to receive the message again.

- (void)applicationWillEnterForeground:(UIApplication *)application
{
    [[EMClient sharedClient] applicationWillEnterForeground:application];
}

Delegate methods

There're two different delegate methods,
- (void)messagesDidReceive:(NSArray *)aMessages
OR
- (void)cmdMessagesDidReceive:(NSArray *)aCmdMessages

Delegate methods will be triggered when new messages come in or you receive previously undelivered queued messages in an array format after the long connection established.

UI update

Call loadMessagesStartFromId or insert messages to the table (determined by message.timestamp to insert in proper order) after delegate messagesDidReceive or cmdMessagesDidReceive.

Send Message with Progress

- (void)sendMessage:(EMMessage *)aMessage
           progress:(void (^)(int progress))aProgressBlock
         completion:(void (^)(EMMessage *message, EMError *error))aCompletionBlock;

ChatViewController.m

@implementation ChatViewController

- (void)sendTextMessage:(NSString *)text
                     to:(NSString *)receiver
               progress:(void (^)(int progress))aProgressBlock
             completion:(void (^)(EMMessage *message, EMError *error))aCompletionBlock;
{
    EMTextMessageBody *messageBody = [[EMTextMessageBody alloc] initWithText:text];

    NSString *sender = [[EMClient sharedClient] currentUsername];
    EMMessage *message = [[EMMessage alloc] initWithConversationID:receiver from:sender to:receiver body:messageBody ext:nil];

    [[EMClient sharedClient].chatManager sendMessage:message progress:nil completion:^(EMMessage *message, EMError *error) {
        [self.tableView reloadData];
    }];
}

Message Sending Failure Handling

  • If there's no connection - the method will return message sending failure callback if the user is offline.
  • If Internet connection is unstable - SDK will continue trying for 30 sec and return failure if timeout, otherwise it will succeed.
  • Will NOT retry or resend automatically after callback, whether success or failure. In other words, once the callback returned message sending fails, then the developer has to manually trigger the method resendMessage or just sendMessage again to resend the the the message.

Message Attributes

EMMessage Object

+ (EMMessage *)initMessage:(NSString *)text
                        to:(NSString *)receiver
                  chatType:(EMChatType)chatType
                messageExt:(NSDictionary *)messageExt

{
    EMTextMessageBody *body = [[EMTextMessageBody alloc] initWithText:text];

    NSString *sender = [[EMClient sharedClient] currentUsername];
    EMMessage *message = [[EMMessage alloc] initWithConversationID:receiver
                                                              from:sender
                                                                to:receiver
                                                              body:body
                                                               ext:messageExt];
    message.chatType = chatType;

    return message;
}

Chat Type

The chat type is used to determine the handler of different type of chats: one-to-one, group, or chat room.

typedef enum{
    EMChatTypeChat   = 0,    // one-to-one  
    EMChatTypeGroupChat,     // group  
    EMChatTypeChatRoom,      // chat room
}EMChatType;

Message Type

EMTextMessageBody, EMCmdMessageBody, EMVoiceMessageBody, etc
Please see Rich Contents for various type of messages, e.g., text, image, audio message, file, command, etc.

Message Operations

Abstract class IEMChatManager contains many important messages and conversation operations. We recommend using the singleton [EMClient sharedClient].chatManager to call the instance methods.

Update a Message Locally

Update a message locally only, will not push the update to the the the server.

- (void)updateMessage:(EMMessage *)aMessage
           completion:(void (^)(EMMessage *aMessage, EMError *aError))aCompletionBlock;

Import Messages

Load message history to the local SDK database on the device manually.
During initialization, the SDK will load the last message from the database into caches for each conversation.

- (void)importMessages:(NSArray *)aMessages
            completion:(void (^)(EMError *aError))aCompletionBlock;

example

EMMessage *message1 = [[EMMessage alloc] initWithConversationID:receiver
                                                           from:sender
                                                             to:receiver
                                                           body:body
                                                            ext:messageExt];

[[EMClient sharedClient].chatManager importMessages:@[message1, message2] 
                                         completion:^(EMError *aError) {

}];

Conversations

The object conversation represents a container of related messages. i.e., conversations between two users, a group chat, or a chat room.

EMConversation serves as a container of EMMessage chat messages.

Conversation ID

  • For one-to-one chat, the ID of the user who sends the message to self is the conversationID. ex. User A received user B's message, then user B's username "B" will be used as conversationID.
  • The group ID is the conversation ID. Group ID can be obtained when creating a new group or fetch a list of groups.
  • The chat room ID is the conversation ID. Chat room ID can be obtained when creating a new chat room or fetch a list of chat rooms.

Insert a Message to Conversation

- (void)insertMessage:(EMMessage *)aMessage
                error:(EMError **)pError;

example

EMTextMessageBody *body = [[EMTextMessageBody alloc] initWithText:fulfillment[@"speech"]];

NSString *receiver = [[EMClient sharedClient] currentUsername];
NSString *sender = _conversation.conversationId;
EMMessage *messageFromBot = [[EMMessage alloc] initWithConversationID:sender
                                                                 from:sender
                                                                   to:receiver
                                                                 body:body
                                                                  ext:nil];

messageFromBot.chatType = [self _messageType];          // inherit message type
messageFromBot.status = EMMessageStatusSucceed;       // marked as delivered
messageFromBot.direction = EMMessageDirectionReceive;   // mark as sender or receiver, affect the side of the message bubble

[self.conversation insertMessage:messageFromBot error:nil];

EMMessageModel *model = [[EMMessageModel alloc] initWithMessage:messageFromBot];
[self.dataSource addObject:model];
[self.tableView reloadData];

Get All the Conversations

Get conversations locally, not from server.

NSArray *conversations = [[EMClient sharedClient].chatManager getAllConversations];
for (EMConversation *conversation in conversations) {
    NSLog(@"%@", conversation.conversationId);
}

Get or Create a Conversation

- (EMConversation *)getConversation:(NSString *)aConversationId
                               type:(EMConversationType)aType
                   createIfNotExist:(BOOL)aIfCreate;
  • getConversation: Get or create a conversation with ID.
    • one-to-one: the receiver's Hyphenate ID
    • group: group ID
  • type: enum EMConversationType
    typedef enum {
        EMConversationTypeChat = 0,         // one-to-one chat  
        EMConversationTypeGroupChat,           
        EMConversationTypeChatRoom     
    } EMConversationType;
  • createIfNotExist: whether to create or not if not exist

example

EMConversation *conversation = [[EMClient sharedClient].chatManager getConversation:@"8001" 
                                                                               type:EMConversationTypeChat 
                                                                   createIfNotExist:YES];

Delete a Conversation

- (void)deleteConversation:(NSString *)aConversationId
          isDeleteMessages:(BOOL)aIsDeleteMessages
                completion:(void (^)(NSString *aConversationId, EMError *aError))aCompletionBlock;
  • deleteConversation: Delete conversation with ID 8001
  • isDeleteMessages: Pass in YES to delete and NO to archive.

Delete Multiple Conversations

- (void)deleteConversations:(NSArray *)aConversations
           isDeleteMessages:(BOOL)aIsDeleteMessages
                 completion:(void (^)(EMError *aError))aCompletionBlock;
  • deleteConversations: conversation to be deleted with a list of conversation IDs
  • isDeleteMessages: Pass in YES to delete and NO to archive.

Conversation Updating Event

This delegate will be triggered if a new conversation is created or destroyed.
This will not be triggered if the message of the conversation is updated.

example - Update new chat list table view controller

@interface EMChatsViewController () <EMChatManagerDelegate>

@end

- (void)conversationListDidUpdate:(NSArray *)aConversationList
{
    WEAK_SELF
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSArray* sorted = [self _sortConversationList:aConversationList];
        dispatch_async(dispatch_get_main_queue(), ^{
            [weakSelf.dataSource removeAllObjects];
            for (EMConversation *conversation in sorted) {
                EMConversationModel *model = [[EMConversationModel alloc] initWithConversation:conversation];
                [weakSelf.dataSource addObject:model];
            }
            [self tableViewDidFinishTriggerHeader:YES];
            [weakSelf.tableView reloadData];
        });
    });
}

Conversation Attributes

See EMConversation.h for a a a more comprehensive list of methods for EMConversation class. Here are some common methods and properties.

Get Unread Messages Count

- (void)showUnreadConversationCount
{
    NSArray *conversations = [[EMClient sharedClient].chatManager getAllConversations];
    NSInteger unreadCount = 0;
    for (EMConversation *conversation in conversations) {
        unreadCount += conversation.unreadMessagesCount;
    }

    if (self.chatsVC) {
        if (unreadCount > 0) {
            self.chatsVC.tabBarItem.badgeValue = [NSString stringWithFormat:@"%i", (int)unreadCount];
        } else {
            self.chatsVC.tabBarItem.badgeValue = nil;
        }
    }

    [[UIApplication sharedApplication] setApplicationIconBadgeNumber:unreadCount];
}

Latest Message

@property (nonatomic, strong, readonly) EMMessage *latestMessage;

Delete Message by ID

- (void)deleteMessageWithId:(NSString *)aMessageId
                      error:(EMError **)pError;

Load messages with specified keyword

Returning messages are sorted by the timestamp received. If the reference timestamp is negative, load from the latest messages; if the message count is negative, count deal with 1 and load one message that meets the condition.

- (void)loadMessagesWithKeyword:(NSString*)aKeyword
                      timestamp:(long long)aTimestamp
                          count:(int)aCount
                       fromUser:(NSString*)aSender
                searchDirection:(EMMessageSearchDirection)aDirection
                     completion:(void (^)(NSArray *aMessages, EMError *aError))aCompletionBlock;

Load messages within specified time range

Returning messages are sorted by timestamp received.

- (void)loadMessagesFrom:(long long)aStartTimestamp
                      to:(long long)aEndTimestamp
                   count:(int)aCount
              completion:(void (^)(NSArray *aMessages, EMError *aError))aCompletionBlock;

Get Messages

Get messages in a conversation based on the message type, start time, end time, etc.
The following methods, like loadMessagesStartFromId:count:searchDirection:completion:, only load the messages from the local database, NOT from the server. You'll need to use REST API to obtain the full set of message history.

Get message in batch started from specified ID

- (void)loadMessagesStartFromId:(NSString *)aMessageId
                          count:(int)aCount
                searchDirection:(EMMessageSearchDirection)aDirection
                     completion:(void (^)(NSArray *aMessages, EMError *aError))aCompletionBlock;

By message body type

- (void)loadMessagesWithType:(EMMessageBodyType)aType
                   timestamp:(long long)aTimestamp
                       count:(int)aCount
                    fromUser:(NSString*)aUsername
             searchDirection:(EMMessageSearchDirection)aDirection
                  completion:(void (^)(NSArray *aMessages, EMError *aError))aCompletionBlock;
typedef enum {
    EMMessageBodyTypeText   = 1,    /*!  Text */
    EMMessageBodyTypeImage,         /*!  Image */
    EMMessageBodyTypeVideo,         /*!  Video */
    EMMessageBodyTypeLocation,      /*!  Location */
    EMMessageBodyTypeVoice,         /*!  Voice */
    EMMessageBodyTypeFile,          /*!  File */
    EMMessageBodyTypeCmd,           /*!  Command */
} EMMessageBodyType;

By specific keyword

- (void)loadMessagesWithKeyword:(NSString*)aKeyword
                      timestamp:(long long)aTimestamp
                          count:(int)aCount
                       fromUser:(NSString*)aSender
                searchDirection:(EMMessageSearchDirection)aDirection
                     completion:(void (^)(NSArray *aMessages, EMError *aError))aCompletionBlock;

By specified time frame with max objects count

- (void)loadMessagesFrom:(long long)aStartTimestamp
                      to:(long long)aEndTimestamp
                   count:(int)aCount
              completion:(void (^)(NSArray *aMessages, EMError *aError))aCompletionBlock;

Message Delivery and Read Status

There are three types of message statuses, delivered, sent, and read.

Methods are part of class [EMClient sharedClient].chatManager

Delivered - Message delivered to Hyphenate server

- (void)messagesDidDeliver:(NSArray *)aMessages;

Sent - Message received by receiving client

- (void)messagesDidReceive:(NSArray *)aMessages;

Read - Receiver responded with message read acknowledgment

- (void)sendMessageReadAck:(EMMessage *)aMessage
                completion:(void (^)(EMMessage *aMessage, EMError *aError))aCompletionBlock;

Sender received callback indicates Message is Read by Receiver

- (void)messagesDidRead:(NSArray *)aMessages;

Next step: Rich Contents

Messages


Suggested Edits are limited on API Reference Pages

You can only suggest edits to Markdown body content, but not to the API spec.