有奖捉虫:办公协同&微信生态&物联网文档专题 HOT

功能描述

用户在登录 App 后,可以像微信或 QQ 那样展示最近会话列表,方便找到目标会话。会话列表如下图所示:

会话列表功能主要分为获取会话列表、处理会话列表更新。本文将为您介绍具体的实现细节。

获取会话列表基础接口

您可以调用 getConversationList(Android / iOS & Mac / Windows) 获取会话列表。该接口拉取的是本地缓存的会话,如果服务器会话有更新,SDK 内部会自动同步,然后在 V2TIMConversationListener 回调告知客户。
用户的会话以列表的形式返回,列表中存储的是 V2TIMConversation 对象。目前 IM SDK 对会话列表的排序规则为:
5.5.892 及以后版本, 获取的会话列表默认已经按照会话对象的 orderKey 做了排序。orderKey 值越大,代表该会话排序越靠前。orderKey 字段是整型数,当发送新消息、接收新消息、设置草稿或置顶会话时,会话被激活,orderKey 字段会增大。
5.5.892 以前版本,获取的会话列表默认已经按照会话 lastMessage -> timestamp 做了排序。timestamp 越大,会话越靠前。
注意
在某些场景下,可能出现会话的 lastMessage 为空(例如清空会话消息)。如果您使用 5.5.892 以前的 SDK,使用 lastMessage 排序时需要额外处理这种异常。我们建议您升级到 5.5.892 及以后的版本,使用 orderKey 字段排序。
您可以使用 getConversationList 实现一次性拉取或分页拉取。参考下文说明。

一次性拉取

一次性拉取适合会话数量比较少的情况(100 个以内)。此时可以将拉取的 count 设置为 INT_MAX(一般会话数量不会达到 INT_MAX 这么多)。
示例代码如下:
Android
iOS & Mac
Windows
V2TIMManager.getConversationManager().getConversationList(0, Integer.MAX_VALUE, new V2TIMValueCallback<V2TIMConversationResult>() {
@Override
public void onSuccess(V2TIMConversationResult v2TIMConversationResult) {
long nextSeq = v2TIMConversationResult.getNextSeq();
Log.i("imsdk", "success nextSeq:" + nextSeq + ", isFinish:" + v2TIMConversationResult.isFinished());

List<V2TIMConversation> v2TIMConversationList = v2TIMConversationResult.getConversationList();
for (V2TIMConversation v2TIMConversation : v2TIMConversationList) {
Log.i("imsdk", "success showName:" + v2TIMConversation.getShowName());
}
}

@Override
public void onError(int code, String desc) {
Log.i("imsdk", "failure, code:" + code + ", desc:" + desc);
}
});
[[V2TIMManager sharedInstance] getConversationList:0
count:INT_MAX
succ:^(NSArray<V2TIMConversation *> *list, uint64_t lastTS, BOOL isFinished) {
// 获取成功,list 为会话列表
} fail:^(int code, NSString *msg) {
// 获取失败
}];
template <class T>
class ValueCallback final : public V2TIMValueCallback<T> {
public:
using SuccessCallback = std::function<void(const T&)>;
using ErrorCallback = std::function<void(int, const V2TIMString&)>;

ValueCallback() = default;
~ValueCallback() override = default;

void SetCallback(SuccessCallback success_callback, ErrorCallback error_callback) {
success_callback_ = std::move(success_callback);
error_callback_ = std::move(error_callback);
}

void OnSuccess(const T& value) override {
if (success_callback_) {
success_callback_(value);
}
}
void OnError(int error_code, const V2TIMString& error_message) override {
if (error_callback_) {
error_callback_(error_code, error_message);
}
}

private:
SuccessCallback success_callback_;
ErrorCallback error_callback_;
};

uint64_t nextSeq = 0;
uint32_t count = std::numeric_limits<uint32_t>::max();

auto callback = new ValueCallback<V2TIMConversationResult>{};
callback->SetCallback(
[=](const V2TIMConversationResult& conversationResult) {
// 获取会话列表成功
delete callback;
},
[=](int error_code, const V2TIMString& error_message) {
// 获取会话列表失败
delete callback;
});

V2TIMManager::GetInstance()->GetConversationManager()->GetConversationList(nextSeq, count, callback);

