Channels

Each channel is identified by an unique channelId, which is an immutable string. When creating a new channel, you can either specify your own channelId, or leave it to Eko to 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 same channelId.

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:

let channelRepository = EkoChannelRepository(client: client)

Create Channel

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 informatino first and then create the particular channel.

var channelToken: EkoNotificationToken?
...
let builder = EkoCommunityChannelBuilder()
// Optional. If you don't provide channel id, sdk will create a unique channel id for you.
builder.setId("my-id")
builder.setUserIds(userIds)
builder.setDisplayName("my-community-channel_\(randomId)")
builder.setTags(["ch-comm","ios-sdk"])
builder.setMetadata(["sdk_type":"ios"])
channelObject = channelRepository.createChannel().community(with: builder)
channelToken = channelObject.observe { channelObject, error in
// Do Something
}

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 the observe: is saved in self.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 call channelToken.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 an error object.

The channelId parameter in createChannel: can be nil: when this happens, the SDK will generate an unique channelId for this channel, ensuring no unique ID conflicts.

3 channel types can be created through SDK i.e Community, Live and Conversation. Creation of Private and Standard type has been removed. Creation of Broadcast channel type is not supported through sdk. But for query, channelCollection: method supports all channel types including Broadcast, Private and Standard.

Create Conversation:

SDK provides a convenient createConversation: method which creates a conversation channel type. You can use either createChannel or createConversation method directly.

Join Channel

let channelObject: EkoObject<EkoChannel> = repository.joinChannel("channel-id")
channelNotification = channelObject.observe { channelObject, error in
...
}

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.

Get Channel

In the case where you'd like to fetch a channel's data without joining, the getChannel: method can be used:

let liveChannel = repository.getChannel("channel3")
channelNotification = liveChannel.observe { liveChannel, error in
...
}

Channel Query

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 using EkoStandardChannelQueryBuilder EkoPrivateChannelQueryBuilder.

switch channelType {
case .byTypes:
let builderSet: Set<String> = Set(arrayLiteral: "standard", "private")
let builder = EkoByTypesChannelQueryBuilder(types: builderSet, channelQueryFilter: channelFilter, includingTags: includingTags, excludingTags: excludingTags)
channelsCollection = repository.channelCollection().byTypes(with: builder).query()
case .broadcast:
let builder = EkoBroadcastChannelQueryBuilder(channelQueryFilter: channelFilter, includingTags: includingTags, excludingTags: excludingTags)
channelsCollection = repository.channelCollection().broadcast(with: builder).query()
case .conversation:
let builder = EkoConversationChannelQueryBuilder(includingTags: nil, excludingTags: nil)
channelsCollection = repository.channelCollection().conversation(with: builder).query()
case .live:
let builder = EkoLiveChannelQueryBuilder(includingTags: includingTags, excludingTags: excludingTags, includeDeleted: false)
channelsCollection = repository.channelCollection().liveType(with: builder).query()
case .community:
let builder = EkoCommunityChannelQueryBuilder(filter: .userIsMember, includingTags: includingTags, excludingTags: excludingTags, includeDeleted: false)
channelsCollection = repository.channelCollection().communityType(with: builder).query()
}
channelsToken = channelsCollection?.observe { [weak self] _, _, _ in
// Update datasource
}

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.

Channel Filtering

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

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:

repository.setMetadataForChannel("channel1", data: ["hello": "world"]) { success, error in
...
}

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.

Display Name

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:

repository.setDisplayNameForChannel("channel1", displayName: "Channel Eko") { success, error in
if success {
print("Channel display name set successful")
}
}

An optional completion callback is available to inform you on whether the request has succeded or not.

Participation

All participation related methods in a channel falls under a seperate 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:

let membershipParticipation = EkoChannelParticipation(client: client, andChannel: "channel1")

Members Query

The participation membership provides a list of all members in the given channel as a LiveObject.

memberNotification = membershipParticipation.memberships.observe { [weak self] _, _ in
self?.tableView.reloadData()
}

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.

let membershipCollection = membershipParticipation.memberships(for: .all, sortBy: .firstCreated, roles: [])
token = membershipCollection.observe({ (collection, change, error) in
// React to changes here
})

Manage Members

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

// add 'user1' and 'user2' to this channel
membershipParticipation.addUsers(["user1", "user2"], completion: nil)
// remove 'user3' from this channel
membershipParticipation.removeUsers(["user3"], completion: nil)
// leave this channel
membershipParticipation.leave(completion: nil)

Reading Status And Unread Count

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 member of.

// repository is a `EkoChannelRepository` instance
let userTotalUnreadCount = repository.totalUnreadCount
let channelObject: EkoObject<EkoChannel> = repository.getChannel("channel1")
let channelUnreadCount = channel.object?.unreadCount

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.

// start reading a channel
membershipParticipation.startReading()
// stop reading a channel
membershipParticipation.stopReading()

Moderation

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.

Permission

You can check your permission in channel using hasPermission(permission:forChannel:_:) method from EkoClient.