Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
This page highlights the steps you will need to follow to begin integrating chat messaging into your products
The message payload is always the same regardless of which Development Kit the user is using. Users also have a choice on what type of message they want to send.
Amity supports the sending and receiving of 5 types of messages. They are Text, Image, Audio, File, and Custom.
Amity will automatically optimize the image and when queried, will return the image in small, medium and large sizes. If the image is marked as isFull
on upload, the original size of the image can also be returned.
When an image is uploaded, it is automatically resized into multiple sizing options. The size of the image is determined by its longest dimension (in pixels) with the aspect ratios being unchanged.
The maximum file size of an image cannot exceed 1 GB.
When a user is observing messages, the message will always appear in this format.
Messages are JSON content containers that can weigh up to 100KB and will be synchronized among all channel users in real-time. If a message requires larger binary data (such as when sending files), we recommend to upload the data to another cloud storage service, such as AWS S3, and store the URL to the content in the message data.
In addition the JSON message type, the SDK also provides support for common text and image message types. These additional types are built on top of the standard JSON message layer.
In case of image messages, the SDK freely provides a cloud storage service that will process and store all images uploaded: you don't need to setup and manage a separate cloud storage service for this common case.
All messaging methods are contained in a EkoMessageRepository
class. Before calling any messaging methods, you must ensure to first instantiate a repository instance using the EkoClient
instance you created on setup.
All message sending methods are designed to be robust enough to work under any network conditions. When you send any message, that message will automatically be put into a queue incase of any unforeseen unstable network conditions. Once the SDK reconnects to the server, it will automatically resend all the queued messages.
Additionally, sent messages are always returned in message queries, even before they have been delivered to the server. This provides the user with a fluid messaging flow: when a user sends a message, that sent message will appear in the message stream right away (instead of waiting until it has been confirmed by the server). To check or display the current status of message delivery for your application, use the syncState
property in the message model.
Every message sending method returns you a live object. This live object should be observed until message has been synced with the server.
Initiate the messaging with the following scripts, depending on your platform of choice.
To send an image message, you must pass in a valid UIImage
instance instead. The SDK will resize and process the image object before sending it to the server. You can also pass in an optional caption as part of the message, this caption will be accessible under the data
property in the message model, under the caption
key.
Use the
fullImage
parameter to request to upload the image at its original resolution. Note that this can drastically reduce the speed of message sending, depending on the original image size. If thefullImage
is set tofalse
, then the uploaded image size will be up to 1500x1500 pixels.
To send a file message, you must pass in an NSData
instance of the selected file and file name for the file. The default file name is file
. The SDK will check the size of the data whether it is exceeding the limitation or not before sending it to the server. If the size of the data is more than the limit than the callback will return an Error
object with the Dictionary
of the error information that you can parse it and show an error message.
Viewing File Message
The server will automatically generate a filename for you under the
fileName
key on the message data property, based on the file name that you choose to use. We advised that you handle the file size issues beforehand, as currently our limitation is set to less than 1 GB.
You can send small voice clips as a message.EkoMessageRepository
provides createAudioMessage:
a method to send voice clips to other users. It accepts voice clips as a NSData
instance.
To send a custom message, you must pass in a Dictionary
instance. The server will populate this as a JSON
format. Later on, you must parse it by yourselves depending on the key and value that you set earlier on.
Viewing Custom Message
A custom message will be sent as a JSON format. If you wish to show the message, remember to parse the value. You are responsible to parse your own custom type data.
To query for a list of all messages in a channel:
This method will return a LiveObject of all messages in the specified channel. You can observe the LiveObject in order to update your view whenever you receive new messages.
To get a specific message:
While the SDK will always return messages in chronological order, developers can ask for the messages to be returned starting from the oldest first, or the newest first.
On a typical messaging application, the messages are fetched from the latest (newest) first, and then more older messages are explored.
There are other situations where fetching the oldest messages is preferred, for example for archiving purposes or in community forums.
Like for channels, we also have various ways to obtain messages that only match specific criteria:
the includingTags
and excludingTags
parameters let you filter messages based on the tags set (or not set) in each message
the filterByParentId
and parentId
parameters let you filter messages by their relationship:
when filterByParentId
is set to false
, any message will match.
when filterByParentId
is set to true
and no parentId
is passed, query for all messages without a parent.
when filterByParentId
is set to true
and a parentId
is passed: query for all messages with the parentId
as parent.
For commenting a message, we can observe the comment on the message from EkoMessageRepository
and observe the message with specific channelId
, and force the filterByParentId
to true
, and inject the parentId
of the message. (See message filtering section)
For creating a comment, we can pass the parentId
to the message creation.
The following method can return a live object of specific EkoMessage
based on messageId
. Since it is a live object remember to observe its changes on top of the token.
Images in messages are not downloaded automatically when the client receives a message. In order to save bandwidth, images should be downloaded only when they're about to be displayed. A typical implementation to trigger the download would be in the tableView:cellForRowAtIndexPath:
method. You can download an image using downloadImage:
method from the same EkoMessageRepository
class. You need to pass the EkoMessage
instance and the method provides the appropriate image depending upon the sync state of message.
Please use the appropriate image size depending on your use-case in order to save bandwidth.
small
is used for image thumbnails, with a maximum image size of 160 pixels per dimension. For example, this should be used for small previews in an image gallery that displays a large amount of images in a grid.
medium
is used for standard image display, with a maximum image size of 600 pixels per dimension. It's sized to take up about half of a mobile phone's screen size.
large
is used for full screen image display, with a maximum image size of 1500 pixels per dimension.
full
is used to get the original image. This size is only valid if the image is uploaded with the property fullImage
set to YES
. If a full sized image is not available, a large
sized image will be returned instead.
The
completionHandler
can be called multiple times as the SDK will attempt to fetch a local cached version of the image first. If a lower resolution version of the image is cached, it will return that image, while also attempting to fetch the correct size from the server. As such, please make sure the logic implemented in thecompletionHandler
is idempotent.
EkoMessageRepository
provides downloadFile:
method to download the file present in message. The same method can be used to download the audio present in audio message.
To query for a list of all reaction on the specific message in a channel, right now to get the list of reactions is controlled by EkoMessageRepository
. We can observe with the same way as observing message, the only thing difference is sending messageId
as the parameter. The operation will return an instance EkoCollection
of EkoMessageReaction
that contains reaction name, message id, reactor id and reactor display name of the user and the reaction used.
This method will return a LiveObject of all the reactions of a specific message in the specified channel. You can observe the LiveObject in order to update your view whenever you receive a new reaction on that message.
For adding a new reaction, we can use EkoMessageReactor
to perform its operation. Initialize the reactor with the client and message, don't forget to specify the reaction name as well.
For removing a new reaction, we can use EkoMessageReactor
to perform its operation. Initialize the reactor with the client and message and specify the reaction name.
A special EkoMessageEditor
class is also provided for you to perform actions on messages you've sent or received. These actions include editing and deleting an existing message, as well as marking a message as being read by you.
To start, first instantiate a EkoMessageEditor
instance with the EkoClient
instance you created on setup, as well as a valid messageID
.
You can only perform edit and delete operations on your own messages. Once the operation is complete, the message's editedAtDate
will be set to the current time. This allows you to provide UI to the user to inform the user of specific messages that has been edited, if needed. An optional completion block can be provided to notify you of operation success.
Name
Data Type
Description
Attributes
messageId
string
The id of this message
Content
parentId
string
The messageId
of the parent of this message
Content
childrenNumber
integer
The number of messages with parentId
of this message
Content
channelId
string
The name of the channel this message was created in
Content
userId
string
The name of the user this message was created by
Content
type
string
The message type
enum*: text
custom
image
file
tags
Array.<string>
The message tags
Content
data
Object
The message data (any text will be stored in text
key)
text
: Text message
isDeleted
boolean
The message has been marked as deleted
Content
channelSegment
integer
The sequence number of a message in channel
Content
createdAt
date
The date/time the message was created at
Content
updatedAt
date
The date/time the message was updated at
Content
editedAt
date
The date/time the message was edited at
Content
flagCount
integer
The number of users that have flagged this message
Content
hashFlah
Object
A hash for checking internally if this message was flagged by the user
Content
reactions
Object
The reaction data (stored as a reactionName and counter key/value pair)
Example: { like
: 1, dislike
: 2 }
reactionsCount
integer
The total number of reactions on this message
Content
myReactions
Array.<string>
A list of user's reactions on this message
Content
This section outlines how you can set-up your project for success and begin using our Chat SDK for iOS application.
Before using the Chat SDK, you will need to create a new SDK instance with your API key. Please find your account API key via the Admin Panel. If you have trouble finding this, you can send our support team an email at developer@amity.co
In order to use any Chat SDK feature, you must first register the current device with an userId
. A registered device will be tied to the registered userId
until the device is either proactively unregistered, or until the device has been inactive for over 90 days. A registered device will receive all the events messages belonging to the tied user.
An optional displayName
can be provided, which will be used in standard push notifications (related to user's actions, such as when the new message is sent).
The
displayName
is set only on the first time the device is registered, please follow your platforms necessary directions if you would like to rename this to something else.
When the user logs out, you should explicitly unregister the user from the SDK as well. This prevents the current device from receiving unnecessary and/or restricted data.
Each user can be registered, at the same time, to an unlimited number of devices. Amity's Chat SDK will automatically synchronize the user data across all registered devices. We will also automatically unregister any device that has not been connected to the server for more than 90 days.
When a device is unregistered due to inactivity, the SDK data on the device will be reset. You will need to re-register this device in order to connect to server again.
If you have any logic or UI around the connection status, you can observe the connectionStatus
property on the EkoClient
instance.
Since the Chat SDK automatically manages the network connection and queue up any requests in cases of bad connection, there should be little need to attach additional logic to this status. However the user may want to know the exact network status to determine if their actions will be performed in real-time, therefore this status is exposed.
The connectionStatus
flag supports KVO notifications, use NSObject
's observe methods to be notified whenever this status changes
Our Sample app adopts an open source framework that highlights how Amity Social Cloud SDK's can be implemented into application builds pragmatically.
With real life use-cases, we guide you through ways you can get started with building stellar applications for yourself and your clients and their users
Moderation is an important feature for building a safe community that encourages user participation and engagement.
Amity’s customer centric nature ensures that security needs are kept at the forefront of the work we do. Our purpose has been to continuously develop features that are safe and ready to use. We power our moderators with tools to control and impose permissions that make their applications a safer place, for all users. We put the utmost importance on giving power to our clients to implement protocols that keep their applications healthy, safe and compliant.
Amity SDK's do not store or manage any user data. This means that you do not have to import or migrate existing user profiles into the system, user management should be handled by your application code. Instead, every user is simply represented by a unique userID
, which can be any string that uniquely identifies the user and is immutable throughout its lifetime.
A database primary key would make an ideal
userID
. Conversely, something like username or emails is not recommended as those values may change overtime.
If you wish to assign additional permissions for a user, for example moderation privileges or different sending limits, you can provide an array of roles to assign to this user. Roles are defined in the admin panel and can be tied to an unlimited number of users. Once again, Amity does not store or manage any user data, which means you do not have to import or migrate existing users into the system. It also means that Amity cannot provide user management functionalities like lists of users, or limit actions of certain users (e.g. user permissions). Instead, these functionalities should be handled by the rest of your application's capabilities and your server.
Though the SDK does not store and should not be responsible for the handling User profile data for your application; We do provide tools to make some surface-level queries and searches for existing user accounts. With the help of our EkoUserRepository
class, you would be able to list all the users, search for list of users whose display name matches your search query and get EkoUser
object from user id.
Each User consists of a userId
and displayName
. The userId
is immutable once the account is created, however the displayName
can be updated at all times. EkoUserRepository
provides a convenient method userForId(_:)
which map user id to particular EkoUser
object. It returns a live EkoObject<EkoUser>
which you can observe too. It accepts one parameter userId
which is the userId of the user.
EkoUserRepository
provides a convenient method getAllUsersSortedBy(_:)
to fetch all users. This method will return EkoCollection<EkoUser>
. You can observe for changes in collection, similar to message or channel. The method accepts EkoUserSortOption
enum as a parameter. The list can be sorted by displayName
, firstCreated
or lastCreated
.
The code above will provide you with list of users which are sorted by displayName
.
EkoUserRepository
contains another convenient method searchUser(_:_:)
which allows you to query for any particular user using their display name. It provides you with a collection of EkoUser
whose display name matches with your search query. It accepts two parameters. The first one is the display name that you want to search for and the second one is sort option which is EkoUserSortOption
enum.
The code above will provide you with the list of users which matches with display name "abc".
EkoClient
class provides a method hasPermission(_:)
which allows to check if the current logged in user has permission to do stuffs in given channel.
Rate limiting a channel controls the speed of messages that is published to all concurrent clients in the channel
This method is useful when there is a large amount of messages going through the channel, which can make the message stream hard to follow. Setting a rate limit enables the SDK to queue up messages once the amount of message in a specified window
exceeds the defined limit
, allowing a slower stream of messages to be published to the user at the expense of adding more latency (because newer messages will be sent to the queue first and not delivered until all previous queued messages are delivered).
There is an internal limit of 1000 messages that can be queued by the rate limit service, if more than 1000 messages are queued up, the system may skip publishing the older messages in order to make room for newer messages. We believe this is the preferred behavior for users, as users will most likely want to see newer messages in a real-time conversation instead of waiting for a significant amount of time for old messages to be published to them first.
Note that the SDK permanently stores all messages it receives in the system before the rate limit comes into effect: in the case of a large spike of incoming messages, even if a message did not get published to a user in real-time, that user can still scroll up to see message history and see that past message.
The above method enables a rate limit of 5 messages every 60 seconds: once there are more than 5 messages sent, from any user, within 60 seconds, those messages will be queued on the server and not published to other channel members until 60 seconds have passed. The rate limit will last as long as the period specified in the method call: in the example above the rate limit will be active for 10 minutes (600 seconds).
If you would like to have a permanent rate limit, call the method above with a period of -1 seconds.
In order to disable the rate limit, simply call remoteRateLimitWithCompletion:
:
When a user is banned in a channel, they are removed from a channel and no longer able to participate or observe messages in that channel.
Moderators can ban and unban users. When a user is banned in a channel, they are forcebly removed from channel and may no longer participate or observe messages in that channel. All their previous messages in the channel will also be automatically deleted.
A user that has been banned from a channel can not rejoin the channel until they have been unbanned.
As well as the banning and unbanning of users, admins also have the ability to global ban a user. When a user is globally banned, they can no longer access Amity's network and will be forcebly removed from all their existing channels. All the globally banned user's messages will also be deleted.
The globally banned user can not access Amity's network again until they have been globally unbanned.
Banning users is a more heavy handed moderation method. When a user is banned, all its messages are retroactively deleted, it will be removed from the channel, and it will not be allowed to join the channel again until he is explicitly unbanned.
There is a separate unban call to unban a user:
Note: This feature does not work with Broadcast
and Conversation
channels. Calling banUsers()
or unBanUsers()
on these channels will result in an error.
When a user is muted, they can not send messages in a channel.
Moderators can mute and unmute users. When a user is muted, they cannot send messages in a channel. However muted users will still be allowed to observe messages in a channel. The status of being muted is indefinite but is only applied at the channel level.
When a user is muted, all messages sent by that user to that channel will be rejected. This method is useful for preventing certain users from sending inappropriate messages, but still allowing them to participate in the conversation in a read-only manner. The timeout property allows you to make the timeout temporary, or permanent by until unset by passing in -1
.
If you want to permanently mute a user, pass in
-1
as the mutePeriod. The user will stay muted until you explicitly unmute that user.
To unmute an user, call unmuteUsers:
:
Name
Data Type
Description
Attributes
userId
string
The id of this user
roles
Array.<string>
A list of user's roles
displayName
string
The display name of the user
flagCount
integer
The number of users that have flagged this user
metadata
Object
The metadata of the user
hashFlag
Object
A hash for checking internally if this user was flagged by the user
createdAt
date
The date/time the user was created at
updatedAt
date
The date/time the user was updated at
Flag and Unflag a channel user
While having moderators surveying your chats is great, this doesn't scale well. A way to overcome this is to let your users do the work for your moderators: by letting users report other users or specific messages, the work of moderators goes from scanning each message in each channel to investigate each user report (to both users and messages) and react only when deemed necessary.
In order to flag a user, create an instance of EkoUserFlagger
first:
The EkoUserFlagger
lets you flag and unflag a user, and it also exposes a asynchronous way to check whether the current logged-in user has already flagged the given user or not:
To flag a user, call the following method:
To unflag a user, call the following method:
flag and unflag a message
While having moderators surveying your chats is great, it doesn't scale well. A way to overcome this is to let your users do the work for your moderators. By letting users flag other users or specific messages, the work of moderators is significantly reduced and democratized, thus allowing administrators to only respond to issues when deemed critical or absolutely necessary.
In order to flag a message, create an instance of EkoMessageFlagger
first:
The EkoMessageFlagger
lets you flag and unflag a message, and it also exposes a asynchronous way to check whether the current user has flagged the given message already:
To flag a message, call the following method:
To unflag a message, call the following method:
The User can also check if they have previously flagged the message before by calling the following asynchronous method:
Remember that each
EkoMessageFlagger
is tied to one specific message.
Error objects can be returned to you via LiveObjects, callbacks, or clientErrorDelegate
. All the errors returned by the SDK come in form of an NSError with domain Eko
. The possible error codes are listed in a public EkoErrorCode
enum: each case is named after its error and they're pretty self explanatory.
UnauthorizedError: 400100
ItemNotFound: 400400
BadRequestError: 400000
Conflict: 400900
ForbiddenError: 400300
PermissionDenied: 400301
UserIsMuted: 400302
ChannelIsMuted: 400303
UserIsBanned: 400304
NumberOfMemberExceed: 400305
ExemptFromBan: 400306
MaxRepetitionExceed: 400307
BanWordFound: 400308
LinkNotAllowed: 400309
GlobalBanError: 400312
BusinessError: 500000
Unknown: 800000
InvalidParameter: 800110
MalformedData: 800130
ErrorQueryInProgress: 800170
ConnectionError: 800210
When an error is returned as a result of an action from your side (e.g. trying to join a channel), the action is considered completed and the SDK will not execute any additional logic.
The EkoClient
includes a clientErrorDelegate
property that can be set to an error handler delegate class on your application. This error delegate gives you a chance to be notified of errors that can potentially break the functionality of the SDK. The SDK logic is usually robust enough to automatically handle most errors, as such, only unrecoverable errors are exposed through this delegate (for example, if the login session was invalidated).
We recommend you to always handle these errors in a production app by gracefully disabling messaging functionality in the event of an error.
This section outlines how you can set-up your project for success and begin using our Chat SDK for Android.
Before using the Chat SDK, you will need to create a new SDK instance with your API key. Please find your account API key via the Admin Panel. If you have trouble finding this, you can send our support team an email at developer@amity.co
In order to use any Chat SDK feature, you must first register the current device with an userId
. A registered device will be tied to the registered userId
until the device is either proactively unregistered, or until the device has been inactive for over 90 days. A registered device will receive all the events messages belonging to the tied user.
An optional displayName
can be provided, which will be used in standard push notifications (related to user's actions, such as when the new message is sent).
The
displayName
is set only on the first time the device is registered, please follow your platforms necessary directions if you would like to rename this to something else.
When the user logs out, you should explicitly unregister the user from the SDK as well. This prevents the current device from receiving unnecessary and/or restricted data.
Each user can be registered, at the same time, to an unlimited number of devices. Amity's Chat SDK will automatically synchronize the user data across all registered devices. We will also automatically unregister any device that has not been connected to the server for more than 90 days.
When a device is unregistered due to inactivity, the SDK data on the device will be reset. You will need to re-register this device in order to connect to server again.
If you have any logic or UI around the connection status, you can observe the connectionStatus
property on the EkoClient
instance.
Since the Chat SDK automatically manages the network connection and queue up any requests in cases of bad connection, there should be little need to attach additional logic to this status. However the user may want to know the exact network status to determine if their actions will be performed in real-time, therefore this status is exposed.
Our Sample app adopts an open source framework that highlights how Amity Social Cloud SDK's can be implemented into application builds pragmatically.
With real life use-cases, we guide you through ways you can get started with building stellar applications for yourself and your clients and their users
Moderation is an important feature for building a safe community that encourages user participation and engagement.
Amity’s customer centric nature ensures that security needs are kept at the forefront of the work we do. Our purpose has been to continuously develop features that are safe and ready to use. We power our moderators with tools to control and impose permissions that make their applications a safer place, for all users. We put the utmost importance on giving power to our clients to implement protocols that keep their applications healthy, safe and compliant.
When a user is muted, they can not send messages in a channel.
Moderators can mute and unmute users. When a user is muted, they cannot send messages in a channel. However muted users will still be allowed to observe messages in a channel. The status of being muted is indefinite but is only applied at the channel level.
When a user is muted, all messages sent by that user to that channel will be rejected. This method is useful for preventing certain users from sending inappropriate messages, but still allowing them to participate in the conversation in a read-only manner. The timeout property allows you to make the timeout temporary, or permanent by until unset by passing in -1
.
The above logic will mute user1
in the selected channel for 10 minutes.
If you want to permanently mute a user, pass in
Duration.millis(-1)
as thetimeout
. The user will stay muted until you explicitly unmute that user.
To unmute an user, call EkoChannelModeration.unmuteUsers()
:
Note: This feature does not work with Broadcast
and Conversation
channel. Calling muteUsers()
or unMuteUsers()
on these channels will result in an error.
When a user is banned in a channel, they are removed from a channel and no longer able to participate or observe messages in that channel.
Moderators can ban and unban users. When a user is banned in a channel, they are forcebly removed from channel and may no longer participate or observe messages in that channel. All their previous messages in the channel will also be automatically deleted.
A user that has been banned from a channel can not rejoin the channel until they have been unbanned.
As well as the banning and unbanning of users, admins also have the ability to global ban a user. When a user is globally banned, they can no longer access Amity's network and will be forcebly removed from all their existing channels. All the globally banned user's messages will also be deleted.
The globally banned user can not access Amity's network again until they have been globally unbanned.
Banning users is a more heavy handed moderation method. When a user is banned, all its messages are retroactively deleted, it will be removed from the channel, and it will not be allowed to join the channel again until he is explicitly unbanned.
There is a separate unban call to unban a user:
Note: This feature does not work with Broadcast
and Conversation
channels. Calling banUsers()
or unBanUsers()
on these channels will result in an error.
This page contains an overview of all relevant changes made to the Amity Chat SDK modules and the latest version releases
Eko Messaging SDK 4.7.1 is released.
None
None
None
Optimize PagedList configuration
Fix incorrect pagination of categories
None
OKHTTP - 3.10.0
Retrofit - 2.4.0
Kotlin-std-lib - 1.3.72
Eko Messaging SDK 4.7.0 is released.
Introduce eko-video-publisher
for video broadcasting. Refer to Video documentation.
Add manual paging functionality to EkoCommentQuery
Refer to Comment documentation.
None
None
None
None
OKHTTP - 3.10.0
Retrofit - 2.4.0
Kotlin-std-lib - 1.3.72
Eko Messaging SDK 4.6.0 is released.
Add new option .roles(roles: List<String>)
inEkoChannelMembershipQuery.Builder
. Refer to Channel
documentation.
Add new option .sortBy(option: EkoCommentSortOption)
in EkoCommentQuery.Builder
. Refer to Comment
documentation.
Add new API getLatestComment()
in EkoCommentRepository
. Refer to Comment
documentation.
Add custom dataType
support for EkoPost
. Refer to Feed
documentation.
Change query option setIsLive(isLive: Boolean)
to setStatus(statuses: Array)
in EkoStreamQuery.Builder
. The user is now able to query live-stream videos based on its statues.
Query memberships by role. .role(role: String)
ImprovegetMyReactions()
performance on EkoMessage
, EkoPost
, EkoComment
None
OKHTTP - 3.10.0
Retrofit - 2.4.0
Kotlin-std-lib - 1.3.72
Eko Messaging SDK 4.5.1 is released.
None
None
None
Active user missing from community list when community has more than 10 members
None
OKHTTP - 3.10.0
Retrofit - 2.4.0
Kotlin-std-lib - 1.3.72
Eko Messaging SDK 4.5.0 is released.
Add query option setIsLive(boolean)
in EkoStreamQuery.Builder
. The user is now able to query currently live or ended live-stream videos.
Add new method getRecordings()
in EkoStream
model . The user is now able to get recorded videos.
None
None
None
None
OKHTTP - 3.10.0
Retrofit - 2.4.0
Kotlin-std-lib - 1.3.72
Eko Messaging SDK 4.4.2 is released.
Add automatic file name encoding for EkoFileRepository
upload API
Fixed incorrect behaviour of private community query.
Eko Messaging SDK 4.4.0 is released.
Add role
and permission
feature. Refer to Channel
and Community
documentation.
Add hasPermission(ekoPermission)
API to EkoClient
Refer to Permission
documentation.
Add AUDIO
message type.
Add getUploadInfo(uploadId)
API to EkoFileRepository
Due to revised role
and permission
feature, user'sglobal role
can only be set from admin panel/ admin API, hence the removal of setRoles()
from EkoClient
. User would still be able to add / remove role at Channel
and Community
level should they have necessary permissions.
Aligning file related message data return type with Feed
feature,
Replacing getUrl() : String
with getImage() : EkoImage
inEkoMessage.Data.IMAGE
Replacing getUrl() : String
with getFile() : EkoFile
inEkoMessage.Data.FILE
Eko Messaging SDK 4.2.0 is released.
Introduce new Channel types; Community
and Live
. Refer to Channels
documentation.
Introduce new EkoClient.registerDevice(userId)
API where displayname
is optional. Refer to Setup
documentation.
Deprecating Channel type Standard
and Private
Deprecating EkoClient.registerDevice(userId, displayname)
API
Eko Messaging SDK 3.2.6
is released.
Change return type of getMessage(String messageId)
API from EkoLiveData
to Flowable
Missing user data from getMessage(String messageId)
API
Eko Messaging SDK 3.2.3
is released.
Return EkoChannel
with createConversation()
Eko Messaging SDK 3.2.2
is released.
Add metadata
createChannel(String channelId, EkoChannel.CreationType type, EkoChannel.CreateOption option)
API
Add metadata createConversation(String userId, JsonObject metadata)
API
Prevent crash on EkoPagedListAdapter
Eko Messaging SDK 3.2.1
is released.
Add getAllUsers(EkoUserSortOption option)
API
Add searchUserByDisplayName(String displayname, EkoUserSortOption option)
API
Optimized socket rescheduling request queue.
Improved diffUtil logic of EkoChannelAdapter
and EkoChannelMembershipAdapter
.
Eko Messaging SDK 3.1.1
is released.
Add getMessage(String messageId)
API
Eko Messaging SDK 2.8.0
is released.
Add getMessage(String messageId)
API
Eko Messaging SDK 3.0.0
is released.
New channel types (Private, Broadcast, Conversation); Support creation and query of new channel types.
Creating a channel requires a EkoChannel.CreationType
as a parameter.
Channel query has been converted to builder pattern to support query of new channel types.
EkoChannelRepository.getOrCreatedById()
is deprecated.
EkoChannelRepository.getChannelCollection()
returning LiveData> is deprecated.
Eko Messaging SDK 2.7.1
is released.
Fixed message query failed for the channel creator that has null
displayname.
Eko Messaging SDK 2.7.0
is released.
Added Optimistic logic for add / remove reactions. Reaction count reflects instantly upon API call and automatically reverts in case of error.
Update DiffUtil
logic in EkoMessageAdapter
.
Eko Messaging SDK 2.6.2
is released.
Fixed myReaction
is inaccurate when the same user is on multi devices.
Applied a workaround for https://issuetracker.google.com/issues/135628748 (IndexOutOfBoundException
in AsyncPagedListDiffer
) to EkoChannelAdapter
, EkoMessageAdapter
, EkoMessageReactionAdapter
, and EkoChannelMembershipAdapter
.
Eko Messaging SDK 2.6.0
is released.
Add support of metadata for EkoUser
Eko Messaging SDK 2.5.1
is released.
Fixed myReaction
value stops EkoMessage
observation.
Eko Messaging SDK 2.5.0
is released.
Add Message reaction feature:
A reaction can be added or removed from a message with EkoMessageReactor
.
A reaction collection of a message can be queried with EkoMessageRepository
.
Add Reaction related data to EkoMessage
.
Eko Messaging SDK 2.3.0
is released.
A message can only be deleted by an editor corresponding to its type.
Add editor for each message type
EkoTextMessageEditor
can edit and delete a message of type text
.
EkoImageMessageEditor
can delete a message of type image
.
EkoFileMessageEditor
can delete a message of type file
.
EkoCustomMessageEditor
can edit and delete a message of type custom
.
Eko Messaging SDK 2.1.1
is released.
All message types are now based on Builder pattern.
The method build()
is now required to be called before the method send()
.
When creating an Image message with EkoMessageCreator
, a valid file Uri is required to be passed as a parameter.
Add File message type: a message of this type can be created with a file Uri. The file is automatically uploaded to the server and can be retrieved with a url that is accessible in FileData
model.
Add Custom message type: a message of this type can be created with a JsonObject
. This object is included in the data
property of the message. Developers can parse their customed data by creating a model that reflects the structure of the customed JsonObject
.
Eko Messaging SDK 2.0.0
is released.
Migrate to AndroidX
EkoMessageRepository
replaces the function getMessageCollection(channelId)
with getMessageCollection(channelId, stackFromEnd)
, along with many other new options such as getMessageCollection(channelId, includingTags, stackFromEnd)
, getMessageCollection(channelId, includingTags, excludingTags, stackFromEnd)
.
Message tagging support:
Messages can now be sent along with customized tags.
Messages can now be filtered by tags (both including and excluding).
Tags can also be set on any message.
Every message has a new tags
property.
Message sorting support:
Messages can now be fetched from the oldest first, or the newest first.
Message parenting support:
Messages can now be connected on creation by passing a new optional parentId
value.
Note how a message child can also become a parent itself, without any limit.
The parentId
must be passed on the child message creation and cannot be changed afterwards.
Every message has a new optional parentId
and childrenNumber
property.
Eko Messaging SDK 1.12.0
is released.
Moving repository from Bintray to Jitpack, Getting Started.
EkoClient.registerDeviceForPushNotification()
method is now parameterless, Client Registration.
Push notification services in China.
Eko Messaging SDK 1.10.1
is released.
Fixed EkoMessage
collection doesn't contain messages sent while you were offline.
Fixed EkoClient.getUserId()
and EkoClient.getDisplayName()
return data of in-active account.
Eko Messaging SDK 1.10.0
is released.
Add Push Notification toggles: users can now choose to mute selected channels or stop receiving notifications completely from any device. The new settings, documentented in the Notifications section, are per user, not per single device.
Eko Messaging SDK 1.9.0
is released.
Add Push Notification feature: developers can call register and unregister for push notification directly from the EkoClient
Read more about the feature in the new Notifications section.
Eko Messaging SDK 1.8.0
is released.
Add new EkoError.USER_IS_GLOBAL_BANNED
when a user is banned globally is automatically unregistered and the EkoChat sdk will be on a clean state.
Eko Messaging SDK 1.7.0
is released.
EkoChannelRepository.getChannelCollectionByTags(filter, includingTags)
returns List of channels with ANY provided tags.
EkoChannelRepository.getChannelCollectionByTags(filter, includingTags, excludingTags)
returns List of channels with ANY provided tags AND without ANY provided tags.
Added two new channel types EkoChannel.Type.BROADCAST
and EkoChannel.Type.CONVERSATION
(channels with conversation type won't be seen in Admin Panel because of privacy concerns)
Eko Messaging SDK 1.6.0
is released.
EkoChannelMembershipRepository.getChannelMembershipCollection(channelId)
returns List of memberships of the channel.
Eko Messaging SDK 1.5.0
is released.
EkoMessage.isFlaggedByMe()
and EkoUser.isFlaggedByMe()
tell whether you've already flagged this EkoMessage
and EkoUser
or not.
Eko Messaging SDK 1.4.0
is released.
You can now be able to flag/unflag a message EkoMessageRepository.report(messageId).flag()
or EkoMessage.report().flag()
and EkoMessageRepository.report(messageId).unflag()
or EkoMessage.report().unflag()
You can now be able to flag/unflag a user EkoUserRepository.report(userId).flag()
or EkoUser.report().flag()
and EkoUserRepository.report(messageId).unflag()
or EkoUser.report().unflag()
Eko Messaging SDK 1.3.0
is released.
EkoMessage.getEditedAt()
returns DateTime instead of string.
EkoChannel.membership().startReading()
will not return anything.
EkoChannel.membership().stopReading()
will not return anything.
EkoLiveData
will no longer return a proxy object.
if you are in a live reading mode and lost internet connection, The SDK will automatically re-enables the live reading mode after re-gaining internet connection.
EkoChannel.getLastActivity()
returns updated DateTime after receiving all message events.
EkoChannel.getUnreadCount()
returns zero after joining a channel.
3 new error codes which are INVALID_REGULAR_EXPRESSION(400001)
, TOO_MANY_MEMBER_ERROR(400310)
and RPC_RATE_LIMIT_ERROR(400311)
Fixed EkoChannel
collection with the filter EkoChannelFilter.NOT_MEMBER
not contains channel you are banned from.
Eko Messaging SDK 1.1.2
is released.
Fixed EkoChannel
collection with the filter EkoChannelFilter.NOT_MEMBER
contains channel you joined.
Fixed EkoChannel
data not update in real-time.
Eko Messaging SDK 1.1.0
is released.
The parameterless EkoChannelRepository.getChannelCollection()
method now required a single parameter of EkoChannelFilter
.
Delete message
Unread message count
You can create a EkoChannel
collection that contains
EkoChannelFilter.MEMBER
: channels that you have joined.
EkoChannelFilter.NOT_MEMBER
: channels in the system which you haven't joined.
EkoChannelFilter.ALL
: all channels.
Live Reading: Eko Messaging SDK now supports live reading mode. When you are in live reading mode, all new message are marked as read automatically.
EkoChannel.membership().startReading()
: enables live reading mode. Should be called in onResume()
method.
EkoChannel.membership().stopReading()
: disables live reading mode. Should be called in onPause()
method.
EkoMessageRepository.getCount()
is deprecated.
EkoMessageRepository.getCount(channelId)
is deprecated.
Eko Messaging SDK 1.0.2
is released with improved network bandwidth efficiency.
Fixed EkoMessage.getUser()
returns null
instead of EkoUser
the sender of the message.
Eko Messaging SDK 1.0.1
is released with internal changes.
Eko Messaging SDK 1.0.0
is released.
Rate limiting a channel controls the speed of messages that is published to all concurrent clients in the channel
This method is useful when there is a large amount of messages going through the channel, which can make the message stream hard to follow. Setting a rate limit enables the SDK to queue up messages once the amount of message in a specified window
exceeds the defined limit
, allowing a slower stream of messages to be published to the user at the expense of adding more latency (because newer messages will be sent to the queue first and not delivered until all previous queued messages are delivered).
There is an internal limit of 1000 messages that can be queued by the rate limit service, if more than 1000 messages are queued up, the system may skip publishing the older messages in order to make room for newer messages. We believe this is the preferred behavior for users, as users will most likely want to see newer messages in a real-time conversation instead of waiting for a significant amount of time for old messages to be published to them first.
Note that the SDK permanently stores all messages it receives in the system before the rate limit comes into effect: in the case of a large spike of incoming messages, even if a message did not get published to a user in real-time, that user can still scroll up to see message history and see that past message.
The above method enables a rate limit of 5 messages every 60 seconds. Once a user sends more than 5 messages in 60 seconds, messages will be queued on the server and not published to other channel members until 60 seconds have passed.
Note: This feature does not work with Broadcast
and Conversation
channel. Calling reateLimit()
or removeRateLimit()
on these channels will result in an error.
flag and unflag a message
While having moderators surveying your chats is great, it doesn't scale well. A way to overcome this is to let your users do the work for your moderators. By letting users flag other users or specific messages, the work of moderators is significantly reduced and democratized, thus allowing administrators to only respond to issues when deemed critical or absolutely necessary.
To flag a message, call the following method:
To unflag a message, call the following method:
The User can also check if they have previously flagged a message before by calling the following asynchronous method:
If this method has been called before in the current session, the user can also check the cached result on the message payload itself.
Flag and Unflag a channel user
While having moderators surveying your chats is great, this doesn't scale well. A way to overcome this is to let your users do the work for your moderators: by letting users report other users or specific messages, the work of moderators goes from scanning each message in each channel to investigate each user report (to both users and messages) and react only when deemed necessary.
To flag a user, call the following method:
To unflag a user, call the following method:
In order to disable the rate limit, simply call :
In order to flag a message, create an instance of by calling Beware that each is tied to only one specific message.
In order to report a user, create an instance of by calling Beware that each is tied to only one specific user.
The Chat SDK for Web is delivered as an npm module.
Interactions are more fun when you can express yourself! Let users react using emojis, stickers, or thumbs up to messages.
To maximize engagement on the content of your application, you can use reactions on messages, posts, or comments. The reaction is similar to the Facebook Like. While a user can add many reactions to a model, it can only add each reaction one time only.
Each model which can be reacted upon will carry a set of properties useful to display its reactions. You will find:
reactions
: an object containing the name of the reactions as key, and their count as value (ex: { like: 1, love: 1 }
)
reactionCount
: the sum of all the counts for all the reactions
myReactions
: an array containing the current's users reactions
First, simply import the ReactorRepository
and pass in the message you want to react upon.
Then call for addReaction()
and pass along the identifier for your reaction.
Just as you did for adding a reaction, you can call removeReaction()
to remove a reaction.
Both addReaction()
and removeReaction()
methods return a Promise resolving a boolean acknowledging the server's successful response. If necessary, you can use await
to receive the result of those operations.
This page highlights the steps you will need to follow to begin integrating chat messaging into your products
The message payload is always the same regardless of which Development Kit the user is using. Users also have a choice on what type of message they want to send.
Amity supports the sending and receiving of 5 types of messages. They are Text, Image, Audio, File, and Custom.
Amity will automatically optimize the image and when queried, will return the image in small, medium and large sizes. If the image is marked as isFull
on upload, the original size of the image can also be returned.
When an image is uploaded, it is automatically resized into multiple sizing options. The size of the image is determined by its longest dimension (in pixels) with the aspect ratios being unchanged.
The maximum file size of an image cannot exceed 1 GB.
When a user is observing messages, the message will always appear in this format.
Messages are JSON content containers that can weigh up to 100KB and will be synchronized among all channel users in real-time. If a message requires larger binary data (such as when sending files), we recommend to upload the data to another cloud storage service, such as AWS S3, and store the URL to the content in the message data.
In addition the JSON message type, the SDK also provides support for common text and image message types. These additional types are built on top of the standard JSON message layer.
In case of image messages, the SDK freely provides a cloud storage service that will process and store all images uploaded: you don't need to setup and manage a separate cloud storage service for this common case.
All messaging methods are contained in a EkoMessageRepository
class. Before calling any messaging methods, you must ensure to first instantiate a repository instance using the EkoClient
instance you created on setup.
All message sending methods are designed to be robust enough to work under any network conditions. When you send any message, that message will automatically be put into a queue incase of any unforeseen unstable network conditions. Once the SDK reconnects to the server, it will automatically resend all the queued messages.
Additionally, sent messages are always returned in message queries, even before they have been delivered to the server. This provides the user with a fluid messaging flow: when a user sends a message, that sent message will appear in the message stream right away (instead of waiting until it has been confirmed by the server). To check or display the current status of message delivery for your application, use the syncState
property in the message model; for web you should useEkoMessage.getState()
method in the EkoMessage
object.
Initiate the messaging with the following scripts, depending on your platform of choice
To query for a list of all messages in a channel:
This method will return a LiveCollection of all messages in the specified channel. You can observe the LiveCollection in order to update your view whenever you receive new messages.
Since v1.3.0, messages can be organized in threads thanks to the parentId
property.
A message can be the root for a thread. To query the children of a message thread, you can add the parentId
parameter in a message query, along with the filterByParentId
flag.
When creating a message, we can also pass the parentId
to make it appear under a parent.
Users can flag messages and unflag messages that they have flagged using the MessageFlagRepository
class.
To flag a message, call the following method:
To unflag a message, call the following method:
The User can also check if they have previously flagged the message before by calling the following asynchronous method:
If this method has been called before in the current session, the user can also check the cached result on the message payload itself.
A special MessageEditorRepository
class is also provided for you to perform actions on messages you've sent or received. These actions include editing and deleting an existing message, as well as marking a message as being read by you.
To start, first instantiate a MessageEditor
instance with the EkoClient
instance you created on setup, as well as a valid messageId
.
You can only perform edit and delete operations on your own messages. Once the operation is complete, the message's editedAtDate
will be set to the current time. This allows you to provide UI to the user to inform the user of specific messages that has been edited, if needed. An optional completion block can be provided to notify you of operation success.
To mark a message as being read by you, simply call the following method with an optional completion block:
Marking a message as read will also retroactively mark all previous messages as read by you as well. You will only need to call this method once on the latest message.
When a user is banned in a channel, they are removed from a channel and no longer able to participate or observe messages in that channel.
Moderators can ban and unban users. When a user is banned in a channel, they are forcebly removed from channel and may no longer participate or observe messages in that channel. All their previous messages in the channel will also be automatically deleted.
A user that has been banned from a channel can not rejoin the channel until they have been unbanned.
As well as the banning and unbanning of users, admins also have the ability to global ban a user. When a user is globally banned, they can no longer access Amity's network and will be forcebly removed from all their existing channels. All the globally banned user's messages will also be deleted.
The globally banned user can not access Amity's network again until they have been globally unbanned.
Banning users is a more heavy handed moderation method. When a user is banned, all its messages are retroactively deleted, it will be removed from the channel, and it will not be allowed to join the channel again until he is explicitly unbanned.
There is a separate unban call to unban a user:
Note: This feature does not work with Broadcast
and Conversation
channels. Calling banUsers()
or unBanUsers()
on these channels will result in an error.
Flag and Unflag a channel user
While having moderators surveying your chats is great, this doesn't scale well. A way to overcome this is to let your users do the work for your moderators: by letting users report other users or specific messages, the work of moderators goes from scanning each message in each channel to investigate each user report (to both users and messages) and react only when deemed necessary.
To flag a user, call the following method:
To unflag a user, call the following method:
Both of these methods return a promise meaning they can be chained with .then
and .catch
handlers:
Name
Data Type
Description
Attributes
messageId
string
The id of this message
Content
parentId
string
The messageId
of the parent of this message
Content
childrenNumber
integer
The number of messages with parentId
of this message
Content
channelId
string
The name of the channel this message was created in
Content
userId
string
The name of the user this message was created by
Content
type
string
The message type
enum*: text
custom
image
file
tags
Array.<string>
The message tags
Content
data
Object
The message data (any text will be stored in text
key)
text
: Text message
isDeleted
boolean
The message has been marked as deleted
Content
channelSegment
integer
The sequence number of a message in channel
Content
createdAt
date
The date/time the message was created at
Content
updatedAt
date
The date/time the message was updated at
Content
editedAt
date
The date/time the message was edited at
Content
flagCount
integer
The number of users that have flagged this message
Content
hashFlah
Object
A hash for checking internally if this message was flagged by the user
Content
reactions
Object
The reaction data (stored as a reactionName and counter key/value pair)
Example: { like
: 1, dislike
: 2 }
reactionsCount
integer
The total number of reactions on this message
Content
myReactions
Array.<string>
A list of user's reactions on this message
Content
An easy-to-integrate module that delivers high-performance messaging services
From travel-loving retirees for cruise lines to hiking enthusiasts for camping equipment brands, there are groups and individuals everywhere seeking to find others with similar interests. Provide a place for your customers to join communities centered towards your brand and what it represents to boost customer loyalty and retention, build a positive association, as well as allow them to feel a deeper connection to your brand.
Our channels enable developers to implement different types of chat messaging capabilities into their applications easily
Users can create and join channels where they will be able to participate and chat with other users. A channel can support up to 300,000 members and can contain an unlimited number of messages. Any message exchanged in the channels will be pushed to all other members of the channel in real-time.
Amity's Chat SDK supports the creations of 4 types of chat channels. Each type is designed to match a particular use-case for chat channels. Here's a table showing what features each channel offers:
The community channel is our default channel type and can be discovered by all users and admins. It acts as a public chat channel that showcases all of the features that our SDK's have to offer.
Typical use cases:
Team collaboration
Online gaming
Celebrity fan club
Live streaming
Any type of public chat
Live channels offers the ability for users and admins to create channels with exclusive memberships. The live channel is identical to our Community channel in features with the caveat that users will not be able to discover the channel when querying for all channels unless they are already a member of it. However users and admins can still invite other users to join the channel.
Typical use cases:
Healthcare
Project Discussion
Any type of private chat
Community and Live channel types can use our SDK moderation tools:
Message and user flagging
Muting/Unmuting users
Banning/Unbanning users from channel
Profanity filters
Whitelisted URLs
User rate-limiting
All broadcast channels are visible on the Amity Social Cloud Console.
The Broadcast channel is heavily adopted by corporate users who constantly promote or advertise their products, or make the announcement to drive awareness. Unlink other channel types, broadcast channels only allow admin users to send messages from Console, and everyone else in the channel will be under read-only mode.
Since this is a one-way communication channel, a tailored moderation tools are provided as well, for instance, users won't be able to flag message / user in the channel.
Typical use cases:
Marketing & Advertising
School / Government Announcements
Conversation channels are NOT visible on the Amity Social Cloud Console.
The Conversation channel is our solution to 1-on-1 messaging. Unlike the other channel types, a Conversation channel can be created simply by knowing the userId of the user we want to converse with. Users can start conversations with any other user and only they will be able to see their conversation.
There are no moderation tools for Conversation channels, users will be able to converse freely with no oversight!
Typical use cases:
Hospitality
Financial Consultancy
Customer Support
When a user joins a channel, they are able to observe and chat with other users in that channel. They are also automatically considered a member of that channel. The Chat SDK provides the ability to view which users are currently in the channel as well as invite other users to join the channel.
Each channel is identified by a unique channelId
, which is any string that uniquely identifies the channel and is immutable through its lifetime. When creating channels, you can specify your own channelId
, or leave it to Amity's Chat SDK to automatically generate one for you.
It's important to note that, createChannel:
guarantees that the requested channel is a new channel, whereas joinChannel:
will attempt to join an existing channel. If there is a requirement to create a new channel, then use of createChannel:
then call joinChannel:
. Lastly calling getChannel:
only gives you back the channel LiveObject, but it won't make the current user join said channel.
Channel management methods are contained in a EkoChannelRepository
class. Before being able to call any channel method, you must initialize a repository instance using the EkoClient
instance you created during setup:
EkoChannelRepository
provides createChannel()
method to create a new channel. It supports creating of 3 types of channels Community
, Live
and Conversation
. Each channel type has specific builder classes which helps you to create that particular channel. Build your channel information first and then create the particular channel.
The above code creates a channel and notifies you through the observer block. It first instantiates the EkoChannelRepository
, a class that contain all channel related methods. Then it calls createChannel:
to obtain the LiveObject and observe it in order to obtain the final channel model.
The
EkoNotificationToken
returned by theobserve:
is saved inself.channelToken
, a strongly referenced property. This is needed in order to prevent the observe block from being released. You should note that this block can get called multiple times, when the underlying data for the channel updates. If you don't want to get notified, you can callchannelToken.invalidate()
. As soon as the token gets invalidated, observer is automatically removed from that channel.In the case that there is already an existing channel with the same
channelID
, the LiveObject will notify you with anerror
.The
channelId
parameter increateChannel:
can benil
: when this happens, the SDK will generate a uniquechannelId
for this channel, ensuring no unique ID conflicts.3 channel types can be created through SDK i.e
Community
,Live
andConversation
. Creation ofPrivate
andStandard
type has been removed. Creation ofBroadcast
channel type is not supported through the SDK. But for query,channelCollection:
method supports all channel types includingBroadcast
,Private
andStandard
.
The Chat SDK provides a convenient createConversation:
method which creates a conversation channel type. You can use either createChannel
or createConversation
method directly as well.
Conversation channel is unique based on its membership. When creating conversation the system will check if channel with the same membership already exists, if such channel already exists the system will return existing channel instead of creating a new one.
joinChannel:
is an idempotent method, this means it can be called multiple times throughout the lifecycle of the application, and you can expect this method to always return the same channel. Because of this, you can also use joinChannel:
any time you need to fetch a channel, even if you know the user may already be in the channel.
In the case where you'd like to fetch a channel's data without joining, the getChannel:
method can be used:
EkoChannelRepository
provides a way to query list of channels using channelCollection()
method. It returns a EkoCollection
of all the matching channels available. This live collection returned will automatically update and notify you on any channel modifications as well.
SDK provides with 7 builder classes. EkoStandardChannelQueryBuilder
, EkoPrivateChannelQueryBuilder
, EkoByTypesChannelQueryBuilder
, EkoBroadcastChannelQueryBuilder
, EkoConversationChannelQueryBuilder
, EkoCommunityChannelQueryBuilder
and EkoLiveChannelQueryBuilder
. These builder classes should be used to construct a query and then used alongside channelCollection method to fetch list of channels.
Depreciated:
channelsForFilter()
,channelsForFilter(_:includingTags:excludingTags:)
method to query channels is now depreciated. SDK now does not support creation of Private & Standard channels but still supports query usingEkoStandardChannelQueryBuilder
EkoPrivateChannelQueryBuilder
.
If you use a UITableView
or UICollectionView
to display channel list data, the ideal location to reload table data is directly in the observe block of the LiveObject that you are displaying, as shown in the example above.
You can filter channels by various criteria such as includingTags, excludingTags, includeDeleted channels etc. All these filters are available in QueryBuilder classes for channel.
Metadata is a general purpose data store that is automatically synchronized to all the channel members. It is meant as an elegant mechanism to store contextual information about a specific channel. The data can be any number of JSON key value pairs up to 100 kb. Example use cases include:
Conversation title or cover photo
Global conversation settings
Metadata is implemented with last writer wins semantics: multiple mutations by independent users to the metadata object will result in a single stored value. No locking, merging, or other coordination is performed across multiple writes on the data.
To set metadata, call the setMetadataForChannel:
method:
The completion block will be triggered with the outcome of the request. The latest metadata of the channel is always exposed as part of the metadata
property on the channel model.
Every channel contains an optional displayName
property. This property is mainly used to identify the channel in push notifications, but it is also exposed to the application via EkoChannel
object.
You can set a channel's displayName
with the following method:
An optional completion callback is available to inform you on whether the request has succeeded or not.
All participation related methods in a channel falls under a separate EkoChannelParticipation
class. Before calling any participation methods, you must ensure to first instantiate a repository instance using the EkoClient
instance you created on setup and a valid channelId
:
The participation membership provides a list of all members in the given channel as a LiveObject.
You can also get a list of channel members with specific roles, membership types etc. EkoChannelParticipation
class provides membershipsForFilter:
method which accepts filter
, sortBy
and roles
as parameter.
The participation membership also provides classes to add and remove members, as well as removing yourself as a member of the channel (leaving the channel).
The EkoChannelRepository
object exposes an totalUnreadCount
property that reflects the number of messages that the current user has yet to read. This count is the sum of all the unreadCount
channels properties where the user is already a member.
To let the server know when the current user is reading one channel, hence resetting that channel unreadCount
to zero, the participation membership exposes the startReading
and stopReading
methods.
You can call both methods as much you'd like, the SDK takes care of multi-device management: therefore a user can read multiple channels, from one or multiple devices at the same time. In case of an abrupt disconnection (whether because the app was killed, or the internet went down etc.) the SDK backend will automatically call the stopReading
on the users behalf.
EkoChannelModeration
class provides various methods to moderate the users present in any given channel. You can ban/unban/mute users, assign roles or remove it from user.
You can check your permission in channel using hasPermission(permission:forChannel:_:)
method from EkoClient.
Channel Type
Discoverable by
Message sending privileges
Moderation access
Community
All users and admins
Users and admins
All Moderation tools
Live
Only members and admins
Users and admins
All Moderation tools
Broadcast
All users and admins
Admins
Admin Moderation tools
Conversation
Only members
Users
No Moderation tools
In iOS, LiveObjects are represented by the EkoObject
and EkoCollection
classes. EkoObject
represents live updates on one model, while EkoCollection
represents live updates on a collection of models.
Observing live changes to any EkoObject
can be done via a simple observe block:
In this example the block observes the data of the currently authenticated user and prints out the displayName
. The observe block can be called multiple times throughout the lifetime of the application (as long as its associated EkoNotificationToken
is retained in memory):
If the requested object data is stored locally on the device, the block will be called immediately with the local version of the data (this can be verified this through the EkoObject
property dataStatus
).
In parallel, a network request for the latest version of the data is fired, once the network returns the data, the observe block will be called again with the updated data.
Any future changes to the data (whenever the user changes its displayName
on another device, for example) can trigger additional callbacks.
Any UI update logic can be performed within the observe blocks, which will always be called in the main thread: this way, you can ensure that your UI displays the most up-to-date version of the state at all times.
In case you'd like to operate exclusively with fresh data, without using the potentially out-of-date local data, you can make sure to do so by reading the
EkoObject
dataStatus
property, which reflects the status of the callback data, and check that its value is set to fresh.You can also use the
EkoObject
loadingStatus
property to determine the current state of network operations being performed by the LiveObject. This is useful for any UI element that needs to communicate the loading state.
The EkoNotificationToken
is a token that is used to control the lifecycle of a LiveObject. The observeWithBlock
callback will be triggered only if the notificationToken
is retained in memory: once it is released, the observe block will no longer be called, and its memory will be automatically released. Hold a strong reference to any EkoNotificationToken
whose block you would like still to be called.
Beside the
observeWithBlock
method, aobserveOnceWithBlock
method is also available, which will trigger its callback only once, regardless of thedataStatus
of the callback and the associated token retainment (the token still needs to be retained to fire once).To stop receiving
observeWithBlock
updates, release the associatedEkoNotificationToken
or callinvalidate
method on the token itself.
An EkoCollection
instance is given for any queries that return a list of objects. EkoCollection
has the same change observation interface as EkoObject
, but contains a few other helper methods around data access that allows better integration with collection views like UITableView
.
Unlike most databases, EkoCollection
does not return all data in an array. Instead, data are fetched one-by-one using the objectAtIndex:
method. This allows the framework to store most of the actual result on disk, and load them in memory only when absoutely necessary. Additionally, the objectAtIndex:
API fits perfectly into UITableView
's tableView:cellForRowAtIndexPath:
. Together with the count
property, a typical tableView
integration looks like this:
EkoCollection
offers both a nextPage
and previousPage
methods which will trigger a local cache lookup, a network call, and multiple LiveObject updates once new data is returned. After the method call is successful, the number of records returned by EkoCollection
will be increased by the additional number of new records. For the typical use case of infinite scroll, you can call nextPage
directly in the scroll view delegate method:
Lastly, if there is a need to shrink the list of models exposed back to original first page, when passing the EkoCollection
object to a new view for example, you can do so by calling resetPage
into the collection itself.
The Chat SDK for iOS is delivered as a binary .xcframework file
Install: Homebrew
Paste that in a macOS Terminal or Linux shell prompt; see more instruction at https://brew.sh
Install: git-lfs using: brew install git-lfs
Starting from version 4.3, the use of the .xcframework will reduce the required number of installation steps and also support the use of same binary, even when the Xcode version changes. We also include an additional framework as a dependency: Realm.
In order to properly install the SDK, you must make sure to import and link both frameworks. XCFrameworks for both realm & our Chat SDK are bundled together for your convenience, this can be downloaded using the link below:
Drag EkoChat.xcframework
and Realm.xcframework
to your project's Embedded Binaries
. Make sure that Copy items if needed
is selected and click Finish. Also switch the Embed section as Embed & Sign
.
Carthage is a decentralised dependency manager that builds your dependencies and provides you with binary frameworks. To integrate the Amity Chat SDK, add the following line of code to your Cartfile
.
To integrate the Amity Chat SDK into your Xcode project using CocoaPods, specify the following line of code in your Podfile
:
Please check if you have git-lfs installed and clear cocoapod cache before running install again
To clear cache please go to ~/Library/Caches/Cocoapods/ and remove Amity SDK folder - you should be able to run a clean install afterward
If this doesn't work, please do visit the cocoapod Github repo for further resolutions.
Here are the steps to migrate from the previous version of our SDK to the new .xcframework
Remove and unlink EkoChat.framework
and Realm.framework
from your project.
Remove custom Run Script Phase
that is required for the version prior to v4.3. strip-frameworks.sh
is no longer required, since .xcframework
automatically handles the fat binary issue.
Copy and link EkoChat.xcframework
and Realm.xcframework
to your project. And set Embed & Sign
.
Amity Chat SDK allows engineers to add powerful messaging capabilities to their native and web apps, without the hassle of deploying, maintaining any server infrastructure, or writing complicated message synchronization logic.
Our Chat SDK allows users to join channels and send messages, instantly. The messages will be synced up to all users within the same chat channel in real-time. The messages sent through the system can be moderated pre-delivery via an automated custom spam and keyword filter, allowing you to moderate all messages sent manually via the admin panel.
Amity Chat SDK allows you to:
Start a new conversation channel with up to 300,000 concurrent participants
Deliver up to 1 million messages per second for each conversation channel
View read counts for every message
Moderate conversations with user banning, muting, and rate limiting
Assign moderators and admins via a role based permission system
Filter out inappropriate content with automated spam filtering and URL whitelists
Manage connection state and handle offline data automatically
Support multi-device and multi-platform for every user
Our channels enable developers to implement different types of chat messaging capabilities into their applications easily
This page highlights the steps you will need to follow to begin integrating chat messaging into your products
Moderation is an important feature for building a safe community that encourages user participation and engagement
Interactions are more fun when you can express yourself! Let users react using emojis, stickers, or thumbs up to messages.
Push notifications play a central role on your app user engagement
This page contains an overview of all relevant changes made to the Amity Chat SDK modules and the latest version releases
An easy-to-integrate module that delivers high-performance messaging services
From travel-loving retirees for cruise lines to hiking enthusiasts for camping equipment brands, there are groups and individuals everywhere seeking to find others with similar interests. Provide a place for your customers to join communities centered towards your brand and what it represents to boost customer loyalty and retention, build a positive association, as well as allow them to feel a deeper connection to your brand.
Interactions are more fun when you can express yourself! Let users react using emojis, stickers, or thumbs up to messages.
To query for a list of all reactions on the specific message in a channel, one must utilise EkoMessageRepository
. We can observe this the same way as when we observe messages, the only thing difference is you will have to use messageId
as the parameter. The operation will return an instance EkoCollection
of EkoMessageReaction
that contains the reaction name, message id, reactor id and reactor display name of the user who reacted to the message.
This method will return a LiveObject of all reactions of specific message in the specified channel. You can observe the LiveObject in order to update your view whenever you receive new reaction on that message.
For adding a new reaction, we can use EkoMessageReactor
to perform its operation. Initialize the reactor with the client and message and specify the reaction name.
In order to remove a new reaction, we can use EkoMessageReactor
. Initialize the reactor with the client, message and specify the reaction name.
The Chat SDK for Android is delivered via maven repository.
Add the Jitpack repository in your project level build.grade
at the end of repositories:
Add the dependency in your module level build.grade
:
To configure your app to use data binding, enable the dataBinding
build option in your build.gradle
file in the app module, as shown in the following example:
This page contains an overview of all relevant changes made to the Amity Chat SDK modules and the latest version releases
Introduce a completion parameter to registerDeviceWithUserId(:_)
in EkoClient
None
Fixed issue where categories property of community is updated incorrectly when fetching list of community categories.
None
Fix socket connection state that causes feed cannot be loaded
Fix issue where token does not update correctly
Fix issue where collection is not triggered when there is empty result
Fix edited date does changed after the comment get updated
None
Fix issue where custom messages are not parsed correctly
Fix crash when setting up custom avatar for in EkoClient
class.
None
N/A
Add EkoUserNotification
and EkoUserNotificationModule
class for supporting user notification settings
Add EkoCommunityNotification
and EkoCommunityNotificationEvent
class for supporting community notification settings
Add notificationManagerForCommunityId:
method in EkoCommunityRepository
class to provide EkoCommunityNotificationsManager
Add EkoRoleFilter
and EkoRoleFilterType
; class and enum for defining what roles would be affected by notification setting
Add displayName
option in EkoCommunitySortOption
enum to sort list of communities alphabetically.
Fix issue where dataStatus
for EkoObject
was not reflected correctly.
Add EkoCommunityFeedSortOption
enum.
sortBy
parameter type is changed to EkoCommunityFeedSortOption
for getCommunityFeed:
method in EkoFeedRepository
class.
Add EkoCommunityMembershipSortOption
enum.
sortBy
parameter type is changed to EkoCommunityMembershipSortOption
for getMemberships:
method in EkoCommunityParticipation
class.
Note: If you have been using enum in short form i.e
.displayName
, these breaking changes would not cause any effect.
Fix issue where post was not getting removed from global feed when deleted
Fix issue where non members could search for private communities locally
Comment in error state can be hard deleted by deleteComment()
api in EkoCommentEditor
Fix issue where deleted comment was being shown from cache
SDK is now distributed as xcframework. .dsym files are also included inside the framework. Please refer to installation docs for more info
Add new message type i.e audio. Please refer to Message documentation
EkoMediaRepository
has been depreciated. Please migrate to downloadImage:
& downloadFile:
method present in EkoMessageRepository
.
Add roles
properties in EkoCommunityMembership
class
Add hasPermission:
methods in EkoClient to check permissions for current user.
New Channel Types: Community
& Live
. Channel type Private
and Standard
has been removed. Please refer to channel documentation for more details
Older createChannel:
methods has been removed. Use new method with builder instead.
type
parameter is removed from joinChannel
method.
Older createConversation:
method has been removed. Use new createChannel
or new method with builder instead.
Add EkoCommentRepository, EkoCommentEditor and EkoCommentFlagger class. Complete documentations are on Comment section.
Add EkoReactionRepository model support reactions.
Add EkoReaction class to provide reaction info.
Support Xcode 11.7
Fix bug on membership
property on EkoChannelUserModel
which has wrong result
Fix bug on isEdited
property on EkoMessage
which has an unconsistent result
No need to add zlib
integration anymore
Support Cocoapod and Carthage installation
Resolve crash when trying to access editedAt
timestamp for message
Add isEdited
property on EkoMessage
to check if message has been edited
Resolve allow display name nil
and empty string on registerDevice
Support Xcode 11.6
Resolve bug on conversation channel filtering
Add getAllUsersSortedBy
method to fetch list of users in EkoUserRepository
.
Add searchUser
method to search list of users with their display name in EkoUserRepository
.
Add new UI for showing list of Users.
Refactor UI to show two tabs, one for list of users and another for channels/chat.
Support getMessage
by messageId
from EkoMessageRepository
using getMessage(messageId)
function.
Add new 'UI' for select the channel type for query.
Add new 'UI' for re-select the channel type on More
page.
Fix 'UI' for create new channel type.
Support query
all channel
types which is Standard
, Private
, Broadcast
, Conversation
, and combination.
Support creating 2 channel
types which is Standard
and Private
.
New API for creating a conversation
is embedded into EkoChannelRepository
which is createConversation
.
Add new function for retrieving the channelCollection
object by query
it through new Builder
pattern. Consists of 5 type of Builder
which is EkoStandardChannelQueryBuilder
, EkoPrivateChannelQueryBuilder
, EkoByTypesChannelQueryBuilder
, EkoBroadcastChannelQueryBuilder
and EkoConversationChannelQueryBuilder
. Each builder has their own configuration settings based on their requirements.
New getter of channelCollection
on EkoChannelRepository
that will return the EkoChannelQueryBuilder
following by the channel type then call query
method, observe the changes using EkoNotificationToken
.
Support private
and standard
channel type for createChannel
.
New enum for creation which is EkoChannelCreateType
.
New method helper inside EkoChannel
for conversion between EkoChannelCreateType
into EkoChannelType
if needed.
channelsForFilter
and channelsForFilter:includingTags:excludingTags
is deprecated function.
joinChannel
only works for join existing channel, it doesn't work for join while creating a channel simultaneously.
Support getMessage
by messageId
from EkoMessageRepository
using getMessage(messageId)
function.
Add new 'Like' UI on each message for react of Like and Unlike to test the optimistic UI.
Change implementation of EkoMessageReactor
so it able to retain the process of previous reactor.
Add optimistic UI on the Reaction
implementation.
Give safeguard for RLMRealm
access of the properties in each object.
Protect setDisplayName
of EkoClient
to be able sent with empty userId
.
Set EkoObject
to be nil in any case if model not exist or invalidated.
Protect joinChannel
parameters attribute with nonnull
protection to guarantee the channelId
is not null
value.
Make sure if the realmModel
is invalidated
then it changes the dataStatus
to be notExist
and set the EkoObject
to be nil
and continue the network request process.
Add new 'Setting' section in the settings page for updating the user meta data.
Add new 'User Meta data' section inside about page for showing the user meta data.
Add setUserMetadata
function inside EkoClient
object for updating the current user meta data.
Fix crash that happens if show reaction with empty display name.
Fix reactions model is not auto removed when someone removes the reaction.
Fix and enhance query system to clear reactions cache on first query.
Fix handle case when display name is empty.
Add support for Xcode 11.3.1.
Support query all reactions.
New method for observing all reaction which is allMessageReactionsWithMessageId
within a message on EkoMessageRepository
for retrieving all of reactions inside a specific message.
New properties on EkoMessageReaction
which is reactorId
and also reactorDisplayName
for getting the user id of the reactor along with the display name.
Add action sheet for displaying all of reactions the single message.
Support add and remove reactions.
New class EkoMessageReaction
and EkoMessageReactor
.
Add Message reaction feature, a reaction can be added or removed from a message with EkoMessageReactor
.
New properties on EkoMessage
which is reactions
data and also reactionsCount
and myReactions
.
Add action sheet for adding and removing reactions on the message.
Add action sheet for displaying all of own reactions on the message.
Change update data endpoint.
Support update custom message.
Sample App Changes
Add action sheet for editing or deleting the message by clicking on the selected message cell.
Support Custom message type:
A message of this type can be created with a Dictionary
data that following a JSON
format that the developers are responsible to parse it by themselves.
This object is included in the data
property of the message.
Support File message type:
A message of this type can be created with an NSData
of the choosen file. File could not exceed than 1 GB.
Add upload file button to choose file from the device.
New file cell view for the file message type.
Parse custom message from server into a text cell.
Add new custom view for sending the custom message, limit to only sent a key and value as a String
.
Fix handling of deleted images
Add support for Xcode 11 and Swift 5.1
Message tagging support:
Messages can now be sent along with customized tags.
Messages can now be filtered by tags (both including and excluding).
Tags can also be set on any message.
Every message has a new tags
property.
Message sorting support:
Messages can now be fetched from the oldest first, or the newest first.
Message parenting support:
Messages can now be connected on creation by passing a new optional parentId
value.
Note how a message child can also become a parent itself, without any limit.
The parentId
must be passed on the child message creation and cannot be changed afterwards.
Every message has a new optional parentId
and childrenNumber
property.
Improve background transaction performances
Remove AFNetworking dependency
Memory improvements
Enhance code documentation
Add full message tags support
Add full message order support
Add full message parenting support
Add example of message parenting usage with a special comment screen:
join a channel with tag “comments
” to see the alternative experience
Enhance api key management
Display push notifications even when app is in foreground
Reset badge count upon opening the app
Enhance project structure
EkoMessageRepository
replaces the function messages(withChannelId:)
with messages(withChannelId:reverse:)
, along with many other new options such as messages(withChannelId:includingTags:excludingTags:reverse:)
, messages(withChannelId:filterByParentId:parentId:reverse:)
.
Be aware that all the functions above are convenience function to the complete messages(withChannelId:includingTags:excludingTags:filterByParentId:parentId:reverse:)
function.
Add Push Notification toggles:
users can now choose to mute selected channels or stop receiving notifications completely from any device.
The new settings, documented in the Notifications section, are per user, not per single device.
Adopt new push notification toggles.
Refactor various settings in new screens throughout the app.
Add Push Notification feature:
developers can call register and unregister for push notification directly from the EkoClient
instance. Read more about the feature in the new Notifications section.
Several internal performance and memory enhancements
Add notifications support (note: your implementation will work with Eko Notifications only in Production, not in sandbox/development)
Add new GlobalBanError
:
when a user is banned globally is automatically unregistered and the EkoChat sdk will be on a clean state. This event is sent to the EkoClient
's clientErrorDelegate
EkoChannel
has a new lastActivity
property
Fix register/unregister issue:
you can now use the same EkoClient to log in and log out multiple times with different users.
Improve documentation
Add possibility to login/logout with different users
ChannelListTableViewController
now displays channels types
Add possibility to choose channel type when creating a new channel
Several minor improvements everywhere
EkoChannelRepository
replaces the function channelsForFilter(:tags:)
with channelsForFilter(:includingTags:excludingTags:)
internal Realm objects are no longer exposed:
from this version there's no longer need for migrations when upgrading the SDK
actively purging Channel Memberships when new data comes from the server:
a new EkoChannelMembership
collection observation is needed in order to to trigger this
update channel filtering functionality with both including and excluding tags
remove channel videos
improve set channel tags UI/UX
improve MembershipListTableViewController
improve EkoMessagesTableViewController
EkoChannelRepository
replaces the function channelsForFilter(:tags:)
with channelsForFilter(:includingTags:excludingTags:)
remove markReadWithCompletion
function from EkoMessageEditor
. Use EkoChannelParticipation
start/stop reading functions instead
change channelsForFilter
behaviour:
a channel is now matched when it contains ANY tag listed in includingTags
, and contains NONE of the tags listed in excludingTags
. Previously a channel would match only if it contained ALL the listed tags. If you would like the old behaviour, please create your own filter on top of this method.
EkoChannelMembership
now behaves correctly
add Channel Membership List View
multiple minor improvements
Xcode 10.2 and Swift 5 support
Xcode 10.1 and iOS 12.1 SDK support
add isFlagByMeWithCompletion:
method in both EkoUserFlagger
and EkoMessageFlagger
EkoUserFlagger
and EkoMessageFlagger
now require, respectively, a EkoUser
and a EkoMessage
on initialisation
improve flag feature
add back iOS 9 support
new Flag feature:
flags are reported to the Admin panel for moderator to see
EkoMessage
and EkoUser
expose a new NSUInteger
flagCount
property
Introducing EkoMessageFlagger
and EkoUserFlagger
objects, both of which have two methods:
flagWithCompletion:
unflagWithCompletion:
EkoChannel
's tags
property is now indexed (which results in slower writes, bigger realm database, and much faster searches)
remove EkoMessage
's EkoMessageEditor
shortcut: this way the EkoMessage is a pure model. If you'd like this feature back, please write your own extension/category/wrapper around it.
Add Flag feature in Sample App
remove completion blocks from EkoChannelParticipation
's start/stop reading methods
EkoChannelRepository
createChannel
requires a new tags
parameter (read the below for more info)
EkoChannelRepository
channelsForFilter
requires a new tags
parameter (read the below for more info)
automatically call startRead
upon re-gaining connection with the server if the connection was ever lost (the SDK will keep track of the channels currently being read until the app is killed)
improve Realm migration logic
introducing EkoChannel
's tags
property:
this property is an optional array of strings that the developer can use for whatever purpose.
Via the EkoChannelRepository
you can now:
create a channel with tags via the createChannel:displayName:type:metadata:users:
method
query/filter channels by tags via the channelsForFilter:tags:
method
set tags on existing channels (each call will overwrite the previous channels tags) via the setTagsForChannel:tags:completion:
method
improve channels cleanup on startup: at every startup, the data of channels where the user is not a member is deleted
internal fixes and enhancements
implement channel tags usage in sample app
implement channels filtering in sample app
Xcode 10 support
add possibility to get channels based on the user membership (all channels, channels where user is member, channels where user is not a member) via the EkoChannelRepository
's channelsForFilter:
add membership
property in EkoChannelMembership
object: the possible values are member
, none
(not member), and banned
;
expose the device user membership
above also in the associated EkoChannel
object via the new currentUserMembership
property;
expose totalUnreadCount
in the EkoChannelRepository
new live reading feature:
every user can now start and stop reading a channel (via the EkoChannelParticipation
's startReadingWithCompletion
/stopReadingWithCompletion
methods), this will automatically update the unread count for said channel when receiving new messages for that channel.
implement unread count
, both total and per channel, and membership type
usage in sample app
internal fixes and enhancements
Internal changes (for gathering statistics on sdk version usage)
To get started using the SDK, data binding is required as a mandatory dependency. You need to download the library from the Support Repository in the Android SDK manager. For more information, see .
Initial release
Currently, Android does not support Live-Objects as such, we use a protocol that follows ReactiveX for Kotlin and Java related data streams.
You can find out more information here; https://github.com/ReactiveX/RxKotlin
Interactions are more fun when you can express yourself! Let users react using emojis, stickers, or thumbs up to messages.
There are 3 Reaction related methods on EkoMessage
:
1. getReactionCount()
returns Int
, the total reaction count on the message.
2. getMyReactions()
returns List<String>
, a collection of reactions that have been added by the active user.
3. getReactions()
returns EkoReactionMap
, an extension of Map<String, Int>
of reaction name and its count.
You can choose to add/remove a reaction to/from a message by calling react()
method on EkoMessage
To query for a list of all reactions on a message:
This method will return a Flowable<PagedList<EkoReaction>>
of all reactions in the specified message.
Push notifications play a central role on your app user engagement.
With this solution live events are sent from Amity's servers to your servers: once an event lands on your server, you have full power and control to do whatever you feel is best with each notification; including editing/removing/stopping the notification before it reaches your users devices.
In this scenario there's no iOS SDK involvement needed, the whole notification process is managed on your end.
With this solution the notifications will be triggered and delivered to your users directly by Amity's servers. There's nothing that the iOS client has to do in order to display the notification to your users. Amity's servers will prepare for you a notification that can be directly displayed to the user as and when it's received.
As Amity's servers are responsible for choosing the content of the push notification, you can expect your users to receive the following notifications for different kind of events:
Event: New channel has been created and the user has been added among other members. Push Notification Title: %s
(%s
= New Channel display name) Push Notification Body: You're now member of %s!
(%s
= New Channel display name)
Event: A new user has joined a channel. Push Notification Title: %s
(%s
= user display name) Push Notification Body: %1s has joined %2s
(%1s
= user display name, %2s
= channel display name)
Event: A new message has been received in a channel where the user is already a member. Push Notification Title: %1s (%2s)
(%1s
= user display name, %2s
= channel display name) Push Notification Body: %s
(%s
= message text body if text message, Image Message
if image message, Special message
otherwise)
A new push notification will be sent to a specific user when:
A new message is sent in a channel of the user who is already an existing member of it.
A new channel is created and the user is among the listed members of the channel on creation.
A new member joins a channel of the user who is already an existing member of it.
Registering your app for push notification will require a registered EkoClient
instance (necessary to know which user is associated with this device) and a push notification token.
Amity's Development Kit does not manage:
user-facing requests for push notifications and authorizations
the creation and refreshing of push notification tokens
It's up to your app to take those steps and pass the notification token to the SDK.
We recommend to observe the completion block outcome to assure of a successful registration.
If the device was previously registered with this or another user, the previous registration is invalidated as soon as this new request is received, which means that the device will always receive notifications of up to one user.
Unlike the registration, unregistering for push does not require the EkoClient
instance to be associated with any user, therefore you can unregister the device from receiving push notifications as soon as the EkoClient
has been initialized with a valid API key.
The unregistration allows to pass an optional userId
:
if a valid userId
is passed, Amity's backend will stop sending push notifications to this device only if the currently active push notification associated with this device is also associated with that user. No action is taken otherwise.
if no userId
is passed, Amity's backend will stop sending push notifications to this device.
You can register and unregister as many times as you'd like, however please remember that we use the "Last write wins" strategy.
The SDK has three levels of notifications and in order for it to be sent, a notification has to pass throughout all three levels.
Network Level: (via Admin Panel) turning off notifications at this level effectively disable push notifications altogether for all of your customers.
User Level: (via client) A user can choose to enable/disable the notifications that it receives on the device (this is an absolute option: enable all or disable all). Please note that this setting is per user, not per device: regardless of which device sets this toggle, the new preference will take effect in all the devices where the user is logged in.
Channel Level: (via client) A user can choose to enable/disable notifications for a specific channel (where is member of). Again, this preference is per user, not per device.
In order to get and set the user level push notifications preference, we use the object EkoUserNotificationsManager
, obtained from the current EkoClient
:
For channel preferences, we use the ChannelLevelPushNotificationManager
instead, obtained via an instance of EkoChannelRepository
:
Swift
Our channels enable developers to implement different types of chat messaging capabilities into their applications easily
Users can create and join channels where they will be able to participate and chat with other users. A channel can support up to 300,000 members and can contain an unlimited number of messages. Any message exchanged in the channels will be pushed to all other members of the channel in real-time.
Amity's Chat SDK supports the creations of 4 types of chat channels. Each type is designed to match a particular use-case for chat channels. Here's a table showing what features each channel offers:
The community channel is our default channel type and can be discovered by all users and admins. It acts as a public chat channel that showcases all of the features that our SDK's have to offer.
Typical use cases:
Team collaboration
Online gaming
Celebrity fan club
Live streaming
Any type of public chat
Live channels offers the ability for users and admins to create channels with exclusive memberships. The live channel is identical to our Community channel in features with the caveat that users will not be able to discover the channel when querying for all channels unless they are already a member of it. However users and admins can still invite other users to join the channel.
Typical use cases:
Healthcare
Project Discussion
Any type of private chat
Community and Live channel types can use our SDK moderation tools:
Message and user flagging
Muting/Unmuting users
Banning/Unbanning users from channel
Profanity filters
Whitelisted URLs
User rate-limiting
All broadcast channels are visible on the Amity Social Cloud Console.
The Broadcast channel is heavily adopted by corporate users who constantly promote or advertise their products, or make the announcement to drive awareness. Unlink other channel types, broadcast channels only allow admin users to send messages from Console, and everyone else in the channel will be under read-only mode.
Since this is a one-way communication channel, a tailored moderation tools are provided as well, for instance, users won't be able to flag message / user in the channel.
Typical use cases:
Marketing & Advertising
School / Government Announcements
Conversation channels are NOT visible on the Amity Social Cloud Console.
The Conversation channel is our solution to 1-on-1 messaging. Unlike the other channel types, a Conversation channel can be created simply by knowing the userId of the user we want to converse with. Users can start conversations with any other user and only they will be able to see their conversation.
There are no moderation tools for Conversation channels, users will be able to converse freely with no oversight!
Typical use cases:
Hospitality
Financial Consultancy
Customer Support
When a user joins a channel, they are able to observe and chat with other users in that channel. They are also automatically considered a member of that channel. The Chat SDK provides the ability to view which users are currently in the channel as well as invite other users to join the channel.
Each channel is identified by a unique channelId
, which is any string that uniquely identifies the channel and is immutable through its lifetime. When creating channels, you can specify your own channelId
, or leave it to Amity to automatically generate one for you.
There are 4 channel types 1. Community: a channel that is discoverable by all users. 2. Live: a channel that is discoverable only if user is already added as a member. 3. Broadcast: a channel that limits message creation to only Admin user. Message can only be created from Admin panel. 4. Conversation: a one-to-one chat that once created will not be available on Admin panel.
There are three ways of obtaining an EkoChannel
object: via create, join, or get methods. EkoChannel
management methods are all contained in the EkoChannelRepository
class. To get an instance of EkoChannelRepository
:
The SDK provides 2 typical ways of channel creation.
Channel creation with specific channelId.
Channel creation with auto-generation of channelId.
The channel creation API guarantees that the requested channel is a new channel. If the channel already exists, the error will be an EkoException
with code 400900
The createChannel()
method initiates channel creation method chain and let you choose which channel type to be created.
To let SDK handle channelId generation, uses withDisplayName()
method to skip channelId specification.
Channel of type Conversation
can also be created with createChannel()
method chain. However, the channelId is always being generated by SDK.
To create a conversation channel with a user, pass the user's userId to withUserId()
method.
Conversation channel is unique based on its membership. When creating conversation the system will check if channel with the same membership already exists, if such channel already exists the system will return existing channel instead of creating a new one.
The joinChannel()
method will add the active user as a member of the channel.
This API can be called as many time as needed. If the channel has already been joined, a "success" result will be returned, ie., going into doOnSuccess{}
block.
In the case where you only want to fetch a channel's data without joining, you can use the getChannel()
method:
The EkoChannelRepository
provides the getChannelCollection()
method which initiates channel query method chain. The query returns Flowable<PagedList<EkoChannel>>
representing all matching channels available.
the filter()
method lets you filter channels based on the current user membership status
the includingTags()
and excludingTags()
methods let you filter channels based on the tags set (or not set) in each channel
Metadata is a general purpose data store that is automatically synchronized to all users of a channel. It is designed to store contextual information about a specific channel. The metadata is a JSON object which can store any number of JSON key value pairs up to 100 kb. Example use cases include:
Conversation title or cover photo
Global conversation settings
Metadata is implemented with last writer wins semantics on the entire store. This means that multiple mutations by independent users to the metadata object will result in a single stored value. The metadata object set by last user override any previous values. No locking, merging, or other coordination is performed across participants.
To set metadata, simply call the following method:
Every channel contains an optional displayName
field. This field is mainly used to identify the channel in push notifications, but it is also exposed to the application via EkoChannel
object.
You can set a channel's displayName
with the following methods:
All participation related methods in a channel falls under a separate EkoChannelParticipation
model. You can access EkoChannelParticipation
from EkoChannelRepository.membership()
method as well as from EkoChannel.membership()
method.
The EkoChannelParticipation
provides a list of members in the given channel
You can add and remove members, as well as removing yourself as a member of a channel (leaving the channel) via EkoChannelParticipation
model should you have appropriate privileges.
Creator of the channel can add and remove the role of user via EkoChannelModeration
.
The EkoChannelParticipation
provides a list of members by role in the given channel.
You can check your permission in channel by sending EkoPermission enums to EkoClient.hasPermission(:ekoPermission)
.
The EkoChannelRepository
provides getTotalUnreadCount()
method. It's giving the flowable of the number of messages that the current user has yet to read. This count is the sum of all the unreadCount
channels properties where the user is member of.
To let the server know when the current user is reading one channel, hence resetting that channel unreadCount
to zero, the participation membership exposes the EkoChannelParticipation.startReading()
and EkoChannelParticipation.stopReading()
methods.
You can call both methods as much as you want, the SDK takes care of multi-device management: therefore a user can read multiple channels, from one or multiple devices at once. In case of an abrupt disconnection (whether because the app was killed, or the internet went down etc) the SDK backend will automatically call the EkoChannelParticipation.stopReading()
on the user behalf.
This page highlights the steps you will need to follow to begin integrating chat messaging into your products
The message payload is always the same regardless of which Development Kit the user is using. Users also have a choice on what type of message they want to send.
Amity supports the sending and receiving of 5 types of messages. They are Text, Image, Audio, File, and Custom.
Amity will automatically optimize the image and when queried, will return the image in small, medium and large sizes. If the image is marked as isFull
on upload, the original size of the image can also be returned.
When an image is uploaded, it is automatically resized into multiple sizing options. The size of the image is determined by its longest dimension (in pixels) with the aspect ratios being unchanged.
The maximum file size of an image cannot exceed 1 GB.
When a user is observing messages, the message will always appear in this format.
Messages are JSON content containers that can weigh up to 100KB and will be synchronized among all channel users in real-time. If a message requires larger binary data (such as when sending files), we recommend to upload the data to another cloud storage service, such as AWS S3, and store the URL to the content in the message data.
In addition the JSON message type, the SDK also provides support for common text and image message types. These additional types are built on top of the standard JSON message layer.
In case of image messages, the SDK freely provides a cloud storage service that will process and store all images uploaded: you don't need to setup and manage a separate cloud storage service for this common case.
All messaging methods are contained in a EkoMessageRepository
class. Before calling any messaging methods, you must ensure to first instantiate a repository instance using the EkoClient
instance you created on setup.
All message sending methods are designed to be robust enough to work under any network conditions. When you send any message, that message will automatically be put into a queue incase of any unforeseen unstable network conditions. Once the SDK reconnects to the server, it will automatically resend all the queued messages.
Additionally, sent messages are always returned in message queries, even before they have been delivered to the server. This provides the user with a fluid messaging flow: when a user sends a message, that sent message will appear in the message stream right away (instead of waiting until it has been confirmed by the server). To check or display the current status of message delivery for your application, use the syncState
property in the message model; for web you should useEkoMessage.getState()
method in the EkoMessage
object.
Initiate the messaging with the following scripts, depending on your platform of choice
To send an image message, you must pass in a valid image URL. The SDK will automatically send it to the server. You can also pass in an optional caption as part of the message.
To send an image in original size, set optional isFullImage()
to true. Note: File size is limited to 1 GB
To send a file message, you must pass in a valid file URL. The SDK will automatically send it to the server. You can also pass in an optional caption as part of the message.
Note: File size is limited to 1 GB
With a custom message, you can send a JsonObect
of your choice as part of the message.
To comment on a message, specify the messageId with parentId()
method
To query for a list of all messages in a channel:
This method will return all messages in the specified channel as Flowable<PagedList<EkoMessage>>
While the SDK will always return messages in chronological order, developers can ask for the messages to be returned starting from the oldest first, or the newest first.
On a typical messaging application, the messages are fetched from the latest (newest) first, and then more older messages are explored. (When stack from end is set to true, the list fills its content starting from the bottom of the view)
There are other situations where fetching the oldest messages is preferred, for example for archiving purposes or in community forums. (When stack from end is set to false, the list fills its content starting from the top of the view)
Note: Please make sure that stackFromEnd
using for obtain MessageCollection is the same as stackFromEnd
of RecyclerView's LayoutManager. Otherwise it may cause jumping issue.
Like channels, we also have various ways to obtain messages that only match specific criteria:
the includingTags
and excludingTags
parameters let you filter messages based on the tags set (or not set) in each message
the parentId
parameter lets you filter messages by their relationship:
when no parentId
is passed, any message will match.
when null parentId
is passed, query for all messages without a parent.
when non-null parentId
is passed: query for all messages with the parentId
as parent.
In the case where you only want to fetch an individual message from a channel, you can use the getMessage()
method:
To get an image url from EkoMessage
:
Calling getUrl()
without specifying image size returns a url of a medium-size image.
Please use the appropriate image size depending on your use-case in order to save bandwidth.
SMALL
is used for image thumbnails, with a maximum image size of 160 pixels per dimension. For example, this should be used for small previews in an image gallery that displays a large amount of images in a grid.
MEDIUM
is used for standard image display, with a maximum image size of 600 pixels per dimension.
LARGE
is used for full screen image display, with a maximum image size of 1500 pixels per dimension.
FULL
is used to get the original image. This size is only valid if the image is uploaded with the method isFullImage()
set to true
. If a FULL
sized image is not available, a LARGE
sized image will be returned instead.
The image is protected by access token. In order to view an image, the http request for that image needs to be authenticated.
To integrate with Glide and OkHttp3:
Ensure that you have the following gradle dependencies where glideVersion
is the latest Glide version:
Integrate Glide with Eko's authentication
i. If you don't have custom AppGlideModule
defined, just add the following class:
ii. If you already have Glide OkHttp3 integration add OkHttp Interceptor using OkHttpClient.Builder.addNetworkInterceptor() method:
To render image with Glide
To integrate with Picasso and OkHttp3:
Ensure that you have the following gradle dependencies where picassoVersion
is 2.7 or above. For picassoVersion
below, you may need a Downloader extension.
Integrate Picasso with Eko's authentication
i. Create an instance of OkHttpClient
with the implementation provided by the SDK and pass it to Picasso's builder.
ii. If you already have your own implementation of OkHttpClient
, add OkHttp Interceptor using OkHttpClient.Builder.addNetworkInterceptor() method:
To render image with Picasso
To get file url and file name from EkoMessage
:
The file is protected by access token. In order to retrieve a file, the http request for that file needs to be authenticated. To integrate with OkHttp3:
Create an instance of OkHttpClient
with the implementation provided by the SDK.
If you already have your own implementation of OkHttpClient
, add OkHttp Interceptor using OkHttpClient.Builder.addNetworkInterceptor() method:
To get customedJsonObject
from EkoMessage
You can only perform edit and delete operations on messages you've sent. Once the operation is complete, the message's editedAt
will be set to the current time. This allows you to provide UI to the user to inform the user of specific messages that has been edited, if needed.
Currently, the Chat SDK has only 2 editable data types, TEXT
and CUSTOM
To delete a message, simply call delete()
on EkoMessage
There are 3 Reaction related methods on EkoMessage
:
1. getReactionCount()
returns Int
, the total reaction count on the message.
2. getMyReactions()
returns List<String>
, a collection of reactions that has been added by the active user.
3. getReactions()
returns EkoReactionMap
, an extension of Map<String, Int>
of reaction name and its count.
You can choose to add/remove a reaction to/from a message using calling react()
method on EkoMessage
To query for a list of all reactions on a message:
This method will return a Flowable<PagedList<EkoReaction>>
of all reactions in the specified message.
Amity SDK's do not store or manage any user data. This means that you do not have to import or migrate existing user profiles into the system, user management should be handled by your application code. Instead, every user is simply represented by a unique userID
, which can be any string that uniquely identifies the user and is immutable throughout its lifetime.
A database primary key would make an ideal
userID
. Conversely, something like username or emails is not recommended as those values may change overtime.
If you wish to assign additional permissions for a user, for example moderation privileges or different sending limits, you can provide an array of roles to assign to this user. Roles are defined in the admin panel and can be tied to an unlimited number of users. Once again, Amity does not store or manage any user data, which means you do not have to import or migrate existing users into the system. It also means that Amity cannot provide user management functionalities like lists of users, or limit actions of certain users (e.g. user permissions). Instead, these functionalities should be handled by the rest of your application's capabilities and your server.
Though the SDK does not store and should not be responsible for the handling User profile data for your application; We do provide tools to make some surface-level queries and searches for existing user accounts. With the help of our EkoUserRepository
class, you would be able to list all the users, search for list of users whose display name matches your search query and get EkoUser
object from user id.
Each EkoUser
consists of a userId
and displayName
. The userId
is immutable once the account is created, however the displayName
can be updated at all times.
To get EkoUserRepository
instance
EkoUserRepository
provides a convenient method getAllUsers()
to fetch all users. You can observe for changes in collection, similar to message or channel. The method accepts EkoUserSortOption
as an optional parameter. The list can be sorted by displayName, firstCreated or lastCreated.
EkoUserRepository
provides searchUserByDisplayName()
method which allows you to query for users using their display name. It provides you with a LiveCollection of EkoUser
whose display name matches with your search query. EkoUserSortOption
is an optional parameter.
The code above will provide you with the list of users which matches with display name "John".
has 3 enums type 1. EkoUserSortOption.DISPLAYNAME
Sort by displayName 2. EkoUserSortOption.FIRST_CREATED
Sort by firstCreated 3. EkoUserSortOption.LAST_CREATED
Sort by lastCreated
An easy-to-integrate module that delivers high-performance messaging services
From travel-loving retirees for cruise lines to hiking enthusiasts for camping equipment brands, there are groups and individuals everywhere seeking to find others with similar interests. Provide a place for your customers to join communities centered towards your brand and what it represents to boost customer loyalty and retention, build a positive association, as well as allow them to feel a deeper connection to your brand.
This section outlines how you can set-up your project for success and begin using our Chat SDK for Web applications
Before using the Chat SDK, you will need to create a new SDK instance with your API key. Please find your account API key via the Admin Panel. If you have trouble finding this, you can send our support team an email at developer@amity.co
In order to use any Chat SDK feature, you must first register the current device with an userId
. A registered device will be tied to the registered userId
until the device is either proactively unregistered, or until the device has been inactive for over 90 days. A registered device will receive all the events messages belonging to the tied user.
An optional displayName
can be provided, which will be used in standard push notifications (related to user's actions, such as when the new message is sent).
The
displayName
is set only on the first time the device is registered, please follow your platforms necessary directions if you would like to rename this to something else.
When the user logs out, you should explicitly unregister the user from the SDK as well. This prevents the current device from receiving unnecessary and/or restricted data.
Each user can be registered, at the same time, to an unlimited number of devices. Amity's Chat SDK will automatically synchronize the user data across all registered devices. We will also automatically unregister any device that has not been connected to the server for more than 90 days.
When a device is unregistered due to inactivity, the SDK data on the device will be reset. You will need to re-register this device in order to connect to server again.
If you have any logic or UI around the connection status, you can observe the connectionStatus
property on the EkoClient
instance.
Since the Chat SDK automatically manages the network connection and queue up any requests in cases of bad connection, there should be little need to attach additional logic to this status. However the user may want to know the exact network status to determine if their actions will be performed in real-time, therefore this status is exposed.
You can also be notified about connectionStatus
changes via the connectionStatusChanged
event.
Our Sample app adopts an open source framework that highlights how Amity Social Cloud SDK's can be implemented into application builds pragmatically.
With real life use-cases, we guide you through ways you can get started with building stellar applications for yourself and your clients and their users
When an error is returned as a result of an action from your side (e.g. trying to join a channel), the action can considered complete, and the SDK will not execute any additional logic.
We recommend you to always handle these errors in a production app by gracefully disabling messaging functionality in the event of an error.
All data returned by the SDK are wrapped in the SDK's LiveObject API. The LiveObject API allows you to easily retrieve the queried data asynchronously, as well as subscribe to any new changes to the data.
Observing live changes to any object queries can be done by observing the dataUpdated
event on the LiveObject:
In this example the block observes the data of the currently authenticated user and prints out the displayName
. The observe block can be called multiple times throughout the lifetime of the application:
If the requested object data is stored locally on the device, the block will be called immediately with the local version of the data (you can verify this through the dataStatus
property).
In parallel, a network request for the latest version of the data is fired. Once the network returns the data, the observe block will be called again with the updated data.
Any future changes to the data (whenever the user changes its displayName
on another device, for example) can trigger additional callbacks.
We recommend you to always call removeAllListeners()
whenever you are done observing event to avoid any unnecessary callbacks.
The data provided by LiveObject is directly accessible via the model
property. The model
property is always kept up to date with the latest state changes; every time when dataUpdated
event is fired, the model
property has already been updated.
If in your UI you want to exclusively display fresh data (without using the potientially out-of-date local data), you can do so by reading the object's dataStatus
property, which reflects the status of the callback data, and check that its value is set to fresh.
You can also use the object's loadingStatus
property to determine the current state of network operations being performed by the LiveObject. This is useful for any UI element that needs to provide the loading state.
The LiveObject can also emit events for updates for dataStatus
as well as loadingStatus
. As with other events, please make sure to call removeAllListeners()
when you are done observing changes to these values in order to prevent memory leaks.
The LiveObject updates statuses and data in strict order and emits related events accordingly when an instance is created. Few different cases might occurs when you create a LiveObject instance:
Initial values:
loadingStatus = EkoLoadingStatus.Loading
dataStatus = EkoDataStatus.NotExist
model = undefined
Process received data:
emits loadingStatusChanged
emits dataStatusChanged
emits dataUpdated
Initial values:
loadingStatus = EkoLoadingStatus.Loading
dataStatus = EkoDataStatus.Local
model = localData
Process received data (same order):
emits loadingStatusChanged
emits dataStatusChanged
emits dataUpdated
- only if data is really different
loadingStatus = EkoLoadingStatus.Loaded
dataStatus = EkoDataStatus.Fresh
model = localFreshData
The LiveObject API supports queries that return a list of objects, this is known as a LiveCollection. LiveCollection has the same methods and properties as its object counterpart, but contains a few other helper methods around pagination.
Pagination with LiveCollections is very simple: the collection offers a convenient nextPage
method that you can call which will automatically trigger a local cache lookup, a network call, and multiple LiveObject updates once new data is returned. Every collection starts with one page of 20 models. After nextPage()
is successful, the dataUpdated
event will be triggered with a new array combining both the old objects as well as 20 newly fetched objects.
You can use the
hasMore
property to determine if you've scrolled to the end of the list. ThehasMore
property initially returns 'false' until the first collection query is finished.
Lastly, if there is a need to shrink the list of objects exported back to only the first 20 records (for example, if you pass the LiveCollection object to a new view), you can simply call resetPage()
.
Similar to model
property of the LiveObject, the LiveCollection provides models
property what is basically is an array of LiveObject's model
objects. models
is mutable and always contains same data as one what returned by dataUpdated
event.
Both LiveObject and LiveCollection can be subscribed to the dataError
event which is fired every time an error happens during the data update process. In other words, every time the LiveObject or LiveCollection fails to get data from the server - this error will be emmited.
We recommend you to always call dispose()
whenever you are done working with any LiveObject/LiveCollection.
Dispose is a very important functionality of the LiveObject. It allows you to avoid memory leaks and keeps your application performant. What does dispose()
do:
unsubscribe all listeners attached to the LiveObject instance;
stop all internall observers related to the LiveObject instance;
clean up an internall buffer of the LiveObject instance;
After you call dispose()
on a LiveObject instance, dataStatus and loadingStatus switch to Error
.
Ensure that your users don’t miss important content from each other.
With this solution live events are sent from Amity's servers to your servers: once an event lands on your servers, you have the full power and control on what to do with each notification, including editing/removing/stopping the notification before it reaches your users devices.
In this scenario there's no Android SDK involvement, as the whole notification is managed on your end.
With this solution, the notifications are triggered and delivered to your users directly by Amity's servers. There's nothing that the Android client has to do in order to display the notification to your users: Amity's servers will prepare a notification that can be directly displayed to the user.
As the Amity servers are responsible for choosing the content of the push notifications, you can expect your users to receive the following notifications for different kinds of events:
Event: New channel has been created and the user has been added among its members. Push Notification Title: %s
(%s
= New Channel display name) Push Notification Body: You're now member of %s!
(%s
= New Channel display name)
Event: A new member joins a channel of the user who is already an existing member of it
Push Notification Title: %s
(%s
= user display name) Push Notification Body: %1$s has joined %2$s
(%1$s
= user display name, %2$s
= channel display name)
Event: A new message is sent in a channel of the user who is already an existing member of it. Push Notification Title: %1$s (%2$s)
(%1$s
= user display name, %2$s
= channel display name) Push Notification Body: %s
(%s
= message text body if text message, Image Message
if image message, Special message
otherwise)
A new push notification will be sent to a specific user when:
A new message is sent in a channel of the user who is already an existing member of it
A new channel is created and the user is among the listed members of the channel on creation
A new member joins a channel of the user who is already an existing member of it
FCM dependency:
Before you can start receiving push notifications, you need to obtain a FCM unique token string that identifies each FCM client app instance:
You can initialize the services with the obtained token. Please note that the FCM token can be changed through application life cycle. Please make sure that the FCM token supplied to the messaging SDK is up to date. To notify the messaging SDK of the latest token, the following line of code can be called whenever necessary:
Since Google play services are banned in China, The messaging SDK provides Baidu push services as a substitute for FCM. The messaging SDK requires an api key and a secret key from Baidu:
Baidu dependency:
Baidu API key is needed for Baidu push services initialization:
Note: The messaging SDK always consider FCM as a primary push provider and Baidu as a secondary push provider. If the messaging SDK detects Google play services on the device, Baidu push services won't be initialized.
The registration will automatically pick up the active userId
, and Amity's back-end will start sending push notifications to the particular user. In the where where the active userId
has been changed, registration will be required again.
The de-registration allows you to pass an optional userId
:
if a valid userId
is passed, Amity's backend will stop sending push notifications to this device only if the currently active push notification associated with this device is also associated with that user. No action is taken otherwise.
if no userId
is passed, Amity's backend will stop sending push notifications to this device.
The SDK has three levels of notifications: to be sent, a notification has to pass throughout all three of them in order to be successfully delivered.
The levels are:
Network Level: (via Amity Social Cloud Console) turning off notifications at this level effectively disables push notifications for all of your customers.
User Level: (via client) A user can choose to entirely enable/disable the notifications that they receive (this is an absolute option: enable all or disable all). Please note that this setting is per user, not per device: regardless of which device sets this toggle, the new preference will take effect on all the devices where the user is logged in.
Channel Level: (via client) A user can choose to enable/disable notifications for a specific channel (where the user is a member). Again, this preference is per user, not per device.
In order to get and set the user level push notifications preference, we use the object EkoUserNotification
, obtained from EkoClient
:
For channel preferences we use the EkoChannelNotification
instead, obtained via an instance of EkoChannelRepository
or EkoChannel
:
Our channels enable developers to implement different types of chat messaging capabilities into their applications easily
Users can create and join channels where they will be able to participate and chat with other users. A channel can support up to 300,000 members and can contain an unlimited number of messages. Any message exchanged in the channels will be pushed to all other members of the channel in real-time.
Amity's Chat SDK supports the creations of 4 types of chat channels. Each type is designed to match a particular use-case for chat channels. Here's a table showing what features each channel offers:
The community channel is our default channel type and can be discovered by all users and admins. It acts as a public chat channel that showcases all of the features that our SDK's have to offer.
Typical use cases:
Team collaboration
Online gaming
Celebrity fan club
Live streaming
Any type of public chat
Live channels offers the ability for users and admins to create channels with exclusive memberships. The live channel is identical to our Community channel in features with the caveat that users will not be able to discover the channel when querying for all channels unless they are already a member of it. However users and admins can still invite other users to join the channel.
Typical use cases:
Healthcare
Project Discussion
Any type of private chat
Community and Live channel types can use our SDK moderation tools:
Message and user flagging
Muting/Unmuting users
Banning/Unbanning users from channel
Profanity filters
Whitelisted URLs
User rate-limiting
All broadcast channels are visible on the Amity Social Cloud Console.
The Broadcast channel is heavily adopted by corporate users who constantly promote or advertise their products, or make the announcement to drive awareness. Unlink other channel types, broadcast channels only allow admin users to send messages from Console, and everyone else in the channel will be under read-only mode.
Since this is a one-way communication channel, a tailored moderation tools are provided as well, for instance, users won't be able to flag message / user in the channel.
Typical use cases:
Marketing & Advertising
School / Government Announcements
Conversation channels are NOT visible on the Amity Social Cloud Console.
The Conversation channel is our solution to 1-on-1 messaging. Unlike the other channel types, a Conversation channel can be created simply by knowing the userId of the user we want to converse with. Users can start conversations with any other user and only they will be able to see their conversation.
There are no moderation tools for Conversation channels, users will be able to converse freely with no oversight!
Typical use cases:
Hospitality
Financial Consultancy
Customer Support
When a user joins a channel, they are able to observe and chat with other users in that channel. They are also automatically considered a member of that channel. The Chat SDK provides the ability to view which users are currently in the channel as well as invite other users to join the channel.
Each channel is identified by an unique channelId
, which is any string that uniquely identifies the channel and is immutable through its lifetime. When creating channels, you can specify your own channelId
, or leave it to Amity's Chat SDK to automatically generate one for you.
There can be only one and one only channel with a given
channelId
: an error will be thrown when trying to generate two channels with the samechannelId
.
There are three ways of obtaining a channel: via create, join, or get. They all return a LiveObject with the complete channel model. However, createChannel:
guarantees that the requested channel is a new channel, whereas joinChannel:
will attempt to join an existing channel. If there is a requirement to create a new channel, then use of createChannel:
then call joinChannel:
. Lastly calling getChannel:
only gives you back the channel LiveObject, but it won't make the current user join said channel.
Channel management methods are contained in a EkoChannelRepository
class. Before being able to call any channel method, you must initialize a repository instance using the EkoClient
instance you created on setup:
EkoChannelRepository
provides createChannel()
method to create a new channel. It supports creating of 3 types of channels Community
, Live
and Conversation
. Each channel type has specific builder classes which helps you to create that particular channel. Build your channel information first and then create the particular channel.
The above code creates a channel and notifies you through observer block. It first instantiates the EkoChannelRepository
, a class that contain all channel related methods. Then it calls createChannel:
to obtain the LiveObject and observe it in order to obtain the final channel model.
The
EkoNotificationToken
returned by theobserve:
is saved inself.channelToken
, a strongly referenced property. This is needed in order to prevent the observe block to be released. Observe block can get called multiple time, when the underlying data for the channel updates. If you don't want to get notified, you can callchannelToken.invalidate()
. As soon as the token gets invalidated, observer is automatically removed from that channel.In the case that there is already an existing channel with the same
channelID
, the LiveObject will notify you with anerror
object.The
channelId
parameter increateChannel:
can benil
: when this happens, the SDK will generate an uniquechannelId
for this channel, ensuring no unique ID conflicts.3 channel types can be created through SDK i.e
Community
,Live
andConversation
. Creation ofPrivate
andStandard
type has been removed. Creation ofBroadcast
channel type is not supported through the SDK. But for query,channelCollection:
method supports all channel types includingBroadcast
,Private
andStandard
.
We do not currently support this method on Web, and will be working towards adding it shortly!
Conversation channel is unique based on its membership. When creating conversation the system will check if channel with the same membership already exists, if such channel already exists the system will return existing channel instead of creating a new one.
joinChannel:
is an idempotent method, this means it can be called multiple times throughout the lifecycle of the application, and you can expect this method to always return the same channel. Because of this, you can also use joinChannel:
any time you need to fetch a channel, even if you know the user may already be in the channel.
In the case where you'd like to fetch a channel's data without joining, the getChannel:
method can be used:
EkoChannelRepository
provides a way to query list of channels using channelCollection()
method. It returns a EkoCollection
of all the matching channels available. This live collection returned will automatically update and notify you on any channel modifications.
SDK provides with 7 builder classes. EkoStandardChannelQueryBuilder
, EkoPrivateChannelQueryBuilder
, EkoByTypesChannelQueryBuilder
, EkoBroadcastChannelQueryBuilder
, EkoConversationChannelQueryBuilder
, EkoCommunityChannelQueryBuilder
and EkoLiveChannelQueryBuilder
. These builder classes should be used to construct a query and then used alongside channelCollection method to fetch list of channels.
Depreciated:
channelsForFilter()
,channelsForFilter(_:includingTags:excludingTags:)
method to query channels is now depreciated. SDK now doesnot support creation of Private & Standard channels but still supports query usingEkoStandardChannelQueryBuilder
EkoPrivateChannelQueryBuilder
.
If you use a UITableView
or UICollectionView
to display channel list data, the ideal location to reload table data is directly in the observe block of the LiveObject that you are displaying, as shown in the example above.
You can filter channels by various criteria such as includingTags, excludingTags, includeDeleted channels etc. All these filters are available in QueryBuilder classes for channel.
Metadata is a general purpose data store that is automatically synchronized to all the channel members. It is meant as an elegant mechanism to store contextual information about a specific channel. The data can be any number of JSON key value pairs up to 100 kb. Example use cases include:
Conversation title or cover photo
Global conversation settings
Metadata is implemented with last writer wins semantics: multiple mutations by independent users to the metadata object will result in a single stored value. No locking, merging, or other coordination is performed across multiple writes on the data.
To set metadata, call the setMetadataForChannel:
method:
The completion block will be triggered with the outcome of the request. The latest metadata of the channel is always exposed as part of the metadata
property on the channel model.
Every channel contains an optional displayName
property. This property is mainly used to identify the channel in push notifications, but it is also exposed to the application via EkoChannel
object.
You can set a channel's displayName
with the following method:
An optional completion callback is available to inform you on whether the request has succeeded or not.
All participation related methods in a channel falls under a separate EkoChannelParticipation
class. Before calling any participation methods, you must ensure to first instantiate a repository instance using the EkoClient
instance you created on setup and a valid channelId
:
Also you can access a ChannelMembershipRepository
instance by the membership
property of a channel LiveObject model:
The participation membership provides a list of all members in the given channel as a LiveObject.
The participation membership also provides classes to add and remove members, as well as removing yourself as a member of the channel (leaving the channel).
The EkoChannelRepository
object exposes an totalUnreadCount
property that reflects the number of messages that the current user has yet to read. This count is the sum of all the unreadCount
channels properties where the user is already a member.
To let the server know when the current user is reading one channel, hence resetting that channel unreadCount
to zero, the participation membership exposes the startReading
and stopReading
methods.
You can call both methods as much you want, the SDK takes care of multi-device management: therefore a user can read multiple channels, from one or multiple devices at once. In case of an abrupt disconnection (whether because the app was killed, or the internet went down etc) the SDK backend will automatically call the stopReading
on the user behalf.
EkoChannelModeration
class provides various methods to moderate the users present in channel. You can ban/unban/mute users, assign roles or remove it from user.
You can check your permission in channel using hasPermission(permission:forChannel:_:)
method from the "ekoclient"
All the errors returned by the SDK come in form of an . The possible error codes are listed in a public enum: each case is named after its error and they are designed to be self explanatory.
You can convert an into enum with the following:
The class includes the method that can be called and observed to asynchronous errors. This observable object notifies you of errors that can potentially break the functionality of the SDK. The SDK logic is usually robust enough to automatically handle most errors, as such, only unrecoverable errors are exposed through this observable (for example, if the login session was invalidated).
Note: Baidu push services require number of additional permissions. You can find .
Channel Type
Discoverable by
Message sending privileges
Moderation access
Community
All users and admins
Users and admins
All Moderation tools
Live
Only members and admins
Users and admins
All Moderation tools
Broadcast
All users and admins
Admins
Admin Moderation tools
Conversation
Only members
Users
No Moderation tools
Channel Type
Discoverable by
Message sending privileges
Moderation access
Community
All users and admins
Users and admins
All Moderation tools
Live
Only members and admins
Users and admins
All Moderation tools
Broadcast
All users and admins
Admins
Admin Moderation tools
Conversation
Only members
Users
No Moderation tools
Name
Data Type
Description
Attributes
messageId
string
The id of this message
Content
parentId
string
The messageId
of the parent of this message
Content
childrenNumber
integer
The number of messages with parentId
of this message
Content
channelId
string
The name of the channel this message was created in
Content
userId
string
The name of the user this message was created by
Content
type
string
The message type
enum*: text
custom
image
file
tags
Array.<string>
The message tags
Content
data
Object
The message data (any text will be stored in text
key)
text
: Text message
isDeleted
boolean
The message has been marked as deleted
Content
channelSegment
integer
The sequence number of a message in channel
Content
createdAt
date
The date/time the message was created at
Content
updatedAt
date
The date/time the message was updated at
Content
editedAt
date
The date/time the message was edited at
Content
flagCount
integer
The number of users that have flagged this message
Content
hashFlah
Object
A hash for checking internally if this message was flagged by the user
Content
reactions
Object
The reaction data (stored as a reactionName and counter key/value pair)
Example: { like
: 1, dislike
: 2 }
reactionsCount
integer
The total number of reactions on this message
Content
myReactions
Array.<string>
A list of user's reactions on this message
Content
Name
Data Type
Description
Attributes
userId
string
The id of this user
roles
Array.<string>
A list of user's roles
displayName
string
The display name of the user
flagCount
integer
The number of users that have flagged this user
metadata
Object
The metadata of the user
hashFlag
Object
A hash for checking internally if this user was flagged by the user
createdAt
date
The date/time the user was created at
updatedAt
date
The date/time the user was updated at
Error | Code |
BAD_REQUEST_ERROR | 400000 |
INVALID_REGULAR_EXPRESSION | 400001 |
UNAUTHORIZED_ERROR | 400100 |
FORBIDDEN_ERROR | 400300 |
PERMISSION_DENIED | 400301 |
USER_IS_MUTED | 400302 |
CHANNEL_IS_MUTED | 400303 |
USER_IS_BANNED | 400304 |
NUMBER_OF_MEMBER_EXCEED | 400305 |
EXEMPT_FROM_BAN | 400306 |
MAX_REPETITION_EXCEED | 400307 |
BAN_WORD_FOUND | 400308 |
LINK_NOT_ALLOWED | 400309 |
TOO_MANY_MEMBER_ERROR | 400310 |
RPC_RATE_LIMIT_ERROR | 400311 |
USER_IS_GLOBAL_BANNED | 400312 |
ITEM_NOT_FOUND | 400400 |
CONFLICT | 400900 |
BUSINESS_ERROR | 500000 |
Error | Code |
UNKNOWN | 800000 |
INVALID_PARAMETER | 800110 |
MALFORMED_DATA | 800130 |
FILE_SIZE_EXCEEDED | 800140 |
CONNECTION_ERROR | 800210 |
Channel Type | Discoverable by | Message sending privileges | Moderation access |
Community | All users and admins | Users and admins | All Moderation tools |
Live | Only members and admins | Users and admins | All Moderation tools |
Broadcast | All users and admins | Admins | Admin Moderation tools |
Conversation | Only members | Users | No Moderation tools |
Channel Type | Discoverable by | Message sending privileges | Moderation access |
Community | All users and admins | Users and admins | All Moderation tools |
Live | Only members and admins | Users and admins | All Moderation tools |
Broadcast | All users and admins | Admins | Admin Moderation tools |
Conversation | Only members | Users | No Moderation tools |
Moderation is an important feature for building a safe community that encourages user participation and engagement.
Amity’s customer centric nature ensures that security needs are kept at the forefront of the work we do. Our purpose has been to continuously develop features that are safe and ready to use. We power our moderators with tools to control and impose permissions that make their applications a safer place, for all users. We put the utmost importance on giving power to our clients to implement protocols that keep their applications healthy, safe and compliant.
Rate limiting a channel controls the speed of messages that is published to all concurrent clients in the channel
This method is useful when there is a large amount of messages going through the channel, which can make the message stream hard to follow. Setting a rate limit enables the SDK to queue up messages once the amount of message in a specified window
exceeds the defined limit
, allowing a slower stream of messages to be published to the user at the expense of adding more latency (because newer messages will be sent to the queue first and not delivered until all previous queued messages are delivered).
There is an internal limit of 1000 messages that can be queued by the rate limit service, if more than 1000 messages are queued up, the system may skip publishing the older messages in order to make room for newer messages. We believe this is the preferred behavior for users, as users will most likely want to see newer messages in a real-time conversation instead of waiting for a significant amount of time for old messages to be published to them first.
Note that the SDK permanently stores all messages it receives in the system before the rate limit comes into effect: in the case of a large spike of incoming messages, even if a message did not get published to a user in real-time, that user can still scroll up to see message history and see that past message.
The above method enables a rate limit of 5 messages every 60 seconds. Once a user sends more than 5 messages in 60 seconds, their messages will be queued on the server and not published to other channel members until 60 seconds have passed.
In order to disable the rate limit, simply call removeRateLimit()
:
When a user is muted, they can not send messages in a channel.
Moderators can mute and unmute users. When a user is muted, they cannot send messages in a channel. However muted users will still be allowed to observe messages in a channel. The status of being muted is indefinite but is only applied at the channel level.
When a user is muted, all messages sent by that user to that channel will be rejected. This method is useful for preventing certain users from sending inappropriate messages, but still allowing them to participate in the conversation in a read-only manner. The timeout property allows you to make the timeout temporary, or permanent by until unset by passing in -1
.
The above logic will mute user1
in the selected channel for 10 minutes (600 seconds). An optional completion block notifies you when the action is complete.
If you want to permanently mute a user, pass in
-1
as the mutePeriod. The user will stay muted until you explicitly unmute that user.
To unmute a user, call unmuteUsers()
:
flag and unflag a message
While having moderators surveying your chats is great, it doesn't scale well. A way to overcome this is to let your users do the work for your moderators. By letting users flag other users or specific messages, the work of moderators is significantly reduced and democratized, thus allowing administrators to only respond to issues when deemed critical or absolutely necessary.
Users can flag messages and unflag messages that they have flagged using the MessageFlagRepository
class.
To flag a message, call the following method:
To unflag a message, call the following method:
The User can also check if they have previously flagged the message before by calling the following asynchronous method:
If this method has been called before in the current session, the user can also check the cached result on the message payload itself.
Ensure that your users don’t miss important content from each other.
This functionality is not currently supported for Web but will be coming soon! We will update the relevant sections accordingly
Error objects can be returned to you via LiveObjects, callbacks, or clientErrorDelegate
. All the errors returned by the SDK come in form of an NSError with domain Eko
. The possible error codes are listed in a public EkoErrorCode
enum: each case is named after its error and they're pretty self explanatory.
UnauthorizedError: 400100
ItemNotFound: 400400
BadRequestError: 400000
Conflict: 400900
ForbiddenError: 400300
PermissionDenied: 400301
UserIsMuted: 400302
ChannelIsMuted: 400303
UserIsBanned: 400304
NumberOfMemberExceed: 400305
ExemptFromBan: 400306
MaxRepetitionExceed: 400307
BanWordFound: 400308
LinkNotAllowed: 400309
GlobalBanError: 400312
BusinessError: 500000
Unknown: 800000
InvalidParameter: 800110
MalformedData: 800130
ErrorQueryInProgress: 800170
ConnectionError: 800210
When an error is returned as a result of an action from your side (e.g. trying to join a channel), the action is considered completed and the SDK will not execute any additional logic.
The EkoClient
includes a clientErrorDelegate
property that can be set to an error handler delegate class on your application. This error delegate gives you a chance to be notified of errors that can potentially break the functionality of the SDK. The SDK logic is usually robust enough to automatically handle most errors, as such, only unrecoverable errors are exposed through this delegate (for example, if the login session was invalidated).
We recommend you to always handle these errors in a production app by gracefully disabling messaging functionality in the event of an error.
This page contains an overview of all relevant changes made to the Amity Chat SDK modules and the latest version releases
Reaction
Normalized API across the SDK
User
UserRepository.getAllUsers(sortBy?: EkoUserSortingMethod)
UserRepository.searchUserByDisplayName(search: string)
Added unreadCount in ChannelMembershipModel
exampleChannelMembershipModel.unreadCount;
Threaded messages:
MessageModel.parentId;
: Message ID of a parent message
MessageRepository.messagesForChannel
now allow parameters parentId: string
and filterByParentId: boolean
to perform queries on threads of messages
Reactions:
{ reactions: Object, reactionsCount: number, myReactions: string[] }
is added to MessageModel to support reactions
ReactorRepository(messageModel: MessageModel);
async ReactorRepository.addReaction(reactionName: string);
async ReactorRepository.removeReaction(reactionName: string);
A new Message Flagger Repository has been added and all message flagging has been moving to this repository:
MessageFlagRepository(messageId);
MessageFlagRepository.flag({ messageId });
MessageFlagRepository.unflag({ messageId });
You can check if you have flagged a message before
await MessageFlagRepository.isFlaggedByMe();
MessageModel now contains a cache for the isFlaggedByMe result
MessageModel.isFlaggedByMeCache;
You can now edit user metadata:
client.setUserMetadata({ test: "test" });
You can now filter channels by tags/excludingTags:
ChannelRepository.channelsWithFilters({ tags: [1,2,3], excludingTags: [4,5,6] });
You can now edit and delete message text:
MessageEditorRepository.editText('new edited text');
MessageEditorRepository.delete();
You can now read and unread channels:
ChannelMembershipRepository.startReading()
ChannelMembershipRepository.stopReading()
You can now be able to flag/unflag a message:
MessageRepository.flag({ messageId });
MessageRepository.unflag({ messageId });
You can now be able to flag/unflag a user:
UserRepository.flag({ userId });
UserRepository.unflag({ userId });
Fixed an issue with LiveObject and LiveCollection when they stop listen for updates from server after unregister/register. (case with SPA multiuser UI).
Enhanced Array.prototype.sort() comparison functions to be in sync with last updates in V8 (changes for sort()
already delivered in Chrome 70 and node-v11).
Amity SDK's do not store or manage any user data. This means that you do not have to import or migrate existing user profiles into the system, user management should be handled by your application code. Instead, every user is simply represented by a unique userID
, which can be any string that uniquely identifies the user and is immutable throughout its lifetime.
A database primary key would make an ideal
userID
. Conversely, something like username or emails is not recommended as those values may change overtime.
If you wish to assign additional permissions for a user, for example moderation privileges or different sending limits, you can provide an array of roles to assign to this user. Roles are defined in the admin panel and can be tied to an unlimited number of users. Once again, Amity does not store or manage any user data, which means you do not have to import or migrate existing users into the system. It also means that Amity cannot provide user management functionalities like lists of users, or limit actions of certain users (e.g. user permissions). Instead, these functionalities should be handled by the rest of your application's capabilities and your server.
Though the SDK does not store and should not be responsible for the handling User profile data for your application; We do provide tools to make some surface-level queries and searches for existing user accounts. With the help of our EkoUserRepository
class, you would be able to list all the users, search for list of users whose display name matches your search query and get EkoUser
object from user id.
All User methods are contained in a UserRepository
class. Before calling any User methods, you must first instantiate a repository instance.
The User Repository provides a method to get a single user, which will be returned as a LiveObject:
The User Repository provides a method to get a list of all users, which will be returned as a LiveCollection:
This method takes an optional sortBy
parameter which must be a EkoUserSortingMethod
- these include displayName
, firstCreated
, and lastCreated
:
The User Repository provides a method to search for users by their display name. The result of this search is returned as a LiveCollection.
The above example searches for all users whose display names start with "Test User 1". Note that the search is case sensitive.
To flag a user, call the following method:
To unflag a user, call the following method:
Both of these methods return a promise meaning they can be chained with .then
and .catch
handlers:
Name
Data Type
Description
Attributes
userId
string
The id of this user
roles
Array.<string>
A list of user's roles
displayName
string
The display name of the user
flagCount
integer
The number of users that have flagged this user
metadata
Object
The metadata of the user
hashFlag
Object
A hash for checking internally if this user was flagged by the user
createdAt
date
The date/time the user was created at
updatedAt
date
The date/time the user was updated at