分页拉取

如果您的应用场景会产生较多的会话数,考虑到加载效率、网络省流,我们建议您采用分页拉取的方式。每次分页拉取的数量建议不超过 100 个。
分页拉取的步骤:
1. 首次调用 getConversationList 时,指定参数 nextSeq 为 0(表示从头开始拉取会话列表),指定 count 为 50(表示一次拉取 50 个会话对象)。
2. 首次拉取会话列表成功后,getConversationList 的回调结果 V2TIMConversationResult 中会包含 nextSeq(下次分页拉取的字段)、isFinish(会话拉取是否完成)。
如果 isFinishedtrue,表示所有会话已经拉取完成。
如果 isFinishedfalse,表示还有更多的会话可以拉取。此时并不意味着要立刻开始拉取 “下一页” 的会话列表。在常见的软件中,分页拉取通常由用户的滑动操作触发的,用户每上拉一次会话列表就触发一次分页拉取。
3. 当用户继续上拉会话列表时,如果还有更多的会话可以拉取,可以继续调用 getConversationList 接口,并传入新一轮的 nextSeq(数值来自上一次拉取返回的 V2TIMConversationResult 对象)和 count 参数。
4. 重复执行【步骤 3】直至 isFinished 返回 true。
示例代码如下:
Android
iOS & Mac
Windows
V2TIMManager.getConversationManager().getConversationList(0, 20, new V2TIMValueCallback<V2TIMConversationResult>() {
@Override
public void onSuccess(V2TIMConversationResult v2TIMConversationResult) {
long nextSeq = v2TIMConversationResult.getNextSeq();
Log.i("imsdk", "success nextSeq:" + nextSeq + ", isFinish:" + v2TIMConversationResult.isFinished());

List<V2TIMConversation> v2TIMConversationList = v2TIMConversationResult.getConversationList();
for (V2TIMConversation v2TIMConversation : v2TIMConversationList) {
Log.i("imsdk", "success showName:" + v2TIMConversation.getShowName());
}

if (!v2TIMConversationResult.isFinished()) {
getConversationListInternal(nextSeq, 20);
}
}

@Override
public void onError(int code, String desc) {
Log.i("imsdk", "failure, code:" + code + ", desc:" + desc);
}
});
// 用户上拉会话列表到底部,没有更多会话数据展示时触发
- (void)loadConversation {
if (self.isFinished) {
return;
}
@weakify(self)
[[V2TIMManager sharedInstance] getConversationList:self.nextSeq
count:20 // 每次拉 20 个会话
succ:^(NSArray<V2TIMConversation *> *list, uint64_t nextSeq, BOOL isFinished) {
// 拉取成功
@strongify(self)
// 更新下一次拉取的锚点 nextSeq 和是否完成拉取标识位 isFinished
self.nextSeq = nextSeq;
self.isFinished = isFinished;

// 用 list 更新 UI
} fail:^(int code, NSString *msg) {
// 拉取失败,结束本次拉取
self.isFinished = YES;
}];
}
template <class T>
class ValueCallback final : public V2TIMValueCallback<T> {
public:
using SuccessCallback = std::function<void(const T&)>;
using ErrorCallback = std::function<void(int, const V2TIMString&)>;

ValueCallback() = default;
~ValueCallback() override = default;

void SetCallback(SuccessCallback success_callback, ErrorCallback error_callback) {
success_callback_ = std::move(success_callback);
error_callback_ = std::move(error_callback);
}

void OnSuccess(const T& value) override {
if (success_callback_) {
success_callback_(value);
}
}
void OnError(int error_code, const V2TIMString& error_message) override {
if (error_callback_) {
error_callback_(error_code, error_message);
}
}

private:
SuccessCallback success_callback_;
ErrorCallback error_callback_;
};

uint64_t nextSeq = 0;
uint32_t count = 20;

auto callback = new ValueCallback<V2TIMConversationResult>{};
callback->SetCallback(
[=](const V2TIMConversationResult& conversationResult) {
// 获取会话列表成功
if (!conversationResult.isFinished) {
nextSeq = conversationResult.nextSeq;
// 继续获取 ...
}

delete callback;
},
[=](int error_code, const V2TIMString& error_message) {
// 获取会话列表失败
delete callback;
});

