tencent cloud

文档反馈

Android&iOS&Windows&Mac

最后更新时间:2025-01-03 10:36:21

    功能描述

    本地消息搜索,提升 App 使用体验必备功能,可以帮助用户从纷繁复杂的信息中直接找到预期内容,快捷方便;也可作为运营工具,增加相关内容的引导,简洁高效。
    说明
    消息搜索只能搜索本地存储的消息,例如接收到的消息、调用拉取历史消息接口得到的消息等。
    消息搜索功能仅增强版 SDK 5.4.666 及以上版本支持。
    本地消息搜索为进阶版功能,购买进阶版后可使用。

    消息搜索类介绍

    消息搜索参数类

    消息搜索参数类为 V2TIMMessageSearchParam(Java / Swift / Objective-C / C++)。搜索消息时,SDK 会按照该对象的设置,执行不同的搜索逻辑。
    V2TIMMessageSearchParam 的参数说明如下:
    参数
    含义
    说明
    keywordList
    关键字列表
    最多支持 5 个。当消息发送者以及消息类型均未指定时,必须设置关键字列表;否则,关键字列表可以为空。
    keywordListMatchType
    指定关键字列表匹配类型
    可设置为 “或” 关系搜索,或 “与” 关系搜索。取值分别为 V2TIM_KEYWORD_LIST_MATCH_TYPE_ORV2TIM_KEYWORD_LIST_MATCH_TYPE_AND。默认为 “或” 关系搜索。
    senderUserIDList
    指定 userID 发送的消息
    最多支持 5 个。
    messageTypeList
    指定搜索的消息类型集合
    传空表示搜索支持的全部类型消息(V2TIMFaceElemV2TIMGroupTipsElem 不支持搜索)。其他类型取值参考 V2TIMElemType(Java / Swift / Objective-C / C++)。
    conversationID
    搜索 “全部会话” 还是搜索 “指定的会话”
    conversationID 为空,搜索全部会话;conversationID 不为空,搜索指定会话。
    searchTimePosition
    搜索的起始时间点
    默认为 0(从现在开始搜索)。UTC 时间戳,单位:秒。
    searchTimePeriod
    从起始时间点开始的过去时间范围
    默认为 0(不限制时间范围)。24x60x60 代表过去一天。单位:秒。
    pageIndex
    分页的页号
    用于分页展示查找结果,0 表示首页。
    pageSize
    每页结果数量
    用于分页展示查找结果,如不希望分页可将其设置成 0。但如果结果数量太多,一次性拉取可能会引发性能问题。

    消息搜索结果类

    消息搜索结果类为 V2TIMMessageSearchResult(Java / Swift / Objective-C / C++)。参数说明如下:
    参数
    含义
    说明
    totalCount
    搜索结果总数
    如果搜索指定会话,返回满足搜索条件的消息总数
    如果搜索全部会话,返回满足搜索条件的消息所在的所有会话总数量
    messageSearchResultItems
    指定关键字列表匹配类型
    如果搜索指定会话,返回结果列表只包含该会话结果;
    如果搜索全部会话,会对满足搜索条件的消息根据会话 ID 分组,分页返回分组结果。
    其中 messageSearchResultItems 是个列表,内含 V2TIMMessageSearchResultItem(Java / Swift / Objective-C / C++) 对象,参数说明如下:
    参数
    含义
    说明
    conversationID
    会话 ID
    ——
    messageCount
    消息数量
    当前会话一共搜索到了多少条符合要求的消息。
    messageList
    满足搜索条件的消息列表
    如果搜索指定会话,messageList 中装载的是本会话中所有满足搜索条件的消息列表。
    如果搜索全部会话,messageList 中装载的消息条数会有如下两种可能:
    如果某个会话中匹配到的消息条数 > 1,则 messageList 为空,您可以在 UI 上显示 “{messageCount} 条相关记录”。
    如果某个会话中匹配到的消息条数 = 1,则 messageList 为匹配到的那条消息,您可以在 UI 上显示之,并高亮匹配关键词。

    搜索全部会话的消息

    当用户在搜索框输入关键字搜索消息时,您可以调用 searchLocalMessages (Java / Swift / Objective-C / C++) 搜索 IM SDK 本地存储的消息。
    如果您希望在全部会话范围内搜索,只需要将 V2TIMMessageSearchParam 中的 conversationID 设置为空或者不设置即可。
    示例代码如下:
    Java
    Swift
    Objective-C
    C++
    List<String> keywordList = new ArrayList<>();
    keywordList.add("abc");
    keywordList.add("123");
    V2TIMMessageSearchParam searchParam = new V2TIMMessageSearchParam();
    // 设置搜索关键字
    searchParam.setKeywordList(keywordList);
    // 搜索第 0 页数据
    searchParam.setPageIndex(0);
    // 每页搜索 10 条数据
    searchParam.setPageSize(10);
    V2TIMManager.getMessageManager().searchLocalMessages(searchParam, new V2TIMValueCallback<V2TIMMessageSearchResult>() {
    @Override
    public void onSuccess(V2TIMMessageSearchResult v2TIMMessageSearchResult) {
    // 搜索成功
    }
    
    @Override
    public void onError(int code, String desc) {
    // 搜索失败
    }
    });
    let param = V2TIMMessageSearchParam()
    param.keywordList = ["key1", "key2"]
    param.keywordListMatchType = .V2TIM_KEYWORD_LIST_MATCH_TYPE_AND
    param.senderUserIDList = ["1", "2"]
    param.messageTypeList = [.V2TIM_ELEM_TYPE_TEXT, .V2TIM_ELEM_TYPE_IMAGE]
    param.searchTimePosition = 100
    param.searchTimePeriod = 100
    // 搜索第 0 页数据
    param.pageIndex = 0
    // 每页搜索 10 条数据
    param.pageSize = 10
    
    V2TIMManager.shared.searchLocalMessages(param: param) { searchResult in
    print(searchResult.description)
    } fail: { code, desc in
    print("searchLocalMessages fail, \\(code), \\(desc)")
    }
    V2TIMMessageSearchParam *param = [[V2TIMMessageSearchParam alloc] init];
    // 设置搜索关键字
    param.keywordList = @[@"abc", @"123"];
    param.messageTypeList = nil;
    param.conversationID = nil;
    param.searchTimePosition = 0;
    param.searchTimePeriod = 0;
    // 搜索第 0 页数据
    param.pageIndex = 0;
    // 每页搜索 10 条数据
    param.pageSize = 10;
    [V2TIMManager.sharedInstance searchLocalMessages:param
    succ:^(V2TIMMessageSearchResult *searchResult) {
    // 搜索成功,searchResult 中返回搜索结果
    } 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_;
    };
    
    V2TIMMessageSearchParam searchParam;
    // 设置搜索关键字
    searchParam.keywordList.PushBack("abc");
    searchParam.keywordList.PushBack("123");
    // 搜索第 0 页数据
    searchParam.pageIndex = 0;
    // 每页搜索 10 条数据
    searchParam.pageSize = 10;
    
    auto callback = new ValueCallback<V2TIMMessageSearchResult>{};
    callback->SetCallback(
    [=](const V2TIMMessageSearchResult& messageSearchResult) {
    // 搜索成功
    delete callback;
    },
    [=](int error_code, const V2TIMString& error_message) {
    // 搜索失败
    delete callback;
    });
    
    V2TIMManager::GetInstance()->GetMessageManager()->SearchLocalMessages(searchParam, callback);

    搜索指定会话的消息

    当用户在搜索框输入关键字搜索消息时,您可以调用 searchLocalMessages (Java / Swift / Objective-C / C++) 搜索 IM SDK 本地存储的消息。
    示例代码如下:
    Java
    Swift
    Objective-C
    C++
    List<String> keywordList = new ArrayList<>();
    keywordList.add("abc");
    keywordList.add("123");
    V2TIMMessageSearchParam searchParam = new V2TIMMessageSearchParam();
    // 搜索与用户 user1 的单聊消息
    searchParam.setConversationID("c2c_user1");
    // 设置搜索关键字
    searchParam.setKeywordList(keywordList);
    // 搜索第 0 页数据
    searchParam.setPageIndex(0);
    // 每页搜索 10 条数据
    searchParam.setPageSize(10);
    V2TIMManager.getMessageManager().searchLocalMessages(searchParam, new V2TIMValueCallback<V2TIMMessageSearchResult>() {
    @Override
    public void onSuccess(V2TIMMessageSearchResult v2TIMMessageSearchResult) {
    // 搜索成功
    }
    
    @Override
    public void onError(int code, String desc) {
    // 搜索失败
    }
    });
    let param = V2TIMMessageSearchParam()
    param.keywordList = ["key1", "key2"]
    // 搜索与用户 user1 的单聊消息
    param.conversationID = "c2c_user1"
    param.searchTimePosition = 0
    param.searchTimePeriod = 0
    // 搜索第 0 页数据
    param.pageIndex = 0
    // 每页搜索 10 条数据
    param.pageSize = 10
    
    V2TIMManager.shared.searchLocalMessages(param: param) { searchResult in
    print(searchResult.description)
    } fail: { code, desc in
    print("searchLocalMessages fail, \\(code), \\(desc)")
    }
    V2TIMMessageSearchParam *param = [[V2TIMMessageSearchParam alloc] init];
    // 设置搜索关键字
    param.keywordList = @[@"abc", @"123"];
    param.messageTypeList = nil;
    // 搜索与用户 user1 的单聊消息
    param.conversationID = @"c2c_user1";
    param.searchTimePosition = 0;
    param.searchTimePeriod = 0;
    // 搜索第 0 页数据
    param.pageIndex = 0;
    // 每页搜索 10 条数据
    param.pageSize = 10;
    [V2TIMManager.sharedInstance searchLocalMessages:param
    succ:^(V2TIMMessageSearchResult *searchResult) {
    // 搜索成功,searchResult 中返回搜索结果
    } 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_;
    };
    
    V2TIMMessageSearchParam searchParam;
    // 搜索与用户 user1 的单聊消息
    searchParam.conversationID = "c2c_user1";
    // 设置搜索关键字
    searchParam.keywordList.PushBack("abc");
    searchParam.keywordList.PushBack("123");
    // 搜索第 0 页数据
    searchParam.pageIndex = 0;
    // 每页搜索 10 条数据
    searchParam.pageSize = 10;
    
    auto callback = new ValueCallback<V2TIMMessageSearchResult>{};
    callback->SetCallback(
    [=](const V2TIMMessageSearchResult& messageSearchResult) {
    // 搜索成功
    delete callback;
    },
    [=](int error_code, const V2TIMString& error_message) {
    // 搜索失败
    delete callback;
    });
    
    V2TIMManager::GetInstance()->GetMessageManager()->SearchLocalMessages(searchParam, callback);

    搜索典型场景示例

    普通的 IM 聊天软件,搜索界面的展示通常分这几种场景:
    图 1:搜索聊天记录
    图 2:搜索更多聊天记录
    图 3:搜索指定会话的消息
    
    
    
    
    
    
    
    
    
    下文我们将依次向您展示如何利用 IM SDK 的搜索 API 实现上图的典型场景。

    展示最近几个活跃的会话

    如图 1 所示,最下方是搜索到的消息所属的最近 3 个会话列表,实现方式如下:
    1. 设置搜索参数 V2TIMMessageSearchParam
    conversationID 设置为 null,表示搜索所有会话的消息。
    pageIndex 设置为 0,表示搜索到的消息所属的会话的首页数据。
    pageSize 设置为 3,表示返回最近的会话数量,UI 上一般显示 3 条。
    2. 处理搜索回调结果 V2TIMMessageSearchResult
    totalCount 表示匹配到的消息所属的所有会话数量。
    messageSearchResultItems 列表为最近 3(即入参 pageSize)个会话信息。其中元素 V2TIMMessageSearchResultItemmessageCount 表示当前会话搜索到的消息总数量;
    搜索到的消息条数 > 1,则 messageList 为空,您可以在 UI 上显示 “4 条相关聊天记录”,其中的 4 为 messageCount
    搜索到的消息条数 = 1,则 messageList 为匹配到的那条消息,您可以在 UI 上显示消息内容并高亮搜索关键词,例如图中的 “test”。
    示例代码如下:
    Java
    Swift
    Objective-C
    C++
    List<String> keywordList = new ArrayList<>();
    keywordList.add("test");
    V2TIMMessageSearchParam v2TIMMessageSearchParam = new V2TIMMessageSearchParam();
    // conversationID 设置为 null 表示搜索所有会话中的消息,结果会按照会话分类
    v2TIMMessageSearchParam.setConversationID(null);
    v2TIMMessageSearchParam.setKeywordList(keywordList);
    v2TIMMessageSearchParam.setPageSize(3);
    v2TIMMessageSearchParam.setPageIndex(0);
    V2TIMManager.getMessageManager().searchLocalMessages(v2TIMMessageSearchParam, new V2TIMValueCallback<V2TIMMessageSearchResult>() {
    @Override
    public void onSuccess(V2TIMMessageSearchResult v2TIMMessageSearchResult) {
    // 匹配到的消息所属的所有会话数量
    int totalCount = v2TIMMessageSearchResult.getTotalCount();
    // 最近3个根据消息会话分类的信息
    List<V2TIMMessageSearchResultItem> resultItemList = v2TIMMessageSearchResult.getMessageSearchResultItems();
    for (V2TIMMessageSearchResultItem resultItem : resultItemList) {
    // 会话 ID
    String conversationID = resultItem.getConversationID();
    // 该会话匹配到的所有消息数量
    int totalMessageCount = resultItem.getMessageCount();
    // 消息列表:如果 totalMessageCount > 1,该列表为空;如果 totalMessageCount = 1,该列表元素为此消息
    List<V2TIMMessage> v2TIMMessageList = resultItem.getMessageList();
    }
    }
    
    @Override
    public void onError(int code, String desc) {}
    });
    let param = V2TIMMessageSearchParam()
    param.keywordList = ["test"]
    // conversationID 设置为 nil 表示搜索所有会话中的消息,结果会按照会话分类
    param.conversationID = nil
    param.pageIndex = 0
    param.pageSize = 3
    
    V2TIMManager.shared.searchLocalMessages(param: param, succ: { searchResult in
    // 匹配到的消息所属的所有会话数量
    let totalCount = searchResult.totalCount
    // 最近3个根据消息会话分类的信息
    let messageSearchResultItems = searchResult.messageSearchResultItems
    for searchItem in messageSearchResultItems {
    // 会话 ID
    let conversationID = searchItem.conversationID
    // 该会话匹配到的所有消息数量
    let messageCount = searchItem.messageCount
    // 消息列表
    let messageList = searchItem.messageList ?? []
    }
    }, fail: { code, desc in
    // fail
    })
    
    V2TIMMessageSearchParam *param = [[V2TIMMessageSearchParam alloc] init];
    param.keywordList = @[@"test"];
    // conversationID 设置为 nil 表示搜索所有会话中的消息,结果会按照会话分类
    param.conversationID = nil;
    param.pageIndex = 0;
    param.pageSize = 3;
    [V2TIMManager.sharedInstance searchLocalMessages:param succ:^(V2TIMMessageSearchResult *searchResult) {
    // 匹配到的消息所属的所有会话数量
    NSInteger totalCount = searchResult.totalCount;
    // 最近3个根据消息会话分类的信息
    NSArray<V2TIMMessageSearchResultItem *> *messageSearchResultItems = searchResult.messageSearchResultItems;
    for (V2TIMMessageSearchResultItem *searchItem in messageSearchResultItems) {
    // 会话 ID
    NSString *conversationID = searchItem.conversationID;
    // 该会话匹配到的所有消息数量
    NSUInteger messageCount = searchItem.messageCount;
    // 消息列表
    NSArray<V2TIMMessage *> *messageList = searchItem.messageList ?: @[];
    }
    } fail:^(int code, NSString *desc) {
    // fail
    }];
    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_;
    };
    
    V2TIMMessageSearchParam searchParam;
    // conversationID 设置为空表示搜索所有会话中的消息,结果会按照会话分类
    searchParam.conversationID = {};
    searchParam.keywordList.PushBack("test");
    searchParam.pageIndex = 0;
    searchParam.pageSize = 3;
    
    auto callback = new ValueCallback<V2TIMMessageSearchResult>{};
    callback->SetCallback(
    [=](const V2TIMMessageSearchResult& messageSearchResult) {
    // 匹配到的消息所属的所有会话数量
    uint32_t totalCount = messageSearchResult.totalCount;
    // 最近3个根据消息会话分类的信息
    V2TIMMessageSearchResultItemVector messageSearchResultItems =
    messageSearchResult.messageSearchResultItems;
    for (size_t i = 0; i < messageSearchResultItems.Size(); ++i) {
    // 会话 ID
    V2TIMString conversationID = messageSearchResultItems[i].conversationID;
    // 该会话匹配到的所有消息数量
    uint32_t messageCount = messageSearchResultItems[i].messageCount;
    // 消息列表:如果 messageCount > 1,该列表为空;如果 messageCount = 1,该列表元素为此消息
    V2TIMMessageVector messageList = messageSearchResultItems[i].messageList;
    }
    delete callback;
    },
    [=](int error_code, const V2TIMString& error_message) {
    // 搜索失败
    delete callback;
    });
    
    V2TIMManager::GetInstance()->GetMessageManager()->SearchLocalMessages(searchParam, callback);

    展示所有搜索到的消息所属会话列表

    点击图 1 中的 “更多聊天记录”,会跳转到图 2,展示所有搜索到的消息所属的会话列表。搜索参数和搜索结果描述跟上文的场景类似。
    为了防止内存膨胀,我们强烈建议您分页加载会话列表。 举个例子,分页加载,每页展示 10 条会话结果,搜索参数 V2TIMMessageSearchParam 可以参考如下设置:
    1. 首次调用:设置参数 pageSize = 10,pageIndex = 0。调用 searchLocalMessages 获取消息搜索结果,解析并展示到首页,并且从结果回调中的 totalCount 获取会话总数量。
    2. 计算页数:totalPage = (totalCount % pageSize == 0) ? (totalCount / pageSize) : (totalCount / pageSize + 1) 。
    3. 再次调用:可以通过设置参数 pageIndexpageIndex < totalPage)查询后续指定页数的搜索结果。
    示例代码如下:
    Java
    Swift
    Objective-C
    C++
    ......
    // 每页展示数量为10条,计算总页数
    int totalPage = (totalCount % 10 == 0) ? (totalCount / 10) : (totalCount / 10 + 1);
    ......
    
    private void searchConversation(int index) {
    if (index >= totalPage) {
    return;
    }
    List<String> keywordList = new ArrayList<>();
    keywordList.add("test");
    V2TIMMessageSearchParam v2TIMMessageSearchParam = new V2TIMMessageSearchParam();
    v2TIMMessageSearchParam.setConversationID(null);
    v2TIMMessageSearchParam.setKeywordList(keywordList);
    v2TIMMessageSearchParam.setPageSize(10);
    v2TIMMessageSearchParam.setPageIndex(index);
    V2TIMManager.getMessageManager().searchLocalMessages(v2TIMMessageSearchParam, new V2TIMValueCallback<V2TIMMessageSearchResult>() {
    @Override
    public void onSuccess(V2TIMMessageSearchResult v2TIMMessageSearchResult) {
    // 匹配到的消息所属的所有会话数量
    int totalCount = v2TIMMessageSearchResult.getTotalCount();
    // 每页展示数量为10条,计算总页数
    int totalPage = (totalCount % 10 == 0) ? (totalCount / 10) : (totalCount / 10 + 1);
    // 该页的根据消息会话分类的信息
    List<V2TIMMessageSearchResultItem> resultItemList = v2TIMMessageSearchResult.getMessageSearchResultItems();
    for (V2TIMMessageSearchResultItem resultItem : resultItemList) {
    // 会话 ID
    String conversationID = resultItem.getConversationID();
    // 该会话匹配到的所有消息数量
    int totalMessageCount = resultItem.getMessageCount();
    // 消息列表:如果 totalMessageCount > 1,该列表为空;如果 totalMessageCount = 1,该列表元素为此消息
    List<V2TIMMessage> v2TIMMessageList = resultItem.getMessageList();
    }
    }
    
    @Override
    public void onError(int code, String desc) {}
    });
    }
    
    // 当需要加载下一页时
    public void loadMore() {
    searchConversation(++pageIndex);
    }
    ......
    // 每页展示数量为10条,计算总页数
    let totalPage = (totalCount % 10 == 0) ? (totalCount / 10) : (totalCount / 10 + 1)
    ......
    func searchConversation(index: UInt) {
    if index >= totalPage {
    return
    }
    let param = V2TIMMessageSearchParam()
    param.keywordList = ["test"]
    param.conversationID = nil
    param.pageIndex = index
    param.pageSize = 10
    V2TIMManager.shared.searchLocalMessages(param: param, succ: { searchResult in
    // 匹配到的消息所属的所有会话数量
    let totalCount = searchResult.totalCount
    // 每页展示数量为10条,计算总页数
    let totalPage = (totalCount % 10 == 0) ? (totalCount / 10) : (totalCount / 10 + 1)
    // 该页的根据消息会话分类的信息
    let messageSearchResultItems = searchResult.messageSearchResultItems
    for searchItem in messageSearchResultItems {
    // 会话 ID
    let conversationID = searchItem.conversationID
    // 该会话匹配到的所有消息数量
    let totalMessageCount = searchItem.messageCount
    // 消息列表:如果 totalMessageCount > 1,该列表为空;如果 totalMessageCount = 1,该列表元素为此消息
    let messageList = searchItem.messageList ?? []
    }
    }, fail: { code, desc in
    // fail
    })
    }
    
    // 当需要加载下一页时
    func loadMore() {
    pageIndex += 1
    searchConversation(index: pageIndex)
    }
    ......
    // 每页展示数量为10条,计算总页数
    NSInteger totalPage = (totalCount % 10 == 0) ? (totalCount / 10) : (totalCount / 10 + 1);
    ......
    
    - (void)searchConversation:(NSUInteger)index {
    if (index >= totalPage) {
    return;
    }
    V2TIMMessageSearchParam *param = [[V2TIMMessageSearchParam alloc] init];
    param.keywordList = @[@"test"];
    param.conversationID = nil;
    param.pageIndex = index;
    param.pageSize = 10;
    [V2TIMManager.sharedInstance searchLocalMessages:param succ:^(V2TIMMessageSearchResult *searchResult) {
    // 匹配到的消息所属的所有会话数量
    NSUInteger totalCount = searchResult.totalCount;
    // 每页展示数量为10条,计算总页数
    NSUInteger totalPage = (totalCount % 10 == 0) ? (totalCount / 10) : (totalCount / 10 + 1);
    // 该页的根据消息会话分类的信息
    NSArray<V2TIMMessageSearchResultItem *> *messageSearchResultItems = searchResult.messageSearchResultItems;
    for (V2TIMMessageSearchResultItem *searchItem in messageSearchResultItems) {
    // 会话 ID
    NSString *conversationID = searchItem.conversationID;
    // 该会话匹配到的所有消息数量
    NSUInteger totalMessageCount = searchItem.messageCount;
    // 消息列表:如果 totalMessageCount > 1,该列表为空;如果 totalMessageCount = 1,该列表元素为此消息
    NSArray<V2TIMMessage *> *messageList = searchItem.messageList ?: @[];
    }
    } fail:^(int code, NSString *desc) {
    // fail
    }];
    }
    
    // 当需要加载下一页时
    - (void)loadMore {
    [self searchConversation:++pageIndex];
    }
    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_;
    };
    
    // 每页展示数量为10条,计算总页数
    uint32_t totalPage = (totalCount % 10 == 0) ? (totalCount / 10) : (totalCount / 10 + 1);
    
    void SearchConversation(uint32_t index) {
    if (index >= totalPage) {
    return;
    }
    
    V2TIMMessageSearchParam searchParam;
    searchParam.keywordList.PushBack("test");
    searchParam.pageIndex = index;
    searchParam.pageSize = 10;
    
    auto callback = new ValueCallback<V2TIMMessageSearchResult>{};
    callback->SetCallback(
    [=](const V2TIMMessageSearchResult& messageSearchResult) {
    // 匹配到的消息所属的所有会话数量
    uint32_t totalCount = messageSearchResult.totalCount;
    // 每页展示数量为10条,计算总页数
    uint32_t totalPage = (totalCount % 10 == 0) ? (totalCount / 10) : (totalCount / 10 + 1);
    // 该页的根据消息会话分类的信息
    V2TIMMessageSearchResultItemVector messageSearchResultItems =
    messageSearchResult.messageSearchResultItems;
    for (size_t i = 0; i < messageSearchResultItems.Size(); ++i) {
    // 会话 ID
    V2TIMString conversationID = messageSearchResultItems[i].conversationID;
    // 该会话匹配到的所有消息数量
    uint32_t messageCount = messageSearchResultItems[i].messageCount;
    // 消息列表:如果 messageCount > 1,该列表为空;如果 messageCount = 1,该列表元素为此消息
    V2TIMMessageVector messageList = messageSearchResultItems[i].messageList;
    }
    delete callback;
    },
    [=](int error_code, const V2TIMString& error_message) {
    // 搜索失败
    delete callback;
    });
    
    V2TIMManager::GetInstance()->GetMessageManager()->SearchLocalMessages(searchParam, callback);
    }
    
    // 当需要加载下一页时
    void LoadMore() { SearchConversation(++pageIndex); }

    展示搜索指定会话的消息

    与图 2 展示会话列表不同的是,图 3 所示在指定会话中搜索到的消息列表。 为了防止内存膨胀,我们强烈建议您分页加载消息。举个例子,分页加载,每页展示 10 条消息结果:
    1. 搜索参数 V2TIMMessageSearchParam 可以参考如下设置(pageIndex 的计算与上一节一致):
    设置搜索参数 V2TIMMessageSearchParamconversationID 为搜索的会话 ID。
    首次调用:设置参数 pageSize = 10,pageIndex = 0。调用 searchLocalMessages 获取消息搜索结果,解析并展示到首页,并且从结果回调中的 totalCount 获取会话总数量。
    计算页数:totalPage = (totalCount % pageSize == 0) ? (totalCount / pageSize) : (totalCount / pageSize + 1) 。
    再次调用:可以通过设置参数 pageIndexpageIndex < totalPage)查询后续指定页数的搜索结果。
    2. 处理搜索结果 V2TIMMessageSearchResult:
    totalCount 表示该会话匹配到的所有消息数量。
    messageSearchResultItems 列表只有该会话的结果。列表中的元素 V2TIMMessageSearchResultItemmessageCount 为该分页的消息数量,messageList 为该分页的消息列表。
    示例代码如下:
    Java
    Swift
    Objective-C
    C++
    ......
    // 每页展示数量为10条,计算总页数
    int totalMessagePage = (totalMessageCount % 10 == 0) ? (totalMessageCount / 10) : (totalMessageCount / 10 + 1);
    ......
    
    private void searchMessage(int index) {
    if (index >= totalMessagePage) {
    return;
    }
    List<String> keywordList = new ArrayList<>();
    keywordList.add("test");
    V2TIMMessageSearchParam v2TIMMessageSearchParam = new V2TIMMessageSearchParam();
    v2TIMMessageSearchParam.setConversationID(conversationID);
    v2TIMMessageSearchParam.setKeywordList(keywordList);
    v2TIMMessageSearchParam.setPageSize(10);
    v2TIMMessageSearchParam.setPageIndex(index);
    V2TIMManager.getMessageManager().searchLocalMessages(v2TIMMessageSearchParam, new V2TIMValueCallback<V2TIMMessageSearchResult>() {
    @Override
    public void onSuccess(V2TIMMessageSearchResult v2TIMMessageSearchResult) {
    // 该会话匹配到的所有消息数量
    int totalMessageCount = v2TIMMessageSearchResult.getTotalCount();
    // 每页展示数量为10条,计算总页数
    int totalMessagePage = (totalMessageCount % 10 == 0) ? (totalMessageCount / 10) : (totalMessageCount / 10 + 1);
    // 该页消息信息
    List<V2TIMMessageSearchResultItem> resultItemList = v2TIMMessageSearchResult.getMessageSearchResultItems();
    for (V2TIMMessageSearchResultItem resultItem : resultItemList) {
    // 会话 ID
    String conversationID = resultItem.getConversationID();
    // 该页的消息数量
    int totalMessageCount = resultItem.getMessageCount();
    // 该页的消息数据列表
    List<V2TIMMessage> v2TIMMessageList = resultItem.getMessageList();
    }
    }
    
    @Override
    public void onError(int code, String desc) {
    }
    });
    }
    // 当需要加载下一页时
    public void loadMore() {
    searchMessage(++pageIndex);
    }
    ......
    // 每页展示数量为10条,计算总页数
    let totalMessagePage = (totalMessageCount % 10 == 0) ? (totalMessageCount / 10) : (totalMessageCount / 10 + 1)
    ......
    func searchMessage(index: UInt) {
    if index >= totalMessagePage {
    return
    }
    let param = V2TIMMessageSearchParam()
    param.keywordList = ["test"]
    param.conversationID = "conversationID"
    param.pageIndex = index
    param.pageSize = 10
    V2TIMManager.shared.searchLocalMessages(param: param, succ: { searchResult in
    // 该会话匹配到的所有消息数量
    let totalMessageCount = searchResult.totalCount
    // 每页展示数量为10条,计算总页数
    let totalMessagePage = (totalMessageCount % 10 == 0) ? (totalMessageCount / 10) : (totalMessageCount / 10 + 1)
    // 该页消息信息
    let messageSearchResultItems = searchResult.messageSearchResultItems
    for searchItem in messageSearchResultItems {
    // 会话 ID
    let conversationID = searchItem.conversationID
    // 该页的消息数量
    let totalMessageCount = searchItem.messageCount
    // 该页的消息数据列表
    let messageList = searchItem.messageList ?? []
    }
    }, fail: { code, desc in
    // fail
    })
    }
    
    // 当需要加载下一页时
    func loadMore() {
    pageIndex += 1
    searchMessage(index: pageIndex)
    }
    ......
    // 每页展示数量为10条,计算总页数
    NSInteger totalMessagePage = (totalMessageCount % 10 == 0) ? (totalMessageCount / 10) : (totalMessageCount / 10 + 1);
    ......
    
    - (void)searchMessage:(NSUInteger)index {
    if (index >= totalMessagePage) {
    return;
    }
    V2TIMMessageSearchParam *param = [[V2TIMMessageSearchParam alloc] init];
    param.keywordList = @[@"test"];
    param.conversationID = conversationID;
    param.pageIndex = index;
    param.pageSize = 10;
    [V2TIMManager.sharedInstance searchLocalMessages:param succ:^(V2TIMMessageSearchResult *searchResult) {
    // 该会话匹配到的所有消息数量
    NSUInteger totalMessageCount = searchResult.totalCount;
    // 每页展示数量为10条,计算总页数
    NSUInteger totalMessagePage = (totalMessageCount % 10 == 0) ? (totalMessageCount / 10) : (totalMessageCount / 10 + 1);
    // 该页消息信息
    NSArray<V2TIMMessageSearchResultItem *> *messageSearchResultItems = searchResult.messageSearchResultItems;
    for (V2TIMMessageSearchResultItem *searchItem in messageSearchResultItems) {
    // 会话 ID
    NSString *conversationID = searchItem.conversationID;
    // 该页的消息数量
    NSUInteger totalMessageCount = searchItem.messageCount;
    // 该页的消息数据列表
    NSArray<V2TIMMessage *> *messageList = searchItem.messageList ?: @[];
    }
    } fail:^(int code, NSString *desc) {
    // fail
    }];
    }
    
    // 当需要加载下一页时
    - (void)loadMore {
    [self searchMessage:++pageIndex];
    }
    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_) {