tencent cloud

Feedback

Android&iOS&Windows&Mac

Last updated: 2024-04-30 15:58:27

    Description

    Cloud message search, a must-have feature to enhance the App user experience, enables users to directly find the desired content from complex information quickly and conveniently. It can also serve as an OPS tool, facilitating efficient and concise guidance to related content.
    Note:
    The cloud message search feature is supported only by version 7.3.4358 or later.
    This feature is a value-added feature, see Billing Overview for more information.
    If this service is not activated, calling the interface will return the error code 60020.

    Message Search Class

    Message Search Parameter Class

    The message search parameter class is V2TIMMessageSearchParam (Android/iOS & Mac/Windows). When searching for messages, the SDK will execute different search logics based on this object's settings.
    The parameters of V2TIMMessageSearchParam are as follows:
    Parameter
    Meaning
    Description
    keywordList
    Keyword list
    It can contain up to five keywords. When the message sender and the message type are not specified, the keyword list must be set; in other cases, it can be left empty.
    keywordListMatchType
    Match type of the keyword list
    You can set it to search with "OR" logic or "AND" logic. The values are V2TIM_KEYWORD_LIST_MATCH_TYPE_OR and V2TIM_KEYWORD_LIST_MATCH_TYPE_AND, respectively. By default, it uses "OR" logic.
    senderUserIDList
    Search for messages sent by a specified userID
    Up to five are supported.
    messageTypeList
    Set of the message types to be searched for
    Leaving it empty means searching for all supported types of messages (V2TIMFaceElem and V2TIMGroupTipsElem are not searchable). Refer to V2TIMElemType (Android/iOS & Mac/Windows) for other types.
    conversationID
    Search "all conversations" or "a specified conversation"
    If conversationID is empty, search all sessions; if conversationID is not empty, search the specified session.
    searchTimePosition
    Start time for the search
    The default is 0 (search from now). UTC Timestamp, in seconds.
    searchTimePeriod
    A past period of time starting from the start time
    The default is 0 (unlimited time range). 24 x 60 x 60 represents the past day, in seconds.
    searchCount
    Number of search results
    Number of searches, support up to 100.
    searchCursor
    Search cursor
    Starting position, fill in an empty character string for the first time, and fill in the searchCursor from the last V2TIMMessageSearchResult returned for subsequent pulls.

    Message Search Result Class

    The message search result class is V2TIMMessageSearchResult(Android/iOS & Mac/Windows). The parameters are as described below:
    Parameter
    Meaning
    Description
    totalCount
    Total number of the search result items
    If a specific session is searched, the total number of messages that meet the search criteria will be returned;
    If all sessions are searched, the total number of sessions containing messages that meet the search criteria will be returned.
    messageSearchResultItems
    Search results list
    If a specific session is searched, the returned result list will only include results from that session;
    If all sessions are searched, messages that meet the search criteria will be grouped by session ID, and the grouping results will be returned paginated.
    searchCursor
    Continue pulling the cursor
    Cursor required for continuation while calling the search API
    Here, messageSearchResultItems is a list containing V2TIMMessageSearchResultItem(Android/iOS & Mac/Windows) objects, with the parameters described as follows:
    Parameter
    Meaning
    Description
    conversationID
    Session ID
    -
    messageCount
    Number of messages
    The total number of messages matching the criteria found in the current session.
    messageList
    List of messages that meet the search criteria
    If a specific session is searched, messageList contains a list of all messages meeting the search criteria within this session.
    If all sessions are searched, the number of messages contained in messageList may have the following two possibilities:
    If the number of messages matched in a session is > 1, then messageList is empty, and you can display "{messageCount} relevant records" on the UI.
    If the number of messages matched in a session = 1, then messageList is the matched message, and you can display it on the UI and highlight the search keywords.

    Searching Messages in All Sessions

    When a user enters keywords in the search box to search for messages, you can call searchCloudMessages(Android/iOS and Mac/Windows) to search for messages.
    If you want to search within the scope of all sessions, you just need to leave conversationID in V2TIMMessageSearchParam unset or set to empty.
    Below is the sample code:
    Android
    iOS & Mac
    Windows
    List<String> keywordList = new ArrayList<>();
    keywordList.add("abc");
    keywordList.add("123");
    V2TIMMessageSearchParam searchParam = new V2TIMMessageSearchParam();
    // Set the keyword for the search
    searchParam.setKeywordList(keywordList);
    // Search for 20 data entries
    searchParam.setSearchCount(20);
    // Start searching from the latest session
    searchParam.setSearchCursor("");
    // Start searching from the current time
    searchParam.setSearchTimePosition(0);
    // Search for messages within 10 minutes
    searchParam.setSearchTimePeriod(600);
    V2TIMManager.getMessageManager().searchCloudMessages(searchParam,newV2TIMValueCallback<V2TIMMessageSearchResult>() {
    @Override
    public void onSuccess(V2TIMMessageSearchResult v2TIMMessageSearchResult) {
    // Data found successfully
    }
    @Override
    public void onError(int code, String desc) {
    // Failed to find the data
    }
    });
    V2TIMMessageSearchParam *param = [[V2TIMMessageSearchParam alloc] init];
    // Set the keyword for the search
    param.keywordList = @[@"abc", @"123"];
    param.messageTypeList = nil;
    param.conversationID = nil;
    param.searchTimePosition = 0;
    param.searchTimePeriod = 0;
    // Search for 20 data entries
    param.searchCount = 20;
    // Start searching from the latest session
    param.searchCursor = @"";
    [V2TIMManager.sharedInstance searchCloudMessages:param
    succ:^(V2TIMMessageSearchResult *searchResult) {
    // The search was successful, and the search results are returned in searchResult
    } fail:^(int code, NSString *desc) {
    // Failed to find the data
    }];
    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;
    // Set the keyword for the search
    searchParam.keywordList.PushBack("abc");
    searchParam.keywordList.PushBack("123");
    // Search for 20 data entries
    searchParam.searchCount = 20;
    // Start searching from the latest session
    searchParam.searchCursor = "";
    
    auto callback = new ValueCallback<V2TIMMessageSearchResult>{};
    callback->SetCallback(
    [=](const V2TIMMessageSearchResult& messageSearchResult) {
    // Data found successfully
    delete callback;
    },
    [=](int error_code, const V2TIMString& error_message) {
    // Failed to find the data
    delete callback;
    });
    
    V2TIMManager::GetInstance()->GetMessageManager()->SearchCloudMessages(searchParam, callback);

    Searching for the Messages in the Specified Session

    When a user enters keywords in the search box to search for messages, you can call searchCloudMessages (Android/iOS and Mac/Windows) to search for messages.
    Below is the sample code:
    Android
    iOS & Mac
    Windows
    List<String> keywordList = new ArrayList<>();
    keywordList.add("abc");
    keywordList.add("123");
    V2TIMMessageSearchParam searchParam = new V2TIMMessageSearchParam();
    // Search for one-to-one messages with the 'user1' user
    searchParam.setConversationID("c2c_user1");
    // Set the keyword for the search
    searchParam.setKeywordList(keywordList);
    // Search for 20 data entries
    searchParam.setSearchCount(20);
    // Start searching from the latest session
    searchParam.setSearchCursor("");
    // Start searching from the current time
    searchParam.setSearchTimePosition(0);
    // Search for messages within 10 minutes
    searchParam.setSearchTimePeriod(600);
    V2TIMManager.getMessageManager().searchCloudMessages(searchParam,newV2TIMValueCallback<V2TIMMessageSearchResult>() {
    @Override
    public void onSuccess(V2TIMMessageSearchResult v2TIMMessageSearchResult) {
    // Data found successfully
    }
    @Override
    public void onError(int code, String desc) {
    // Failed to find the data
    }
    });
    V2TIMMessageSearchParam *param = [[V2TIMMessageSearchParam alloc] init];
    // Set the keyword for the search
    param.keywordList = @[@"abc", @"123"];
    param.messageTypeList = nil;
    // Search for one-to-one messages with the 'user1' user
    param.conversationID = @"c2c_user1";
    param.searchTimePosition = 0;
    param.searchTimePeriod = 0;
    // Search for 20 data entries
    param.searchCount = 20;
    // Start searching from the latest session
    param.searchCursor = @"";
    [V2TIMManager.sharedInstance searchCloudMessages:param
    succ:^(V2TIMMessageSearchResult *searchResult) {
    // The search was successful, and the search results are returned in searchResult
    } fail:^(int code, NSString *desc) {
    // Failed to find the data
    }];
    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;
    // Search for one-to-one messages with the 'user1' user
    searchParam.conversationID = "c2c_user1";
    // Set the keyword for the search
    searchParam.keywordList.PushBack("abc");
    searchParam.keywordList.PushBack("123");
    // Search for 20 data entries
    searchParam.searchCount = 20;
    // Start searching from the latest session
    searchParam.searchCursor = "";
    
    auto callback = new ValueCallback<V2TIMMessageSearchResult>{};
    callback->SetCallback(
    [=](const V2TIMMessageSearchResult& messageSearchResult) {
    // Data found successfully
    delete callback;
    },
    [=](int error_code, const V2TIMString& error_message) {
    // Failed to find the data
    delete callback;
    });
    
    V2TIMManager::GetInstance()->GetMessageManager()->SearchCloudMessages(searchParam, callback);

    Typical Use Cases for the Search

    In general IM chat software, a search UI is usually displayed as follows:
    Figure 1. Chat Record
    Figure 2. More Chat Record
    Figure 3. Messages in the specified session
    
    
    
    The following describes how to implement the above use cases through IM SDK's search APIs.

    Displaying the Latest Active Sessions

    As shown in Figure 1, a list of the latest three sessions to which the messages found belong is displayed at the bottom. The implementation method is as follows:
    1. Setting search parameters V2TIMMessageSearchParam
    conversationID set to null, indicates searching messages from all sessions.
    searchCursor set to "", indicates searching for the latest data.
    searchCount set to 3, indicates returning the number of the most recent sessions, typically showing 3 entries on the UI.
    2. Handling search callback results V2TIMMessageSearchResult
    totalCount indicates the number of all sessions to which the matched messages belong.
    The messageSearchResultItems list contains the last 3 sessions (as per the searchCount parameter). messageCount of V2TIMMessageSearchResultItem indicates the total number of messages found in the current session;
    If the number of messages found is > 1, then messageList will be empty. You can display "4 related chat records" on the UI, where 4 represents the messageCount.
    If the number of messages found = 1, then messageList is the message that matches. You can display the message content on the UI and highlight the search keyword, for example, "test" in the Typical Use Cases for the Search image.
    Below is the sample code:
    Android
    iOS & Mac
    Windows
    List<String> keywordList = new ArrayList<>();
    keywordList.add("test");
    V2TIMMessageSearchParam v2TIMMessageSearchParam = new V2TIMMessageSearchParam();
    // Setting `conversationID` to `null` is to search for messages in all sessions and the results will be classified by session
    v2TIMMessageSearchParam.setConversationID(null);
    v2TIMMessageSearchParam.setKeywordList(keywordList);
    v2TIMMessageSearchParam.setSearchCursor("");
    v2TIMMessageSearchParam.setSearchCount(3);
    V2TIMManager.getMessageManager().searchCloudMessages(v2TIMMessageSearchParam, newV2TIMValueCallback<V2TIMMessageSearchResult>() {
    @Override
    public void onSuccess(V2TIMMessageSearchResult v2TIMMessageSearchResult) {
    // Total number of matched sessions to which messages belong
    int totalCount = v2TIMMessageSearchResult.getTotalCount();
    // Last three messages classified by session
    List<V2TIMMessageSearchResultItem> resultItemList = v2TIMMessageSearchResult.getMessageSearchResultItems();
    for (V2TIMMessageSearchResultItem resultItem : resultItemList) {
    // Session ID
    String conversationID = resultItem.getConversationID();
    // Total number of messages matching the session
    int totalMessageCount = resultItem.getMessageCount();
    // Message list: If totalMessageCount > 1, this list is empty; if totalMessageCount = 1, this list Element (XML) is this message
    List<V2TIMMessage> v2TIMMessageList = resultItem.getMessageList();
    }
    }
    @Override
    public void onError(int code, String desc) {
    }
    });
    V2TIMMessageSearchParam *param = [[V2TIMMessageSearchParam alloc] init];
    param.keywordList = @[@"test"];
    // Setting `conversationID` to `nil` is to search for messages in all sessions and the results will be classified by session
    param.conversationID = nil;
    param.searchCursor = @"";
    param.searchCount = 3;
    [V2TIMManager.sharedInstance searchCloudMessages:param succ:^(V2TIMMessageSearchResult *searchResult) {
    // Total number of matched conversations to which messages belong
    NSInteger totalCount = searchResult.totalCount;
    // Last three messages classified by session
    NSArray<V2TIMMessageSearchResultItem *> *messageSearchResultItems = searchResult.messageSearchResultItems;
    for (V2TIMMessageSearchResultItem *searchItem in messageSearchResultItems) {
    // Conversation ID
    NSString *conversationID = searchItem.conversationID;
    // Total number of messages matching the session
    NSUInteger messageCount = searchItem.messageCount;
    // Message list
    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;
    // Setting conversationID to null searches for messages in all sessions, and results will be classified by session
    searchParam.conversationID = "";
    searchParam.keywordList.PushBack("test");
    searchParam.searchCursor = "";
    searchParam.searchCount = 3;
    
    auto callback = new ValueCallback<V2TIMMessageSearchResult>{};
    callback->SetCallback(
    [=](const V2TIMMessageSearchResult& messageSearchResult) {
    // Total number of matched sessions to which messages belong
    uint32_t totalCount = messageSearchResult.totalCount;
    // Last three messages classified by session
    V2TIMMessageSearchResultItemVector messageSearchResultItems =
    messageSearchResult.messageSearchResultItems;
    for (size_t i = 0; i < messageSearchResultItems.Size(); ++i) {
    // Session ID
    V2TIMString conversationID = messageSearchResultItems[i].conversationID;
    // Total number of messages matching the session
    uint32_t messageCount = messageSearchResultItems[i].messageCount;
    // Message list: If messageCount > 1, this list is empty; if messageCount = 1, this list Element (XML) is this message
    V2TIMMessageVector messageList = messageSearchResultItems[i].messageList;
    }
    delete callback;
    },
    [=](int error_code, const V2TIMString& error_message) {
    // Failed to find the data
    delete callback;
    });
    
    V2TIMManager::GetInstance()->GetMessageManager()->SearchCloudMessages(searchParam, callback);

    Displaying the list of sessions to which the messages found belong

    Clicking on "More chat records" in figure 1 of the Typical Use Cases for the Search will redirect to figure 2, displaying the list of sessions to which all the found messages belong. The search parameters and results description are similar to the scenario described above.
    To prevent memory bloat, we strongly recommend that you load the session list by paging. For example, load by page, displaying 10 session results per page, the search parameter V2TIMMessageSearchParam can be set as follows:
    1. For the first call: set searchCount = 10, searchCursor = "". Call searchCloudMessages to obtain the message search results, parse and display them on the homepage, and obtain the total number of sessions totalCount and the cursor for the next request searchCursor from the result callback.
    2. When the interface is almost scrolled to the bottom, continue to pull the next page of data based on the cursor searchCursor from the previous request results.
    Below is the sample code:
    Android
    iOS & Mac
    Windows
    ......
    // Logging the search cursor
    String searchCursor = "";
    ......
    
    private void searchConversation(String cursor) {
    List<String> keywordList = new ArrayList<>();
    keywordList.add("test");
    V2TIMMessageSearchParam v2TIMMessageSearchParam = new V2TIMMessageSearchParam();
    v2TIMMessageSearchParam.setConversationID(null);
    v2TIMMessageSearchParam.setKeywordList(keywordList);
    v2TIMMessageSearchParam.setSearchCount(10);
    v2TIMMessageSearchParam.setSearchCursor(cursor);
    V2TIMManager.getMessageManager().searchCloudMessages(v2TIMMessageSearchParam, newV2TIMValueCallback<V2TIMMessageSearchResult>() {
    @Override
    public void onSuccess(V2TIMMessageSearchResult v2TIMMessageSearchResult) {
    // Total number of matched sessions to which messages belong
    int totalCount = v2TIMMessageSearchResult.getTotalCount();
    // Cursor for the next page
    searchCursor = v2TIMMessageSearchResult.getSearchCursor();
    // Information of messages classified by session
    List<V2TIMMessageSearchResultItem> resultItemList = v2TIMMessageSearchResult.getMessageSearchResultItems();
    for (V2TIMMessageSearchResultItem resultItem : resultItemList) {
    // Session ID
    String conversationID = resultItem.getConversationID();
    // Total number of messages matching the session
    int totalMessageCount = resultItem.getMessageCount();
    // Message list: If totalMessageCount > 1, this list is empty; if totalMessageCount = 1, this list Element (XML) is this message
    List<V2TIMMessage> v2TIMMessageList = resultItem.getMessageList();
    }
    }
    @Override
    public void onError(int code, String desc) {
    }
    });
    }
    
    // Load the next page
    public void loadMore() {
    searchConversation(searchCursor);
    }
    ......
    // Logging the search cursor
    NSString *searchCursor = @"";
    ......
    
    - (void)searchConversation:(NSString *)cursor {
    V2TIMMessageSearchParam *param = [[V2TIMMessageSearchParam alloc] init];
    param.keywordList = @[@"test"];
    param.conversationID = nil;
    param.searchCursor = cursor;
    param.searchCount = 10;
    [V2TIMManager.sharedInstance searchCloudMessages:param succ:^(V2TIMMessageSearchResult *searchResult) {
    // Total number of matched sessions to which messages belong
    NSUInteger totalCount = searchResult.totalCount;
    // Cursor for the next page
    searchCursor = searchResult.searchCursor;
    // Information of messages classified by session
    NSArray<V2TIMMessageSearchResultItem *> *messageSearchResultItems = searchResult.messageSearchResultItems;
    for (V2TIMMessageSearchResultItem *searchItem in messageSearchResultItems) {
    // Session ID
    NSString *conversationID = searchItem.conversationID;
    // Total number of messages matching the session
    NSUInteger totalMessageCount = searchItem.messageCount;
    // Message list: If totalMessageCount > 1, this list is empty; if totalMessageCount = 1, this list Element (XML) is this message
    NSArray<V2TIMMessage *> *messageList = searchItem.messageList ?: @[];
    }
    } fail:^(int code, NSString *desc) {
    // fail
    }];
    }
    
    // Load the next page
    - (void)loadMore {
    [self searchConversation:searchCursor];
    }
    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_;
    };
    
    // Logging the search cursor
    V2TIMString searchCursor = "";
    
    void SearchConversation(V2TIMString cursor) {
    V2TIMMessageSearchParam searchParam;
    searchParam.keywordList.PushBack("test");
    searchParam.searchCursor = cursor;
    searchParam.searchCount = 10;
    auto callback = new ValueCallback<V2TIMMessageSearchResult>{};
    callback->SetCallback(
    [=](const V2TIMMessageSearchResult& messageSearchResult) {
    // Total number of matched sessions to which messages belong
    uint32_t totalCount = messageSearchResult.totalCount;
    // Cursor for the next page
    searchCursor = messageSearchResult.searchCursor;
    // Information of messages classified by session
    V2TIMMessageSearchResultItemVector messageSearchResultItems =
    messageSearchResult.messageSearchResultItems;
    for (size_t i = 0; i < messageSearchResultItems.Size(); ++i) {
    // Session ID
    V2TIMString conversationID = messageSearchResultItems[i].conversationID;
    // Total number of messages matching the session
    uint32_t messageCount = messageSearchResultItems[i].messageCount;
    // Message list: If messageCount > 1, this list is empty; if messageCount = 1, this list Element (XML) is this message
    V2TIMMessageVector messageList = messageSearchResultItems[i].messageList;
    }
    delete callback;
    },
    [=](int error_code, const V2TIMString& error_message) {
    // Failed to find the data
    delete callback;
    });
    V2TIMManager::GetInstance()->GetMessageManager()->SearchLocalMessages(searchParam, callback);
    }
    
    // Load the next page
    void LoadMore() { SearchConversation(searchCursor); }

    Displaying the Messages of a Specified Session

    Unlike the session list shown in figure 2 in the Typical Use Cases for the Search, figure 3 displays the list of messages found in a specified session. To prevent memory bloat, we strongly recommend paginating the message display. For example, paginate and show 10 message results per page:
    1. Search parameter V2TIMMessageSearchParam settings can be referred to as follows:
    Setting the search parameter V2TIMMessageSearchParam's conversationID as the session ID you are searching for.
    Initial call: Set the parameter searchCount = 10, searchCursor = "". Call searchCloudMessages to obtain the message search results, parse and display them on the homepage, and obtain the total number of sessions totalCount and the cursor for the next page searchCursor from the result callback.
    Subsequent call: Update the value of searchCursor to the return value from the callback of the previous call.
    2. Handling the search results V2TIMMessageSearchResult:
    totalCount indicates the total number of messages matched in that session.
    messageSearchResultItems list contains only the results for that session. In the list, messageCount of V2TIMMessageSearchResultItem is the number of messages on that page, and messageList is the list of messages on that page.
    searchCursor represents the starting cursor for the next page search.
    Below is the sample code:
    Android
    iOS & Mac
    Windows
    ......
    // Record the search cursor
    String searchCursor = "";
    ......
    
    private void searchMessage(String cursor) {
    List<String> keywordList = new ArrayList<>();
    keywordList.add("test");
    V2TIMMessageSearchParam v2TIMMessageSearchParam = new V2TIMMessageSearchParam();
    v2TIMMessageSearchParam.setConversationID(conversationID);
    v2TIMMessageSearchParam.setKeywordList(keywordList);
    v2TIMMessageSearchParam.setSearchCount(10);
    v2TIMMessageSearchParam.setSearcuCursor(cursor);
    V2TIMManager.getMessageManager().searchCloudMessages(v2TIMMessageSearchParam,newV2TIMValueCallback<V2TIMMessageSearchResult>() {
    @Override
    public void onSuccess(V2TIMMessageSearchResult v2TIMMessageSearchResult) {
    // Total number of messages matching the session
    int totalMessageCount = v2TIMMessageSearchResult.getTotalCount();
    // Cursor for the next page
    searchCursor = v2TIMMessageSearchResult.getSearchCursor();
    // Number of messages on the current page
    List<V2TIMMessageSearchResultItem> resultItemList = v2TIMMessageSearchResult.getMessageSearchResultItems();
    for (V2TIMMessageSearchResultItem resultItem : resultItemList) {
    // Session ID
    String conversationID = resultItem.getConversationID();
    // The number of messages on the current page
    int totalMessageCount = resultItem.getMessageCount();
    // List of messages on the current page
    List<V2TIMMessage> v2TIMMessageList = resultItem.getMessageList();
    }
    }
    @Override
    public void onError(int code, String desc) {
    }
    });
    }
    // Load the next page
    public void loadMore() {
    searchMessage(searchCursor);
    }
    ......
    // Record the search cursor
    NSString *searchCursor = @"";
    ......
    
    - (void)searchMessage:(NSString *)cursor {
    V2TIMMessageSearchParam *param = [[V2TIMMessageSearchParam alloc] init];
    param.keywordList = @[@"test"];
    // conversationID is the session ID to search
    param.conversationID = conversationID;
    param.searchCursor = cursor;
    param.searchCount = 10;
    [V2TIMManager.sharedInstance searchCloudMessages:param succ:^(V2TIMMessageSearchResult *searchResult) {
    // Total number of messages matching the session
    NSUInteger totalMessageCount = searchResult.totalCount;
    // Cursor for the next page
    searchCursor = searchResult.searchCursor;
    // Messages on the current page
    NSArray<V2TIMMessageSearchResultItem *> *messageSearchResultItems = searchResult.messageSearchResultItems;
    for (V2TIMMessageSearchResultItem *searchItem in messageSearchResultItems) {
    // Session ID
    NSString *conversationID = searchItem.conversationID;
    // The number of messages on the current page
    NSUInteger totalMessageCount = searchItem.messageCount;
    // List of messages on the current page
    NSArray<V2TIMMessage *> *messageList = searchItem.messageList ?: @[];
    }
    } fail:^(int code, NSString *desc) {
    // fail
    }];
    }
    
    // Load the next page
    - (void)loadMore {
    [self searchMessage:searchCursor];
    }
    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_;
    };
    
    // Record the search cursor
    V2TIMString searchCursor = "";
    
    void SearchConversation(V2TIMString cursor) {
    V2TIMMessageSearchParam searchParam;
    searchParam.conversationID = conversationID;
    searchParam.keywordList.PushBack("test");
    searchParam.searchCursor = cursor;
    searchParam.searchCount = 10;
    auto callback = new ValueCallback<V2TIMMessageSearchResult>{};
    callback->SetCallback(
    [=](const V2TIMMessageSearchResult& messageSearchResult) {
    // The number of all messages matched by the session
    uint32_t totalCount = messageSearchResult.totalCount;
    // Cursor for the next page
    searchCursor = messageSearchResult.searchCursor;
    // Messages on the current page
    V2TIMMessageSearchResultItemVector messageSearchResultItems =
    messageSearchResult.messageSearchResultItems;
    for (size_t i = 0; i < messageSearchResultItems.Size(); ++i) {
    // Session ID
    V2TIMString conversationID = messageSearchResultItems[i].conversationID;
    // Number of messages on the current page
    uint32_t messageCount = messageSearchResultItems[i].messageCount;
    // List of messages on the current page
    V2TIMMessageVector messageList = messageSearchResultItems[i].messageList;
    }
    delete callback;
    },
    [=](int error_code, const V2TIMString& error_message) {
    // Search failed
    delete callback;
    });
    V2TIMManager::GetInstance()->GetMessageManager()->SearchCloudMessages(searchParam, callback);
    }
    
    // Load the next page
    void LoadMore() { SearchConversation(SearchCursor); }

    Searching for a Custom Message

    Typically, if you use the createCustomMessage(data) (Android/iOS & Mac/Windows) API to create a custom message, the message cannot be found because the SDK saves it as a binary data stream.
    If you want your custom messages to be searchable, you must use the createCustomMessage(data, description, extension) (Android/iOS & Mac/Windows) API to create and send custom messages, placing the searchable text in the description parameter.
    If you have configured the offline push feature, after setting the description parameter, your custom messages will also have offline push and the notification bar will display the content of that parameter. If you don't need offline push, you can control it with the disablePush in the V2TIMOfflinePushInfo parameter of the sendMessage (Android/iOS & Mac/Windows) API.
    If you do not want the content displayed in the push notification bar to be the searchable text, you can use the desc in the V2TIMOfflinePushInfo parameter to set the push content differently.

    Searching for a Rich Media Message

    Rich media messages include file, image, audio, and video messages.
    For file messages, the interface usually displays the file name. If you pass the fileName parameter when calling createFileMessage to create a file message, fileName will be used as the content of the file message to be searched and matched with the search keyword. If fileName is not set, the SDK will automatically extract the file name from filePath as the search content. Both fileName and filePath information is saved to the local device and server, and can be searched after pulling relevant information on a new device.
    For image, audio, and video messages, there is no such name as fileName, and the interface usually displays a thumbnail or duration, making the specification of keywordList ineffective for searches. If you wish to search for such messages, you can specify messageTypeList as V2TIM_ELEM_TYPE_IMAGE/V2TIM_ELEM_TYPE_SOUND/V2TIM_ELEM_TYPE_VIDEO for categorized searches, which will then retrieve all messages of the specified types.

    Exchange and Feedback

    Join the Telegram technical exchange group or WhatsApp discussion group, benefit from the support of professional engineers, and solve your toughest challenges.
    Contact Us

    Contact our sales team or business advisors to help your business.

    Technical Support

    Open a ticket if you're looking for further assistance. Our Ticket is 7x24 avaliable.

    7x24 Phone Support