V2TIMManager::GetInstance()->GetConversationManager()->GetConversationList(nextSeq, count, callback);

获取会话列表高级接口

如果以上的普通接口无法满足您对拉取会话列表的需求,我们还提供了高级接口 getConversationListByFilter (Android / iOS & Mac / Windows),其中拉取会话的 V2TIMConversationListFilter 详解如下:
属性
含义
说明
type
会话类型(填 0 代表不过滤此项)
C2C 或者群组会话
conversationGroup
会话分组名称(不填写代表不过滤此项)
不是群组名称,是会话分组的名称,详情请参见 会话分组
markType
会话标记类型(填 0 代表不过滤此项)
详情请参见 会话标记
hasUnreadCount
会话包含未读数
true :返回包含未读数的会话;false:返回所有会话
hasGroupAtInfo
会话包含群 @ 消息
true :返回包含群 @ 消息的会话;false:返回所有会话

拉取单聊或群聊会话

Android
iOS & Mac
Windows
V2TIMConversationListFilter filter = new V2TIMConversationListFilter();
filter.setConversationType(V2TIMConversation.V2TIM_C2C); //拉取单聊会话
// filter.setConversationType(V2TIMConversation.V2TIM_GROUP); //拉取群聊会话
V2TIMManager.getConversationManager().getConversationListByFilter(filter, 0, 50, new V2TIMValueCallback<V2TIMConversationResult>() {
@Override
public void onSuccess(V2TIMConversationResult v2TIMConversationResult) {
// 获取会话列表成功
}

@Override
public void onError(int code, String desc) {
// 获取会话列表失败
}
});
V2TIMConversationListFilter *filter = [[V2TIMConversationListFilter alloc] init];
filter.type = V2TIM_C2C; //拉取单聊会话
// filter.type = V2TIM_GROUP; //拉取群聊会话
[[V2TIMManager sharedInstance] getConversationListByFilter:filter nextSeq:0 count:50 succ:^(NSArray<V2TIMConversation *> *list, uint64_t nextSeq, BOOL isFinished) {
// 获取会话列表成功,list 为会话列表
} fail:^(int code, NSString *desc) {
// 获取会话列表失败
}];
template <class T>
class ValueCallback final : public V2TIMValueCallback<T> {
public:
using SuccessCallback = std::function<void(const T&)>;
using ErrorCallback = std::function<void(int, const V2TIMString&)>;

ValueCallback() = default;
~ValueCallback() override = default;

void SetCallback(SuccessCallback success_callback, ErrorCallback error_callback) {
success_callback_ = std::move(success_callback);
error_callback_ = std::move(error_callback);
}

void OnSuccess(const T& value) override {
if (success_callback_) {
success_callback_(value);
}
}
void OnError(int error_code, const V2TIMString& error_message) override {
if (error_callback_) {
error_callback_(error_code, error_message);
}
}

private:
SuccessCallback success_callback_;
ErrorCallback error_callback_;
};

V2TIMConversationListFilter filter;
filter.type = V2TIMConversationType::V2TIM_C2C; // 拉取单聊会话
// filter.type = V2TIMConversationType::V2TIM_GROUP; //拉取群聊会话
auto callback = new ValueCallback<V2TIMConversationResult>{};
callback->SetCallback(
[=](const V2TIMConversationResult& conversationResult) {
// 获取会话列表成功
delete callback;
},
[=](int error_code, const V2TIMString& error_message) {
// 获取会话列表失败
delete callback;
});
V2TIMManager::GetInstance()->GetConversationManager()->GetConversationListByFilter(filter, 0, 50, callback);

拉取指定分组会话

