service = client.service().messaging();
Depending on the client you initialised ComapiClient or RxComapiClient you will have access to callbacks or reactive profile APIs. Reactive version returns Observables you need to subscribe to. For callback version pass callback as the last parameter and the request will be performed in the background delivering result in UI thread.
data consistency
In order to manage concurrent updates of a conversation from many devices/websites use ETag. When obtaining conversation details from Comapi services you can find an ETag in ComapiResult object. It describes what version of server data you got. When you want to update this data pass the same ETag with the new details. If the server data will change before your next update the services will not allow such modification until you obtain the recent version of the data and pass correct ETag with the next update. This way you can keep consistency of the data across many devices.
messaging service API
create conversation
ConversationCreate conversation = ConversationCreate.builder()
// Unique conversation identifier.
.setId("1234")
// Description
.setDescription("This is my first conversation")
// Name
.setName("Awesome chat")
// Is this conversation visible to users not being participants.
.setPublic(false)
/* Sets what permissions 'owner' and 'participant' will have in this conversation
You can set if they will can: add new participants, remove participants, send messages.
By default 'owner' and 'participant' can send messages, can add participants, cannot remove participants.
Here we added CanRemoveParticipants permission for the 'owner'. */
.setRoles(new Roles(Role.builder().setCanRemoveParticipants().build(), new Role()))
.build();
Then pass this object to Comapi services
service.createConversation(conversation,
new Callback<ComapiResult<ConversationDetails>>(){/* implement */});
rxService.createConversation(conversation)
.subscribe(new Observer<ComapiResult<ConversationDetails>>(){/* implement */});
update conversation
ConversationUpdate update = ConversationUpdate.builder()
.setDescription("New description")
.setName("Different name")
.build();
Then pass this object to Comapi services
service.updateConversation(conversationId, update, eTag,
new Callback<ComapiResult<ConversationDetails>>(){/* implement */});
rxService.updateConversation(conversationId, update, eTag)
.subscribe(new Observer<ComapiResult<ConversationDetails>>(){/* implement */});
delete conversation
service.deleteConversation(conversationId, eTag,
new Callback<ComapiResult<Void>>(){/* implement */});
rxService.deleteConversation(conversationId, eTag)
.subscribe(new Observer<ComapiResult<Void>>(){/* implement */});
get convesartion
To obtain conversation details call
service.getConversation(conversationId,
new Callback<ComapiResult<ConversationDetails>>(){/* implement */});
rxService.getConversation(conversationId)
.subscribe(new Observer<ComapiResult<ConversationDetails>>(){/* implement */});
// is the conversation public or private
isPublic();
// unique identification number
getId();
// name of the conversation
getName();
// description of the conversation
getDescription();
// privileges of owner and participants in this conversation
getRoles();
query conversations
You can also obtain the list of all conversations:
service.getConversations(isPublic,
new Callback<ComapiResult<List<Conversation>>>(){/* implement */});
rxService.getConversations(isPublic)
.subscribe(new Observer<ComapiResult<List<Conversation>>>(){/* implement */});
// is the conversation public or private
isPublic();
// unique identification number
getId();
// name of the conversation
getName();
// description of the conversation
getDescription();
// privileges of owner and participants in this conversation
getRoles();
// eTag to compare if local version of the data is the same as the one the server side
getETag();
// number of participant in conversation
getParticipantCount();
// latest event id of sent message in the conversation. If null there are no messages in the conversation
getLatestSentEventId();
remove conversation participants
Provide list of profile ids to be removed from conversation.
service.removeParticipants(conversationId, ids,
new Callback<ComapiResult<Void>>(){/* implement */});
rxService.removeParticipants(conversationId, ids)
.subscribe(new Observer<ComapiResult<Void>>(){/* implement */});
query conversation participants
Query all participants for particular conversation
service.getParticipants(conversationId,
new Callback<ComapiResult<List<Participant>>>(){/* implement */});
rxService.getParticipants(conversationId)
.subscribe(new Observer<ComapiResult<List<Participant>>>(){/* implement */});
add participants to conversation
Add new participants to conversation
service.addParticipants(conversationId, participants,
new Callback<ComapiResult<Void>>(){/* implement */});
rxService.addParticipants(conversationId, participants)
.subscribe(new Observer<ComapiResult<Void>>(){/* implement */});
send message in conversation
service.sendMessage(conversationId, body,
new Callback<ComapiResult<MessageSentResponse>>(){/* implement */});
rxService.sendMessage(conversationId, body)
.subscribe(new Observer<ComapiResult<MessageSentResponse>>(){/* implement */});
You can update the message status later using conversationId from ComapiResult result.
// globaly unique message identifier
getId();
// unique for conversation event identifier, monotonically increasing, can be used to order messages
getEventId();
The more advanced way of constructing a new message is through
Map<String, Object> data = new HashMap<>();
data.put("key","value");
Map<String, Object> fcm = new HashMap<>();
fcm.put("data", data);
fcm.put("notification", "{ \"title\":\"Message\", \"body\":\"Hi!\" } ");
Map<String, Object> apns = new HashMap<>();
apns.put("alert", "Hi!");
Part part = Part.builder()
.setData("Hi")
.setName("body")
.setSize("Hi".length())
.setType("text/plain")
.build();
MessageToSend message = MessageToSend.builder()
.setAlert(fcm, apns)
.setMetadata(data)
.addPart(part)
.build();
In this way you can set details of FCM/APNS notifications to be sent to participants devices, some custom metadata, add more message parts with e.g. Base64 encoded images etc.
Then call
service.sendMessage(conversationId, message,
new Callback<ComapiResult<MessageSentResponse>>(){/* implement */});
rxService.sendMessage(conversationId, message)
.subscribe(new Observer<ComapiResult<MessageSentResponse>>(){/* implement */});
You can update the message status later using conversationId from ComapiResult result.
update message status
MessageStatusUpdate update = MessageStatusUpdate.builder()
.addMessageId("id")
.setStatus(MessageStatus.delivered)
.build();
List<MessageStatusUpdate> updates = new ArrayList<>();
updates.add();
Then pass the list with 'delivered' and 'read' statuses to the service
service.updateMessageStatus(conversationId, updates,
new Callback<ComapiResult<Void>>(){/* implement */});
rxService.updateMessageStatus(conversationId, updates)
.subscribe(new Observer<ComapiResult<Void>>(){/* implement */});
query conversation events
Introduced in v1.0.2.
Conversation events - sending a message and updating a message status can be obtained providing conversation event id to start from (and going forward) and an upper limit of events you are interested in.
service.queryConversationEvents(conversationId, from, limit,
new Callback<ComapiResult<ConversationEventsResponse>>(){/* implement */});
rxService.queryConversationEvents(conversationId, from, limit)
.subscribe(new Observer<ComapiResult<ConversationEventsResponse>>(){
/* implement */});
In response you will get
/**
* Gets Events in the order in which they were received.
* This collection can contain following conversation events:
* MessageSentEvent - new message received in the conversation
* MessageDeliveredEvent - message status marked 'delivered'
* MessageReadEvent - message status marked 'read'
* Cast elements of this collection to one of these.
*/
getEventsInOrder();
// Parsed message sent events
getMessageSent();
// Parsed message status 'delivered' events
getMessageDelivered();
// Parsed message status 'read' events
getMessageRead();
See socket events for details.
query messages
List of messages in a conversation can be obtained providing conversation event id to start from (and going backwards) and an upper limit of messages you are interested in. This interface allows you to get messages from the end of the conversation one page at a time. This will allow you to implement the classic pull down interface to load more messages.
service.queryMessages(conversationId, from, limit,
new Callback<ComapiResult<MessagesQueryResponse>>(){/* implement */});
rxService.queryMessages(conversationId, from, limit)
.subscribe(new Observer<ComapiResult<MessagesQueryResponse>>(){/* implement */});
The result is a list of messages and orphaned events associated with them. The orphaned events are the events updating messages for conversation event id higher then 'from' - so for messages obtained e.g. in previous 'paging calls'. This events need to be applied to this newer messages.
// Messages conforming to the query.
getMessages();
/* Latest event id in this conversation that
was taken into account constructing the query result. */
getLatestEventId();
/* Earliest event id in this conversation that
was taken into account constructing the query result. */
getEarliestEventId();
// Events updating messages for conversation event id later/higher then 'from'.
getOrphanedEvents();
Getter messagesQueryResponse.getMessages() returns list of MessageReceived:
// Message unique identifier.
getMessageId();
/* Unique, monotonically increasing number of event
of this message and conversation. */
getSentEventId();
// Message sender.
getFromWhom();
/* Message sender defined internally on server
(shouldn't be visible inside the app). */
getSentBy();
// When the message was sent.
getSentOn();
// Conversation unique identifier
getConversationId();
// Key is the profile identifier the value is either 'delivered' or 'read'
getStatusUpdate();
Getter messagesQueryResponse.getOrphanedEvents() returns list of OrphanedEvent:
// Conversation event id.
getConversationEventId()
// Event name.
getName();
// Unique event identifier.
getEventId()
// Id of the updated message.
getMessageId();
// Id of the conversation for which message was updated.
getConversationId();
// Profile id of the user that changed the message status.
getProfileId();
// Gets time when the message status changed.
getTimestamp();
// True if this event is of type message delivered.
isEventTypeDelivered()
// True if this event is of type message read.
isEventTypeRead();
send user is typing event
Introduced in v1.0.2.
To send an information to conversation participants that the user started or finished typing a new message call
service.isTyping(conversationId, isTyping,
new Callback<ComapiResult<Void>>(){/* implement */});
rxService.isTyping(conversationId, isTyping)
.subscribe(new Observer<ComapiResult<Void>>(){/* implement */});
Upload content data
Introduced in v1.1.1
To upload content data
service.uploadContent(folder, contentData,
new Callback<ComapiResult<UploadContentResponse>>(){/* implement */});
rxService.uploadContent(folder, contentData)
.subscribe(new Observer<ComapiResult<UploadContentResponse>>(){
/* implement */});
The content data can be created based on a file, byte array and base64 string
contentData = ContentData.create(file, type, name);
contentData = ContentData.create(byte[], type, name);
contentData = ContentData.create(base64, type, name);
The UploadContentResponse will contain the full url to the file in the cloud. You can for e.g. send a message with a message Part containing this url pointing to an attachment data.