Android
iOS & Mac
Windows
V2TIMConversationListFilter filter = new V2TIMConversationListFilter();
filter.setConversationGroup("conversation_group");
V2TIMManager.getConversationManager().getConversationListByFilter(filter, 0, 50, new V2TIMValueCallback<V2TIMConversationResult>() {
@Override
public void onSuccess(V2TIMConversationResult v2TIMConversationResult) {
// 获取会话列表成功
}

@Override
public void onError(int code, String desc) {
// 获取会话列表失败
}
});
V2TIMConversationListFilter *filter = [[V2TIMConversationListFilter alloc] init];
filter.conversationGroup = @"conversation_group";
[[V2TIMManager sharedInstance] getConversationListByFilter:filter nextSeq:0 count:50 succ:^(NSArray<V2TIMConversation *> *list, uint64_t nextSeq, BOOL isFinished) {
// 获取会话列表成功,list 为会话列表
} fail:^(int code, NSString *desc) {
// 获取会话列表失败
}];
template <class T>
class ValueCallback final : public V2TIMValueCallback<T> {
public:
using SuccessCallback = std::function<void(const T&)>;
using ErrorCallback = std::function<void(int, const V2TIMString&)>;

ValueCallback() = default;
~ValueCallback() override = default;

void SetCallback(SuccessCallback success_callback, ErrorCallback error_callback) {
success_callback_ = std::move(success_callback);
error_callback_ = std::move(error_callback);
}

void OnSuccess(const T& value) override {
if (success_callback_) {
success_callback_(value);
}
}
void OnError(int error_code, const V2TIMString& error_message) override {
if (error_callback_) {
error_callback_(error_code, error_message);
}
}

private:
SuccessCallback success_callback_;
ErrorCallback error_callback_;
};

V2TIMConversationListFilter filter;
filter.conversationGroup = u8"conversation_group";
auto callback = new ValueCallback<V2TIMConversationResult>{};
callback->SetCallback(
[=](const V2TIMConversationResult& conversationResult) {
// 获取会话列表成功
delete callback;
},
[=](int error_code, const V2TIMString& error_message) {
// 获取会话列表失败
delete callback;
});
V2TIMManager::GetInstance()->GetConversationManager()->GetConversationListByFilter(filter, 0, 50, callback);

拉取指定标记会话

Android
iOS & Mac
Windows
V2TIMConversationListFilter filter = new V2TIMConversationListFilter();
filter.setMarkType(V2TIMConversation.V2TIM_CONVERSATION_MARK_TYPE_STAR);
V2TIMManager.getConversationManager().getConversationListByFilter(filter, 0, 50, new V2TIMValueCallback<V2TIMConversationResult>() {
@Override
public void onSuccess(V2TIMConversationResult v2TIMConversationResult) {
// 获取会话列表成功
}

@Override
public void onError(int code, String desc) {
// 获取会话列表失败
}
});
V2TIMConversationListFilter *filter = [[V2TIMConversationListFilter alloc] init];
filter.markType = V2TIM_CONVERSATION_MARK_TYPE_STAR;
[[V2TIMManager sharedInstance] getConversationListByFilter:filter nextSeq:0 count:50 succ:^(NSArray<V2TIMConversation *> *list, uint64_t nextSeq, BOOL isFinished) {
// 获取会话列表成功,list 为会话列表
} fail:^(int code, NSString *desc) {
// 获取会话列表失败
}];
template <class T>
class ValueCallback final : public V2TIMValueCallback<T> {
public:
using SuccessCallback = std::function<void(const T&)>;
using ErrorCallback = std::function<void(int, const V2TIMString&)>;

ValueCallback() = default;
~ValueCallback() override = default;

void SetCallback(SuccessCallback success_callback, ErrorCallback error_callback) {
success_callback_ = std::move(success_callback);
error_callback_ = std::move(error_callback);
}

void OnSuccess(const T& value) override {
if (success_callback_) {
success_callback_(value);
}
}
void OnError(int error_code, const V2TIMString& error_message) override {
if (error_callback_) {
error_callback_(error_code, error_message);
}
}

private:
SuccessCallback success_callback_;
ErrorCallback error_callback_;
};

V2TIMConversationListFilter filter;
filter.markType = V2TIMConversationMarkType::V2TIM_CONVERSATION_MARK_TYPE_STAR;
auto callback = new ValueCallback<V2TIMConversationResult>{};
callback->SetCallback(
[=](const V2TIMConversationResult& conversationResult) {
// 获取会话列表成功
delete callback;
},
[=](int error_code, const V2TIMString& error_message) {
// 获取会话列表失败
delete callback;
});
V2TIMManager::GetInstance()->GetConversationManager()->GetConversationListByFilter(filter, 0, 50, callback);

拉取含有未读数的会话

Android
iOS & Mac
Windows
V2TIMConversationListFilter filter = new V2TIMConversationListFilter();
filter.setHasUnreadCount(true);
V2TIMManager.getConversationManager().getConversationListByFilter(filter, 0, 50, new V2TIMValueCallback<V2TIMConversationResult>() {
@Override
public void onSuccess(V2TIMConversationResult v2TIMConversationResult) {
// 获取会话列表成功
}

@Override
public void onError(int code, String desc) {
// 获取会话列表失败
}
});
V2TIMConversationListFilter *filter = [[V2TIMConversationListFilter alloc] init];
filter.hasUnreadCount = YES;
[[V2TIMManager sharedInstance] getConversationListByFilter:filter nextSeq:0 count:50 succ:^(NSArray<V2TIMConversation *> *list, uint64_t nextSeq, BOOL isFinished) {
// 获取会话列表成功,list 为会话列表
} fail:^(int code, NSString *desc) {
// 获取会话列表失败
}];
template <class T>
class ValueCallback final : public V2TIMValueCallback<T> {
public:
using SuccessCallback = std::function<void(const T&)>;
using ErrorCallback = std::function<void(int, const V2TIMString&)>;

ValueCallback() = default;
~ValueCallback() override = default;

void SetCallback(SuccessCallback success_callback, ErrorCallback error_callback) {
success_callback_ = std::move(success_callback);
error_callback_ = std::move(error_callback);
}

void OnSuccess(const T& value) override {
if (success_callback_) {
success_callback_(value);
}
}
void OnError(int error_code, const V2TIMString& error_message) override {
if (error_callback_) {
error_callback_(error_code, error_message);
}
}

private:
SuccessCallback success_callback_;
ErrorCallback error_callback_;
};

V2TIMConversationListFilter filter;
filter.hasUnreadCount = true;
auto callback = new ValueCallback<V2TIMConversationResult>{};
callback->SetCallback(
[=](const V2TIMConversationResult& conversationResult) {
// 获取会话列表成功
delete callback;
},
[=](int error_code, const V2TIMString& error_message) {
// 获取会话列表失败
delete callback;
});
V2TIMManager::GetInstance()->GetConversationManager()->GetConversationListByFilter(filter, 0, 50, callback);

拉取含有群 @ 消息的会话

Android
iOS & Mac
Windows
V2TIMConversationListFilter filter = new V2TIMConversationListFilter();
filter.setHasGroupAtInfo(true);
V2TIMManager.getConversationManager().getConversationListByFilter(filter, 0, 50, new V2TIMValueCallback<V2TIMConversationResult>() {
@Override
public void onSuccess(V2TIMConversationResult v2TIMConversationResult) {
// 获取会话列表成功
}

@Override
public void onError(int code, String desc) {
// 获取会话列表失败
}
});
V2TIMConversationListFilter *filter = [[V2TIMConversationListFilter alloc] init];
filter.hasGroupAtInfo = YES;
[[V2TIMManager sharedInstance] getConversationListByFilter:filter nextSeq:0 count:50 succ:^(NSArray<V2TIMConversation *> *list, uint64_t nextSeq, BOOL isFinished) {
// 获取会话列表成功,list 为会话列表
} fail:^(int code, NSString *desc) {
// 获取会话列表失败
}];
template <class T>
class ValueCallback final : public V2TIMValueCallback<T> {
public:
using SuccessCallback = std::function<void(const T&)>;
using ErrorCallback = std::function<void(int, const V2TIMString&)>;

ValueCallback() = default;
~ValueCallback() override = default;

void SetCallback(SuccessCallback success_callback, ErrorCallback error_callback) {
success_callback_ = std::move(success_callback);
error_callback_ = std::move(error_callback);
}

void OnSuccess(const T& value) override {
if (success_callback_) {
success_callback_(value);
}
}
void OnError(int error_code, const V2TIMString& error_message) override {
if (error_callback_) {
error_callback_(error_code, error_message);
}
}

private:
SuccessCallback success_callback_;
ErrorCallback error_callback_;
};

V2TIMConversationListFilter filter;
filter.hasGroupAtInfo = true;
auto callback = new ValueCallback<V2TIMConversationResult>{};
callback->SetCallback(
[=](const V2TIMConversationResult& conversationResult) {
// 获取会话列表成功
delete callback;
},
[=](int error_code, const V2TIMString& error_message) {
// 获取会话列表失败
delete callback;
});
V2TIMManager::GetInstance()->GetConversationManager()->GetConversationListByFilter(filter, 0, 50, callback);



会话列表排序

会话列表始终按照 V2TIMConversation.orderKey 从大到小的顺序排列,orderKey 会随着会话的更新依次递增。
常见引起 orderKey 递增的操作有:收发消息(也即 lastMessage 发生变化)、置顶/取消置顶。
当会话的 lastMessage 的时间顺序与 orderKey 不一致时,以 orderKey 顺序为准。

会话列表更新

IM SDK 会在登录成功后、用户上线后、以及断线重连后,自动更新会话列表。 为了获取会话列表的更新,您需要操作如下几步:
1. 添加会话监听器。
2. 接收会话变更通知并处理。
3. 移除会话监听器。非必须,可按照业务逻辑按需调用。

添加会话监听器

您可以调用 addConversationListenerAndroid / iOS & Mac / Windows)添加会话监听器。添加监听器后,您才能接收到会话变更事件。
示例代码如下:
Android
iOS & Mac
Windows
V2TIMManager.getConversationManager().addConversationListener(conversationListener);
// self 为 id<V2TIMConversationListener> 类型
[[V2TIMManager sharedInstance] addConversationListener:self];
class ConversationListener final : public V2TIMConversationListener {
// 成员 ...
};

// 添加会话事件监听器,注意在移除监听器之前需要保持 conversationListener 的生命期,以免接收不到事件回调
ConversationListener conversationListener;
V2TIMManager::GetInstance()->GetConversationManager()->AddConversationListener(&conversationListener);

会话新增变更通知

您可以在 V2TIMConversationListenerAndroid / iOS & Mac / Windows)中的事件,获取会话列表变更的通知。
目前 IM SDK 支持的会话变更事件有:
事件
说明
建议
onSyncServerStart
同步服务器会话开始
SDK 会在登录成功、用户上线、断网重连后自动同步服务器会话,您可以监听这个事件做一些 UI 进度展示操作。
onSyncServerFinish
同步服务器会话完成
如果会话有变更,会通过 onNewConversation/onConversationChanged 回调告知。
onSyncServerFailed
同步服务器会话失败
您可以监听这个事件做一些 UI 异常展示操作。
onNewConversation
有会话新增
例如收到一个新同事发来的单聊消息、被拉入了一个新的群组中等,此时可以重新对会话列表做排序。
onConversationChanged
有会话更新
例如未读计数发生变化、最后一条消息被更新等,此时可以重新对会话列表做排序。
onConversationDeleted
有会话被删除
详情请参考 删除会话。7.2.4123 及以上版本支持。
onTotalUnreadMessageCountChanged
会话未读总数变更通知
详情请参考 会话未读数。5.3.425 及以上版本支持。
onUnreadMessageCountChangedByFilter
过滤条件下未读总数变更通知
详情请参考 会话未读数。7.0.3754 及以上版本支持。
注意
1. 为保证会话列表顺序符合最后一条消息的排序原则,每次会话变更/新增后,您需要对数据源重新排序。
如果您使用 5.5.892 以前的版本,可以使用 lastMessage 排序,但是需要注意处理 lastMessage 为空(例如清空会话消息)的情况。
如果您使用 5.5.892 及以后的版本,使用 orderKey 字段排序。我们强烈建议您升级到 5.5.892 及以后版本。
2. 调用 getConversationList 接口拉取的会话可能已经通过 onNewConversation 回调接口添加到了 UI 会话列表的数据源中。为了避免重复添加同一个会话,您需要在 UI 会话列表数据源中根据 getConversationID 找到相同的会话并做替换。
示例代码如下:
Android
iOS & Mac
Windows
// 监听会话的回调

V2TIMConversationListener conversationListener = new V2TIMConversationListener() {
@Override
public void onSyncServerStart() {
Log.i("imsdk", "onSyncServerStart");
}

@Override
public void onSyncServerFinish() {
Log.i("imsdk", "onSyncServerFinish");
}

@Override
public void onSyncServerFailed() {
Log.i("imsdk", "onSyncServerFailed");
}

@Override
public void onNewConversation(List<V2TIMConversation> conversationList) {
Log.i("imsdk", "onNewConversation");
}

@Override
public void onConversationChanged(List<V2TIMConversation> conversationList) {
Log.i("imsdk", "onConversationChanged");
}
@Override
public void onConversationDeleted(List<String> conversationIDList) {
Log.i("imsdk", "onConversationDeleted");
}

@Override
public void onTotalUnreadMessageCountChanged(long totalUnreadCount) {
Log.i("imsdk", "onTotalUnreadMessageCountChanged");
}
@Override
public void onUnreadMessageCountChangedByFilter(V2TIMConversationListFilter filter, long totalUnreadCount) {
Log.i("imsdk", "onUnreadMessageCountChangedByFilter");
}
};
- (void)onSyncServerStart {
// 同步服务器会话开始
}

- (void)onSyncServerFinish {
// 同步服务器会话结束
}

- (void)onSyncServerFailed {
// 同步服务器会话失败
}

- (void)onNewConversation:(NSArray<V2TIMConversation*> *)conversationList {
// 收到会话新增通知,conversationList 为新增的会话
[self updateConversation:conversationList];
}

- (void)onConversationChanged:(NSArray<V2TIMConversation*> *)conversationList {
// 收到会话变更通知,conversationList 中为变更后的会话对象
[self updateConversation:conversationList];
}


- (void)onConversationDeleted:(NSArray<NSString *> *)conversationIDList {
// 会话被删除
}

- (void)onTotalUnreadMessageCountChanged:(UInt64) totalUnreadCount {
// 会话未读总数变化
}


- (void)onUnreadMessageCountChangedByFilter:(V2TIMConversationListFilter *)filter totalUnreadCount:(UInt64)totalUnreadCount {
// 过滤条件下的会话未读总数变化
}

- (void)updateConversation:(NSArray *)convList {
// 更新 UI 会话列表,如果 UI 会话列表已经存在该新增/变更的会话,就替换之;如果没有,就新增一个会话对象
for (int i = 0 ; i < convList.count ; ++ i) {
V2TIMConversation *conv = convList[i];
BOOL isExit = NO;
for (int j = 0; j < self.localConvList.count; ++ j) {
V2TIMConversation *localConv = self.localConvList[j];
if ([localConv.conversationID isEqualToString:conv.conversationID]) {
// UI 会话列表有更新的会话,直接替换
[self.localConvList replaceObjectAtIndex:j withObject:conv];
isExit = YES;
break;
}
}
// UI 会话列表没有更新的会话,直接新增
if (!isExit) {
[self.localConvList addObject:conv];
}
}
// 重新对 UI 会话列表做排序
[self sortDataList:dataList];
self.dataList = dataList;
}

class ConversationListener final : public V2TIMConversationListener {
public:
ConversationListener() = default;
~ConversationListener() override = default;

void OnSyncServerStart() override {
// 同步服务器会话开始
}

void OnSyncServerFinish() override {
// 同步服务器会话结束
}

void OnSyncServerFailed() override {
// 同步服务器会话失败
}

void OnNewConversation(const V2TIMConversationVector& conversationList) override {
// 收到会话新增通知
}

void OnConversationChanged(const V2TIMConversationVector& conversationList) override {
// 收到会话变更通知
}
void OnConversationDeleted(const V2TIMStringVector &conversationIDList) override {
// 收到会话被删除通知
}

void OnTotalUnreadMessageCountChanged(uint64_t totalUnreadCount) override {
// 会话未读总数变更通知
}
void OnUnreadMessageCountChangedByFilter(const V2TIMConversationListFilter &filter, uint64_t totalUnreadCount) {
// 过滤条件下会话未读总数变更通知
}
};

// 添加会话事件监听器,注意在移除监听器之前需要保持 conversationListener 的生命期,以免接收不到事件回调
ConversationListener conversationListener;
V2TIMManager::GetInstance()->GetConversationManager()->AddConversationListener(&conversationListener);

移除会话监听器

您可以调用 removeConversationListenerAndroid / iOS & Mac / Windows )移除会话监听器。移除后,您将无法再接收到会话变更事件。 该步骤不是必须的,您可以按照自己的业务逻辑按需调用。
示例代码如下:
Android
iOS & Mac
Windows
V2TIMManager.getConversationManager().removeConversationListener(conversationListener);
// self 为 id<V2TIMConversationListener> 类型
[[V2TIMManager sharedInstance] removeConversationListener:self];
class ConversationListener final : public V2TIMConversationListener {
// 成员 ...
};

// conversationListener 是 ConversationListener 的实例
V2TIMManager::GetInstance()->GetConversationManager()->RemoveConversationListener(&conversationListener);

发送不更新 lastMessage 的消息

会话列表界面,通常需要展示每个会话的最新一条消息预览及发送时间,此时您可以使用 V2TIMConversationlastMessage 作为数据源实现。 但是某些场景下,如果您不希望一些消息(例如系统提示等)显示为会话的最新消息,可以在 sendMessage 时设置 isExcludedFromLastMessagefalse/NO
发送消息 sendMessage 的使用参考:发送消息
说明
isExcludedFromLastMessage 参数仅增强版 SDK 5.4.666 及以上版本支持。
示例代码如下:
Android
iOS & Mac
Windows
// 创建消息对象
V2TIMMessage v2TIMMessage = V2TIMManager.getMessageManager().createTextMessage(content);
// 设置不更新会话 lastMessage
v2TIMMessage.setExcludedFromLastMessage(true);

// 发送消息
V2TIMManager.getMessageManager().sendMessage(v2TIMMessage, "userID", null, V2TIMMessage.V2TIM_PRIORITY_DEFAULT, false, null, new V2TIMSendCallback<V2TIMMessage>() {
@Override
public void onSuccess(V2TIMMessage v2TIMMessage) {
Log.i("imsdk", "success");
}

@Override
public void onProgress(int progress) {
Log.i("imsdk", "progress:" + progress);
}

@Override
public void onError(int code, String desc) {
Log.i("imsdk", "failure, code:" + code + ", desc:" + desc);
}
});
// 创建消息对象
V2TIMMessage *message = [V2TIMManager.sharedInstance createTextMessage:content];
// 设置不计入会话 lastMessage 的标记
message.isExcludedFromLastMessage = YES;
// 发送消息
[V2TIMManager.sharedInstance sendMessage:message
receiver:@"userA"
groupID:nil
priority:V2TIM_PRIORITY_NORMAL
onlineUserOnly:NO
offlinePushInfo:nil
progress:^(uint32_t progress) {
// 发送进度
} succ:^{
// 消息发送成功
} fail:^(int code, NSString *desc) {
// 消息发送失败
}];
class SendCallback final : public V2TIMSendCallback {
public:
using SuccessCallback = std::function<void(const V2TIMMessage&)>;
using ErrorCallback = std::function<void(int, const V2TIMString&)>;
using ProgressCallback = std::function<void(uint32_t)>;

SendCallback() = default;
~SendCallback() override = default;

void SetCallback(SuccessCallback success_callback, ErrorCallback error_callback,
ProgressCallback progress_callback) {
success_callback_ = std::move(success_callback);
error_callback_ = std::move(error_callback);
progress_callback_ = std::move(progress_callback);
}

void OnSuccess(const V2TIMMessage& message) override {
if (success_callback_) {
success_callback_(message);
}
}
void OnError(int error_code, const V2TIMString& error_message) override {
if (error_callback_) {
error_callback_(error_code, error_message);
}
}
void OnProgress(uint32_t progress) override {
if (progress_callback_) {
progress_callback_(progress);
}
}

private:
SuccessCallback success_callback_;
ErrorCallback error_callback_;
ProgressCallback progress_callback_;
};

// 创建消息对象
V2TIMMessage message = V2TIMManager::GetInstance()->GetMessageManager()->CreateTextMessage(u8"content");
// 设置不更新会话 lastMessage
message.isExcludedFromLastMessage = true;

auto callback = new SendCallback{};
callback->SetCallback([=](const V2TIMMessage& message) { delete callback; },
[=](int error_code, const V2TIMString& error_message) { delete callback; },
[=](uint32_t progress) {});

V2TIMManager::GetInstance()->GetMessageManager()->SendMessage(
message, u8"userID", {}, V2TIMMessagePriority::V2TIM_PRIORITY_NORMAL, false, {}, callback);