一、功能描述
·拉取历史消息的 API 在类 V2TIMManager 和 V2TIMManager+Message(Objective-C) / V2TIMMessageManager(Java & C++) 中。
·除了支持单聊、群聊历史消息的拉取外,还提供了高级接口以支持按指定方向拉取、按指定起点和指定时间范围拉取。
·除了支持单独拉取本地历史消息外,还支持拉取云端历史消息。
注意:拉取历史消息接口说明:
本地存储的历史消息无时间限制,但云端存储的历史消息有存储时长的限制:
·体验版:免费存储 7 天,不支持延长。
·专业版:免费存储 7 天,支持延长。
·旗舰版:免费存储 30 天,支持延长。
·企业版:免费存储 90 天,支持延长。
注意:说明:
二、拉取单聊历史消息
你可以调用接口 getC2CHistoryMessageList(Java / Swift /Objective-C)获取单聊历史消息。
在网络正常的情况下会拉取最新的云端数据。如果网络出现异常,SDK 会返回本地存储的历史消息。
如果你仅仅想拉取本地历史消息,请参见 高级接口 。
本接口支持分页拉取,请参见 分页拉取。
示例代码如下:
JavaSwiftObjective-C// 拉取单聊历史消息// 首次拉取,lastMsg 设置为 null// 再次拉取时,lastMsg 可以使用返回的消息列表中的最后一条消息V2TIMManager.getMessageManager().getC2CHistoryMessageList(#your user id#, 20, null, new V2TIMValueCallback<List<V2TIMMessage>>() { @Override public void onError(int code, String desc) { Log.i("imsdk", "fail, " + code + ", " + desc); } @Override public void onSuccess(List<V2TIMMessage> v2TIMMessages) { // 记录下次拉取的 lastMsg, 用于下次拉取 V2TIMMessage lastMsg = v2TIMMessages.get(v2TIMMessages.size() – 1); Log.i("imsdk", "success"); }});// 拉取单聊历史消息// 首次拉取,lastMsg 设置为 nil// 再次拉取时,lastMsg 可以使用返回的消息列表中的最后一条消息V2TIMManager.shared.getC2CHistoryMessageList(userID: "userID", count: 100, lastMsg: lastMessage) { msgs in msgs.forEach { item in print("\\(item.description)") } // 记录下次拉取的 lastMsg,用于下次拉取 lastMessage = msgs.last} fail: { code, desc in print("fail \\(code), \\(desc)")}// 拉取单聊历史消息// 首次拉取,lastMsg 设置为 nil// 再次拉取时,lastMsg 可以使用返回的消息列表中的最后一条消息[V2TIMManager.sharedInstance getC2CHistoryMessageList:#your user id# count:20 lastMsg:nil succ:^(NSArray<V2TIMMessage *> *msgs) { // 记录下次拉取的 lastMsg,用于下次拉取 V2TIMMessage *lastMsg = msgs.lastObject; NSLog(@"success, %@", msgs);} fail:^(int code, NSString *desc) { NSLog(@"fail, %d, %@", code, desc);}];
三、拉取群聊历史消息
你可以调用接口 getGroupHistoryMessageList(Java / Swift / Objective-C)获取群聊历史消息。
在网络正常的情况下会拉取最新的云端数据。如果网络出现异常,SDK 会返回本地存储的历史消息。
如果你仅仅想拉取本地历史消息,请参见 高级接口 。
本接口支持分页拉取,请参见 分页拉取。
示例代码如下:
JavaSwiftObjective-C// 拉取群聊历史消息// 首次拉取,lastMsg 设置为 null// 再次拉取时,lastMsg 可以使用返回的消息列表中的最后一条消息V2TIMManager.getMessageManager().getGroupHistoryMessageList(#your group id#, 20, null, new V2TIMValueCallback<List<V2TIMMessage>>() { @Override public void onError(int code, String desc) { Log.i("imsdk", "fail, " + code + ", " + desc); } @Override public void onSuccess(List<V2TIMMessage> v2TIMMessages) { // 记录下次拉取的 lastMsg,用于下次拉取 V2TIMMessage lastMsg = v2TIMMessages.get(v2TIMMessages.size() – 1); Log.i("imsdk", "success"); }});// 拉取单聊历史消息// 首次拉取,lastMsg 设置为 nil// 再次拉取时,lastMsg 可以使用返回的消息列表中的最后一条消息V2TIMManager.shared.getGroupHistoryMessageList(groupID: "groupID", count: 100, lastMsg: lastMessage) { msgs in msgs.forEach { item in print("\\(item.description)") } // 记录下次拉取的 lastMsg,用于下次拉取 lastMessage = msgs.last} fail: { code, desc in print("fail \\(code), \\(desc)")}// 拉取群聊历史消息// 首次拉取,lastMsg 设置为 null// 再次拉取时,lastMsg 可以使用返回的消息列表中的最后一条消息[V2TIMManager.sharedInstance getGroupHistoryMessageList:#your group id# count:20 lastMsg:nil succ:^(NSArray<V2TIMMessage *> *msgs) { // 记录下次拉取的 lastMsg,用于下次拉取 V2TIMMessage *lastMsg = msgs.lastObject; NSLog(@"success, %@", msgs);} fail:^(int code, NSString *desc) { NSLog(@"fail, %d, %@", code, desc);}];
四、高级接口
如果以上的普通接口无法满足你对拉取历史消息的需求,我们还提供了高级接口 getHistoryMessageList(Java / Swift / Objective-C / C++)。
该接口除了支持普通拉取单聊、群聊历史消息外,还支持以下高级特性:
·支持设置消息拉取时的起点。
·支持设置拉取消息的时间范围。
·支持设置拉取消息的位置:从本地拉取、从云端拉取。
·支持按照指定的方向拉取:往消息时间更老的方向拉取、往消息时间更新的方向拉取。
·支持拉取本地指定的消息类型:文本、图片、语音、视频、文件、表情、群 tips 消息、合并消息、自定义消息等。
接口原型:
JavaSwiftObjective-Cpublic abstract void getHistoryMessageList(V2TIMMessageListGetOption option, V2TIMValueCallback<List<V2TIMMessage>> callback);public func getHistoryMessageList(option: V2TIMMessageListGetOption, succ: V2TIMMessageListSucc?, fail: V2TIMFail?)- (void)getHistoryMessageList:(V2TIMMessageListGetOption *)option succ:(V2TIMMessageListSucc)succ fail:(V2TIMFail)fail;
V2TIMMessageListGetOption 类参数说明:
| 参数 | 含义 | 单聊有效 | 群聊有效 | 是否必填 | 说明 |
| getType | 拉取消息的位置及方向,可以设置拉取 本地/云端 的 更老/更新 的消息 | YES | YES | YES | 当设置从云端拉取时,会将本地存储消息列表与云端存储消息列表合并后返回。如果无网络,则直接返回本地消息列表。 |
| userID | 拉取指定用户的单聊历史消息 | YES | NO | NO | 拉取单聊消息,需要指定对方的 userID,此时 groupID 传空即可。 |
| groupID | 拉取指定群组的群聊历史消息 | NO | YES | NO | 拉取群聊消息,需要指定群聊的 groupID,此时 userID 传空即可。 |
| count | 单次拉取的消息数量 | YES | YES | YES | 建议设置为 20,否则可能影响拉取速度 |
| messageTypeList | 拉取的消息类型集合 | YES | YES | NO | 1. 只支持本地拉取,即当 getType 为 V2TIM_GET_LOCAL_OLDER_MSG 或 V2TIM_GET_LOCAL_NEWER_MSG 时有效。2. 如果该字段为空,表示拉取所有的消息类型。3. 支持的消息类型详见 V2TIMElemType(Java / Swift /Objective-C / C++)。 |
| lastMsg | 最后一条消息 | YES | YES | NO | 可用于拉取历史消息的场景。1. 单聊和群聊中均能使用。2. 设置 lastMsg 作为拉取的起点,返回的消息列表中不包含这条消息。3. 如果设置为空,则使用会话的最新一条消息作为拉取起点。 |
| lastMsgSeq | 最后一条消息的 seq | NO | YES | NO | 可用于拉取历史消息或消息定位等场景。1. 仅能在群聊中使用该字段。2. 设置 lastMsgSeq 作为拉取的起点,返回的消息列表中包含这条消息。3. 如果同时指定了 lastMsg 和 lastMsgSeq,SDK 优先使用 lastMsg。4. 如果均未指定 lastMsg 和 lastMsgSeq,拉取的起点取决于是否设置 getTimeBegin。设置了,则使用设置的范围作为起点;未设置,则使用最新消息作为起点。 |
| getTimeBegin | 拉取消息的时间起点。UTC 时间戳,单位:秒 | YES | YES | NO | 默认为 0,表示从当前时间开始拉取。 |
| getTimePeriod | 拉取消息的时间范围。单位:秒 | YES | YES | NO | 1. 默认为 0,表示不限制时间范围。2. 取值的范围区间为闭区间,包含起止时间,二者关系如下:如果 getType 指定了朝消息时间更老的方向拉取,则时间范围表示为 [getTimeBegin – getTimePeriod, getTimeBegin]。如果 getType 指定了朝消息时间更新的方向拉取,则时间范围表示为 [getTimeBegin, getTimeBegin + getTimePeriod]。 |
五、分页拉取
上述拉取单聊历史消息、群聊历史消息,及高级接口均可按照相同的方式实现分页,即使用 lastMsg 和 count 来实现:
1. 首次拉取,设置 lastMsg 为空,此时 SDK 会拉取到最新的消息。
2. 非首次拉取,使用上一次拉取到的消息列表中最后一条消息作为本次拉取的 lastMsg,拉取下一页数据。此时消息列表返回的消息不包含设置的 lastMsg。
3. 如果成功回调中返回的消息列表为空,表示拉取完毕,没有更多数据了。
注意:说明:
注意:1. 拉取到的消息列表中,越新的消息越靠前。
注意:2. 考虑到加载效率、网络省流,建议分页时 count 设置为 20。
如果你使用 lastMsgSeq 拉取历史消息,返回的消息列表会包含该 lastMsgSeq 所对应的消息。因此,非首次拉取群聊历史消息(也就是续拉)时,建议不要使用 lastMsgSeq,否则可能出现同一条消息被重复拉到的情况。
例如,现在的历史消息有 8 条,分别是:msg1、msg2、msg3、msg4、msg5、msg6、msg7、msg8。每次拉取 4 条,首次拉取得到了 msg1、msg2、msg3、msg4,此时再用 msg4 的 lastMsgSeq 续拉,会拉到消息 msg4、msg5、msg6、msg7。两次拉取中,msg4 被重复拉取了。
如果你一定要使用 lastMsgSeq 续拉,建议处理好消息去重的逻辑。
六、按照时间范围拉取
你可以通过设置 getTimeBegin 和 getTimePeriod 来拉取指定的时间范围内的消息。
如下所示,时间范围的起止时间戳与 getType 有关。
示例代码将演示:从 2022-01-01 00:00:00 开始(时间戳是 1640966400),往过去的方向,从云端拉取一整天的群聊消息。
JavaSwiftObjective-CC++V2TIMMessageListGetOption option = new V2TIMMessageListGetOption();option.setGetType(V2TIMMessageListGetOption.V2TIM_GET_CLOUD_OLDER_MSG); // 拉取云端的更老的消息option.setGetTimeBegin(1640966400); // 从 2022-01-01 00:00:00 开始option.setGetTimePeriod(1 * 24 * 60 * 60); // 拉取一整天的消息option.setCount(Integer.MAX_VALUE); // 返回时间范围内所有的消息option.setGroupID(#you group id#); // 拉取群聊消息V2TIMManager.getMessageManager().getHistoryMessageList(option, new V2TIMValueCallback<List<V2TIMMessage>>() { @Override public void onSuccess(List<V2TIMMessage> v2TIMMessages) { Log.i("imsdk", "success"); } @Override public void onError(int code, String desc) { Log.i("imsdk", "failure, code:" + code + ", desc:" + desc); }});let option = V2TIMMessageListGetOption()option.getType = .V2TIM_GET_CLOUD_OLDER_MSG// 拉取云端的更老的消息option.getTimeBegin = 1640966400 // 从 2022-01-01 00:00:00 开始option.getTimePeriod = 1 * 24 * 60 * 60 // 拉取一整天的消息option.groupID = "#your group id#"option.count = UInt(INT_MAX) // 返回时间范围内所有的消息V2TIMManager.shared.getHistoryMessageList(option: option) { msgs in msgs.forEach { item in } print("success")} fail: { code, desc in print("fail \\(code), \\(desc)")}V2TIMMessageListGetOption *option = [[V2TIMMessageListGetOption alloc] init];option.getType = V2TIM_GET_CLOUD_OLDER_MSG; // 拉取云端的更老的消息option.getTimeBegin = 1640966400; // 从 2022-01-01 00:00:00 开始option.getTimePeriod = 1 * 24 * 60 * 60; // 拉取一整天的消息option.count = INT_MAX; // 返回时间范围内所有的消息option.groupID = #your group id#; // 拉取群聊消息[V2TIMManager.sharedInstance getHistoryMessageList:option succ:^(NSArray<V2TIMMessage *> *msgs) { NSLog(@"success");} fail:^(int code, NSString *desc) { NSLog(@"failure, code:%d, desc:%@", code, 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_;};V2TIMMessageListGetOption option;option.getType = V2TIMMessageGetType::V2TIM_GET_CLOUD_OLDER_MSG; // 拉取云端的更老的消息option.getTimeBegin = 1640966400; // 从 2022-01-01 00:00:00 开始option.getTimePeriod = 1 * 24 * 60 * 60; // 拉取一整天的消息option.count = std::numeric_limits<uint64_t>::max(); // 返回时间范围内所有的消息option.groupID = "your group id"; // 拉取群聊消息auto callback = new ValueCallback<V2TIMMessageVector>{};callback->SetCallback( [=](const V2TIMMessageVector& messageList) { std::cout << "success" << std::endl; delete callback; }, [=](int error_code, const V2TIMString& error_message) { std::cout << "error" << std::endl; delete callback; });V2TIMManager::GetInstance()->GetMessageManager()->GetHistoryMessageList(option, callback);
七、在时间范围内分页拉取
你可以同时指定拉取的时间范围和 lastMsg/lastMsgSeq。此时 SDK 的表现是:
1. 如果用户同时设置了 getTimeBegin/getTimePeriod 和 lastMsg/lastMsgSeq,结果集可理解成:「单独按起始消息拉取的结果」与「单独按时间范围拉取的结果」 取交集。
2. 如果用户都没设置 getTimeBegin/getTimePeriod 和 lastMsg/lastMsgSeq,结果集可理解成:从当前会话最新的一条消息开始,按照 getType 所指定的方向和拉取方式拉取。
示例代码将演示:从 2022-01-01 00:00:00 开始(时间戳是 1640966400),往过去的方向,每页 20 条,分页地从云端拉取一整天的群聊消息。
JavaSwiftObjective-CC++// 定义变量,记录每次拉取的游标private V2TIMMessage m_lastMsg = null; // 首次拉取时为 null// 分页拉取逻辑V2TIMMessageListGetOption option = new V2TIMMessageListGetOption();option.setGetType(V2TIMMessageListGetOption.V2TIM_GET_CLOUD_OLDER_MSG); // 拉取云端的更老的消息option.setGetTimeBegin(1640966400); // 从 2022-01-01 00:00:00 开始option.setGetTimePeriod(1 * 24 * 60 * 60); // 拉取一整天的消息option.setCount(20); // 每页 20 条option.setLastMsg(m_lastMsg); // 上次拉取的位置 (每次返回的消息列表的最后一条消息)option.setGroupID(#you group id#); // 拉取群聊消息V2TIMManager.getMessageManager().getHistoryMessageList(option, new V2TIMValueCallback<List<V2TIMMessage>>() { @Override public void onSuccess(List<V2TIMMessage> v2TIMMessages) { Log.i("imsdk", "success"); // 记录下一次拉取的 lastMsg m_lastMsg = v2TIMMessages.get(v2TIMMessages.size() – 1); } @Override public void onError(int code, String desc) { Log.i("imsdk", "failure, code:" + code + ", desc:" + desc); }});// 定义变量,记录每次拉取的游标var lastMsg: V2TIMMessage?// 分页拉取逻辑let option = V2TIMMessageListGetOption()option.getType = .V2TIM_GET_CLOUD_OLDER_MSG// 拉取云端的更老的消息option.getTimeBegin = 1640966400 // 从 2022-01-01 00:00:00 开始option.getTimePeriod = 1 * 24 * 60 * 60 // 拉取一整天的消息option.count = 20 // 每页 20 条option.lastMsg = self.lastMsg; // 上次拉取的位置 (每次返回的消息列表的最后一条消息)option.groupID = "#your group id#" // 拉取群聊消息V2TIMManager.shared.getHistoryMessageList(option: option) { msgs in msgs.forEach { item in } print("success")} fail: { code, desc in print("fail \\(code), \\(desc)")}// 定义变量,记录每次拉取的游标@property (nonatomic, copy) V2TIMMessage *lastMsg;// 分页拉取逻辑V2TIMMessageListGetOption *option = [[V2TIMMessageListGetOption alloc] init];option.getType = V2TIM_GET_CLOUD_OLDER_MSG; // 拉取云端的更老的消息option.getTimeBegin = 1640966400; // 从 2022-01-01 00:00:00 开始option.getTimePeriod = 1 * 24 * 60 * 60; // 拉取一整天的消息option.count = 20; // 每页 20 条option.lastMsg = self.lastMsg; // 上次拉取的位置 (每次返回的消息列表的最后一条消息)option.groupID = #your group id#; // 拉取群聊消息__weak typeof(self) weakSelf = self;[V2TIMManager.sharedInstance getHistoryMessageList:option succ:^(NSArray<V2TIMMessage *> *msgs) { NSLog(@"success"); // 记录下一次拉取的 lastMsg weakSelf.lastMsg = msgs.lastObject;} fail:^(int code, NSString *desc) { NSLog(@"failure, code:%d, desc:%@", code, 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_;};// 定义变量,记录每次拉取的游标V2TIMMessage lastMsg;// 分页拉取逻辑V2TIMMessageListGetOption option;option.getType = V2TIMMessageGetType::V2TIM_GET_CLOUD_OLDER_MSG; // 拉取云端的更老的消息option.getTimeBegin = 1640966400; // 从 2022-01-01 00:00:00 开始option.getTimePeriod = 1 * 24 * 60 * 60; // 拉取一整天的消息option.count = 20; // 每页 20 条option.lastMsg = 首次拉取 ? nullptr : &lastMsg; // 上次拉取的位置(每次返回的消息列表的最后一条消息)option.groupID = "your group id"; // 拉取群聊消息auto callback = new ValueCallback<V2TIMMessageVector>{};callback->SetCallback( [=](const V2TIMMessageVector& messageList) mutable { std::cout << "success" << std::endl; // 记录下一次拉取的 lastMsg lastMsg = messageList[messageList.Size() – 1]; delete callback; }, [=](int error_code, const V2TIMString& error_message) { std::cout << "error" << std::endl; delete callback; });V2TIMManager::GetInstance()->GetMessageManager()->GetHistoryMessageList(option, callback);
八、仅拉取本地消息
通过设置 getType 来实现仅拉取本地消息:
·getType 取值为 V2TIM_GET_LOCAL_OLDER_MSG 时,表示往时间更旧的方向,拉取本地存储的消息。
·getType 取值为 V2TIM_GET_LOCAL_NEWER_MSG 时,表示往时间更新的方向,拉取本地存储的消息。
示例代码将演示:从最新的消息开始,往更老的方向,从本地数据库中拉取 20 条单聊消息。
JavaSwiftObjective-CC++V2TIMMessageListGetOption option = new V2TIMMessageListGetOption();option.setGetType(V2TIMMessageListGetOption.V2TIM_GET_LOCAL_OLDER_MSG); // 拉取本地的更老的消息option.setLastMsg(null); // 设置从最新的消息开始拉取option.setCount(20); // 拉取 20 条消息option.setUserID(#you user id#); // 拉取单聊消息V2TIMManager.getMessageManager().getHistoryMessageList(option, new V2TIMValueCallback<List<V2TIMMessage>>() { @Override public void onSuccess(List<V2TIMMessage> v2TIMMessages) { Log.i("imsdk", "success"); } @Override public void onError(int code, String desc) { Log.i("imsdk", "failure, code:" + code + ", desc:" + desc); }});let option = V2TIMMessageListGetOption()option.getType = .V2TIM_GET_LOCAL_OLDER_MSG // 拉取本地的更老的消息option.lastMsg = nil // 设置从最新的消息开始拉取option.count = 20 // 每页 20 条option.userID = "userID" // 拉取单聊消息V2TIMManager.shared.getHistoryMessageList(option: option) { msgs in msgs.forEach { item in } print("success")} fail: { code, desc in print("fail \\(code), \\(desc)")}V2TIMMessageListGetOption *option = [[V2TIMMessageListGetOption alloc] init];option.getType = V2TIM_GET_LOCAL_OLDER_MSG; // 拉取本地的更老的消息option.lastMsg = nil; // 设置从最新的消息开始拉取option.count = 20; // 拉取 20 条消息option.userID = #your user id#; // 拉取单聊消息[V2TIMManager.sharedInstance getHistoryMessageList:option succ:^(NSArray<V2TIMMessage *> *msgs) { NSLog(@"success");} fail:^(int code, NSString *desc) { NSLog(@"failure, code:%d, desc:%@", code, 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_;};V2TIMMessageListGetOption option;option.getType = V2TIMMessageGetType::V2TIM_GET_LOCAL_OLDER_MSG; // 拉取本地的更老的消息option.count = 20; // 拉取 20 条消息option.userID = "you user id"; // 拉取单聊消息auto callback = new ValueCallback<V2TIMMessageVector>{};callback->SetCallback( [=](const V2TIMMessageVector& messageList) mutable { std::cout << "success" << std::endl; delete callback; }, [=](int error_code, const V2TIMString& error_message) { std::cout << "error" << std::endl; delete callback; });V2TIMManager::GetInstance()->GetMessageManager()->GetHistoryMessageList(option, callback);
九、拉取指定类型的消息
SDK 定义一些常见的消息类型,例如文本、图片、视频等,参考 V2TIMElemType(Java / Swift /Objective-C / C++)。高级接口 getHistoryMessageList 支持通过设置 messageTypeList,拉取指定类型的消息。
注意:1. 当 messageTypeList 为空时,表示拉取所有类型的消息。
注意:2. 拉取指定的消息类型,只支持从本地拉取。从云端拉取消息不支持指定消息类型。
示例代码将演示:从当前开始,往过去的方向,拉取 20 条文本和图片消息。
JavaSwiftObjective-CC++// 拉取图片消息、文本消息ArrayList<Integer> messageTypeList = new ArrayList<Integer>();messageTypeList.add(V2TIM_ELEM_TYPE_IMAGE);messageTypeList.add(V2TIM_ELEM_TYPE_TEXT);V2TIMMessageListGetOption option = new V2TIMMessageListGetOption();option.setGetType(V2TIMMessageListGetOption.V2TIM_GET_LOCAL_OLDER_MSG); // 拉取本地的更老的消息option.setCount(20);option.setMessageTypeList(messageTypeList);option.setGroupID("you group id");V2TIMManager.getMessageManager().getHistoryMessageList(option, new V2TIMValueCallback<List<V2TIMMessage>>() { @Override public void onSuccess(List<V2TIMMessage> v2TIMMessages) { Log.i("imsdk", "success"); } @Override public void onError(int code, String desc) { Log.i("imsdk", "failure, code:" + code + ", desc:" + desc); }});let option = V2TIMMessageListGetOption()option.getType = .V2TIM_GET_LOCAL_OLDER_MSG // 拉取本地的更老的消息option.messageTypeList = [.V2TIM_ELEM_TYPE_IMAGE, .V2TIM_ELEM_TYPE_TEXT]option.count = 20 // 每页 20 条option.groupID = "your group id";V2TIMManager.shared.getHistoryMessageList(option: option) { msgs in msgs.forEach { item in } print("success")} fail: { code, desc in print("fail \\(code), \\(desc)")}V2TIMMessageListGetOption *option = [[V2TIMMessageListGetOption alloc] init];option.getType = V2TIM_GET_LOCAL_OLDER_MSG;// 拉取图片消息、文本消息option.messageTypeList = @[@(V2TIM_ELEM_TYPE_IMAGE), @(V2TIM_ELEM_TYPE_TEXT)];option.count = 20;option.groupID = @"your group id";[V2TIMManager.sharedInstance getHistoryMessageList:option succ:^(NSArray<V2TIMMessage *> *msgs) { NSLog(@"success");} fail:^(int code, NSString *desc) { NSLog(@"failure, code:%d, desc:%@", code, 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_;};V2TIMMessageListGetOption option;option.getType = V2TIMMessageGetType::V2TIM_GET_LOCAL_OLDER_MSG; // 拉取本地的更老的消息option.count = 20; // 拉取 20 条消息option.messageTypeList.PushBack(V2TIMElemType::V2TIM_ELEM_TYPE_IMAGE); // 拉取图片消息option.messageTypeList.PushBack(V2TIMElemType::V2TIM_ELEM_TYPE_TEXT); // 拉取文本消息option.userID = "you group id"; // 拉取群聊消息auto callback = new ValueCallback<V2TIMMessageVector>{};callback->SetCallback( [=](const V2TIMMessageVector& messageList) mutable { std::cout << "success" << std::endl; delete callback; }, [=](int error_code, const V2TIMString& error_message) { std::cout << "error" << std::endl; delete callback; });V2TIMManager::GetInstance()->GetMessageManager()->GetHistoryMessageList(option, callback);
十、拉取指定 sequence 的消息
在拉取群聊历史消息时,你可以按照指定的消息序列号 sequence 拉取。
注意:说明:
示例代码将演示:在群组中,从云端拉取消息 sequence 为 1,3,5,9 的消息,并将消息按照时间逆序返回。
JavaSwiftObjective-CC++ArrayList<Long> sequenceList = new ArrayList<>();sequenceList.add(1L);sequenceList.add(3L);sequenceList.add(5L);sequenceList.add(9L);V2TIMMessageListGetOption option = new V2TIMMessageListGetOption();option.setGroupID("your groupID");option.setMessageSeqList(sequenceList);option.setGetType(V2TIMMessageListGetOption.V2TIM_GET_CLOUD_OLDER_MSG);V2TIMManager.getMessageManager().getHistoryMessageList(option, new V2TIMValueCallback<List<V2TIMMessage>>() { @Override public void onSuccess(List<V2TIMMessage> v2TIMMessages) { } @Override public void onError(int code, String desc) { }});option.getType = .V2TIM_GET_LOCAL_OLDER_MSG // 拉取本地的更老的消息option.groupID = "your group id";option.messageSeqList = [1,3,5,9]V2TIMManager.shared.getHistoryMessageList(option: option) { msgs in msgs.forEach { item in } print("success")} fail: { code, desc in print("fail \\(code), \\(desc)")}V2TIMMessageListGetOption *option = [[V2TIMMessageListGetOption alloc] init];option.getType = V2TIM_GET_CLOUD_OLDER_MSG;option.groupID = @"your groupID";option.messageSeqList = @[@(1), @(3), @(5), @(9)];[V2TIMManager.sharedInstance getHistoryMessageList:option succ:^(NSArray<V2TIMMessage *> *msgs) {} 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_;};V2TIMUInt64Vector sequence_list;sequence_list.PushBack(1);sequence_list.PushBack(3);sequence_list.PushBack(5);sequence_list.PushBack(9);V2TIMMessageListGetOption option;option.getType = V2TIMMessageGetType::V2TIM_GET_CLOUD_OLDER_MSG; option.messageSeqList = sequence_list;option.groupID = "your group id";auto callback = new ValueCallback<V2TIMMessageVector>{};callback->SetCallback( [=](const V2TIMMessageVector& messageList) { std::cout << "success" << std::endl; delete callback; }, [=](int error_code, const V2TIMString& error_message) { std::cout << "error" << std::endl; delete callback; });V2TIMManager::GetInstance()->GetMessageManager()->GetHistoryMessageList(option, callback);
十一、一键跳转到群 @ 消息
在群聊会话中,收到群 @ 消息后,一般需要通过点击群 @ 提示条,跳转到群 @ 消息的位置,并拉取附近的消息列表用于显示。
由于群 @ 消息本身也需要显示,可以将 lastMsgSeq 设置成群 @ 消息的 sequence ,并使用高级接口 getHistoryMessageList 来拉取。
示例代码将演示:单击群 @ 提示后,跳转到群 @ 消息,并拉取前后各 20 条消息用于展示。
JavaSwiftObjective-CC++// 获取群 @ 消息对应的的 sequencelong atSequence = 1081;// 拉取群 @ 消息及之前的消息V2TIMMessageListGetOption beforeOption = new V2TIMMessageListGetOption();beforeOption.setGetType(V2TIMMessageListGetOption.V2TIM_GET_CLOUD_OLDER_MSG); // 拉取比群 @ 消息更早的消息beforeOption.setCount(20); // 拉取 20 条beforeOption.setLastMsgSeq(atSequence); // 从群 @ 消息开始拉取,包括群 @ 消息beforeOption.setGroupID(#you group id#); // 拉取群聊消息V2TIMManager.getMessageManager().getHistoryMessageList(beforeOption, new V2TIMValueCallback<List<V2TIMMessage>>() { @Override public void onSuccess(List<V2TIMMessage> v2TIMMessages) {、 // 返回的消息列表中包括群 @ 消息 Log.i("imsdk", "success"); } @Override public void onError(int code, String desc) { Log.i("imsdk", "failure, code:" + code + ", desc:" + desc); }});// 拉取群 @ 消息之后的消息V2TIMMessageListGetOption afterOption = new V2TIMMessageListGetOption();afterOption.setGetType(V2TIMMessageListGetOption.V2TIM_GET_CLOUD_NEWER_MSG); // 拉取比群 @ 消息更晚的消息afterOption.setCount(20); // 拉取 20 条afterOption.setLastMsgSeq(atSequence + 1); // 从群 @ 消息的后一条消息开始拉取,不包括群 @ 消息afterOption.setGroupID(#you group id#); // 拉取群聊消息V2TIMManager.getMessageManager().getHistoryMessageList(afterOption, new V2TIMValueCallback<List<V2TIMMessage>>() { @Override public void onSuccess(List<V2TIMMessage> v2TIMMessages) { // 返回的消息列表中不包括群 @ 消息 Log.i("imsdk", "success"); } @Override public void onError(int code, String desc) { Log.i("imsdk", "failure, code:" + code + ", desc:" + desc); }});// 获取群 @ 消息对应的的 sequencelet atSequence = 1081// 拉取群 @ 消息及之前的消息let beforeOption = V2TIMMessageListGetOption()beforeOption.getType = .V2TIM_GET_CLOUD_OLDER_MSG // 拉取比群 @ 消息更早的消息beforeOption.count = 20 // 拉取 20 条beforeOption.lastMsgSeq = atSequence // 从群 @ 消息开始拉取, 包括群 @ 消息beforeOption.groupID = "your group id";// 拉取群聊消息V2TIMManager.shared.getHistoryMessageList(option: beforeOption) { msgs in msgs.forEach { item in // 返回的消息列表中包括群 @ 消息 } print("success")} fail: { code, desc in print("fail \\(code), \\(desc)")}// 拉取群 @ 消息之后的消息let afterOption = V2TIMMessageListGetOption()afterOption.getType = .V2TIM_GET_CLOUD_NEWER_MSG // 拉取比群 @ 消息更晚的消息afterOption.count = 20 // 拉取 20 条afterOption.lastMsgSeq = atSequence + 1; // 从群 @ 消息的后一条消息开始拉取,不包括群 @ 消息afterOption.groupID = "your group id";// 拉取群聊消息V2TIMManager.shared.getHistoryMessageList(option: afterOption) { msgs in msgs.forEach { item in // 返回的消息列表中不包括群 @ 消息 } print("success")} fail: { code, desc in print("fail \\(code), \\(desc)")}// 获取群 @ 消息对应的的 sequenceNSInteger atSequence = 1081;// 拉取群 @ 消息及之前的消息V2TIMMessageListGetOption *beforeOption = [[V2TIMMessageListGetOption alloc] init];beforeOption.getType = V2TIM_GET_CLOUD_OLDER_MSG; // 拉取比群 @ 消息更早的消息beforeOption.count = 20; // 拉取 20 条beforeOption.lastMsgSeq = atSequence; // 从群 @ 消息开始拉取, 包括群 @ 消息beforeOption.groupID = #your group id#; // 拉取群聊消息[V2TIMManager.sharedInstance getHistoryMessageList:beforeOption succ:^(NSArray<V2TIMMessage *> *msgs) { // 返回的消息列表中包括群 @ 消息 NSLog(@"success");} fail:^(int code, NSString *desc) { NSLog(@"failure, code:%d, desc:%@", code, desc);}];// 拉取群 @ 消息之后的消息V2TIMMessageListGetOption *afterOption = [[V2TIMMessageListGetOption alloc] init];afterOption.getType = V2TIM_GET_CLOUD_NEWER_MSG; // 拉取比群 @ 消息更晚的消息afterOption.count = 20; // 拉取 20 条afterOption.lastMsgSeq = atSequence + 1; // 从群 @ 消息的后一条消息开始拉取,不包括群 @ 消息afterOption.groupID = #your group id#; // 拉取群聊消息[V2TIMManager.sharedInstance getHistoryMessageList:afterOption succ:^(NSArray<V2TIMMessage *> *msgs) { // 返回的消息列表中不包括群 @ 消息 NSLog(@"success");} fail:^(int code, NSString *desc) { NSLog(@"failure, code:%d, desc:%@", code, 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_;};// 获取群 @ 消息对应的的 sequenceuint64_t atSequence = 1081;// 拉取群 @ 消息及之前的消息V2TIMMessageListGetOption beforeOption;beforeOption.getType = V2TIMMessageGetType::V2TIM_GET_CLOUD_OLDER_MSG; // 拉取比群 @ 消息更早的消息beforeOption.count = 20; // 拉取 20 条消息beforeOption.lastMsgSeq = atSequence; // 从群 @ 消息开始拉取,包括群 @ 消息beforeOption.userID = "you group id"; // 拉取群聊消息auto beforeCallback = new ValueCallback<V2TIMMessageVector>{};beforeCallback->SetCallback( [=](const V2TIMMessageVector& messageList) mutable { // 返回的消息列表中包括群 @ 消息 std::cout << "success" << std::endl; delete beforeCallback; }, [=](int error_code, const V2TIMString& error_message) { std::cout << "error" << std::endl; delete beforeCallback; });V2TIMManager::GetInstance()->GetMessageManager()->GetHistoryMessageList(beforeOption, beforeCallback);// 拉取群 @ 消息及之前的消息V2TIMMessageListGetOption afterOption;afterOption.getType = V2TIMMessageGetType::V2TIM_GET_CLOUD_NEWER_MSG; // 拉取比群 @ 消息更晚的消息afterOption.count = 20; // 拉取 20 条消息afterOption.lastMsgSeq = atSequence + 1; // 从群 @ 消息的后一条消息开始拉取,不包括群 @ 消息afterOption.userID = "you group id"; // 拉取群聊消息auto afterCallback = new ValueCallback<V2TIMMessageVector>{};afterCallback->SetCallback( [=](const V2TIMMessageVector& messageList) mutable { // 返回的消息列表中不包括群 @ 消息 std::cout << "success" << std::endl; delete afterCallback; }, [=](int error_code, const V2TIMString& error_message) { std::cout << "error" << std::endl; delete afterCallback; });V2TIMManager::GetInstance()->GetMessageManager()->GetHistoryMessageList(afterOption, afterCallback);
十二、搜索场景下的消息定位
当用户通过本地搜索获取到 V2TIMMessage 对象。点击该消息后,一般需要跳转到该消息对应的位置并展示附近的消息。
此时可以将 lastMsg 设置成该消息对象,并使用高级接口 getHistoryMessageList 拉取前后的消息。
示例代码将演示:拉取搜索到的消息前后各 20 条消息,用于展示。
JavaSwiftObjective-CC++// 获取当前的 message 对象V2TIMMessage lastMsg = #搜索到的消息#;// 拉取指定消息之前的消息V2TIMMessageListGetOption beforeOption = new V2TIMMessageListGetOption();beforeOption.setGetType(V2TIMMessageListGetOption.V2TIM_GET_CLOUD_OLDER_MSG); // 拉取比指定消息更早的消息beforeOption.setCount(20); // 拉取 20 条beforeOption.setLastMsg(lastMsg); // 从指定消息开始拉取,不包括该消息beforeOption.setGroupID(#you group id#); // 拉取群聊消息V2TIMManager.getMessageManager().getHistoryMessageList(beforeOption, new V2TIMValueCallback<List<V2TIMMessage>>() { @Override public void onSuccess(List<V2TIMMessage> v2TIMMessages) {、 // 返回的消息列表中不包括 lastMsg Log.i("imsdk", "success"); } @Override public void onError(int code, String desc) { Log.i("imsdk", "failure, code:" + code + ", desc:" + desc); }});// 拉取指定消息之后的消息V2TIMMessageListGetOption afterOption = new V2TIMMessageListGetOption();afterOption.setGetType(V2TIMMessageListGetOption.V2TIM_GET_CLOUD_NEWER_MSG); // 拉取比指定消息更晚的消息afterOption.setCount(20); // 拉取 20 条afterOption.setLastMsg(lastMsg); // 从指定消息开始拉取,不包括该消息afterOption.setGroupID(#you group id#); // 拉取群聊消息V2TIMManager.getMessageManager().getHistoryMessageList(afterOption, new V2TIMValueCallback<List<V2TIMMessage>>() { @Override public void onSuccess(List<V2TIMMessage> v2TIMMessages) { // 返回的消息列表中不包括 lastMsg Log.i("imsdk", "success"); } @Override public void onError(int code, String desc) { Log.i("imsdk", "failure, code:" + code + ", desc:" + desc); }});// 获取当前的 message 对象let lastMsg: V2TIMMessage = "搜索后的消息"// 拉取指定消息之前的消息let beforeOption = V2TIMMessageListGetOption()beforeOption.getType = .V2TIM_GET_CLOUD_OLDER_MSG // 拉取比指定消息更早的消息beforeOption.count = 20 // 拉取 20 条beforeOption.lastMsg = lastMsg // 从指定消息开始拉取,不包括该消息beforeOption.groupID = "your_group_id" // 拉取群聊消息V2TIMManager.sharedInstance().getHistoryMessageList(beforeOption, succ: { msgs in // 返回的消息列表中不包括指定消息 print("success")}) { code, desc in print("failure, code: \\(code), desc: \\(desc)")}// 拉取指定消息之后的消息let afterOption = V2TIMMessageListGetOption()afterOption.getType = .V2TIM_GET_CLOUD_NEWER_MSG // 拉取比指定消息更晚的消息afterOption.count = 20 // 拉取 20 条afterOption.lastMsg = lastMsg // 从指定消息开始拉取,不包括该消息afterOption.groupID = "your_group_id" // 拉取群聊消息V2TIMManager.sharedInstance().getHistoryMessageList(afterOption, succ: { msgs in // 返回的消息列表中不包括指定消息 print("success")}) { code, desc in print("failure, code: \\(code), desc: \\(desc)")}// 获取当前的 message 对象V2TIMMessage *lastMsg = #搜索后的消息#;// 拉取指定消息之前的消息V2TIMMessageListGetOption *beforeOption = [[V2TIMMessageListGetOption alloc] init];beforeOption.getType = V2TIM_GET_CLOUD_OLDER_MSG; // 拉取比指定消息更早的消息beforeOption.count = 20; // 拉取 20 条beforeOption.lastMsg = lastMsg; // 从指定消息开始拉取, 不包括该消息beforeOption.groupID = #your group id#; // 拉取群聊消息[V2TIMManager.sharedInstance getHistoryMessageList:beforeOption succ:^(NSArray<V2TIMMessage *> *msgs) { // 返回的消息列表中不包括指定消息 NSLog(@"success");} fail:^(int code, NSString *desc) { NSLog(@"failure, code:%d, desc:%@", code, desc);}];// 拉取指定消息之后的消息V2TIMMessageListGetOption *afterOption = [[V2TIMMessageListGetOption alloc] init];afterOption.getType = V2TIM_GET_CLOUD_NEWER_MSG; // 拉取比指定消息更晚的消息afterOption.count = 20; // 拉取 20 条afterOption.lastMsg = lastMsg; // 从指定消息开始拉取,不包括该消息afterOption.groupID = #your group id#; // 拉取群聊消息[V2TIMManager.sharedInstance getHistoryMessageList:afterOption succ:^(NSArray<V2TIMMessage *> *msgs) { // 返回的消息列表中不包括指定消息 NSLog(@"success");} fail:^(int code, NSString *desc) { NSLog(@"failure, code:%d, desc:%@", code, 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_;};// 获取当前的 message 对象V2TIMMessage lastMsg = 搜索到的消息;// 拉取指定消息之前的消息V2TIMMessageListGetOption beforeOption;beforeOption.getType = V2TIMMessageGetType::V2TIM_GET_CLOUD_OLDER_MSG; // 拉取比指定消息更早的消息beforeOption.count = 20; // 拉取 20 条消息beforeOption.lastMsg = lastMsg; // 从指定消息开始拉取,不包括该消息beforeOption.userID = "you group id"; // 拉取群聊消息auto beforeCallback = new ValueCallback<V2TIMMessageVector>{};beforeCallback->SetCallback( [=](const V2TIMMessageVector& messageList) mutable { // 返回的消息列表中不包括 lastMsg std::cout << "success" << std::endl; delete beforeCallback; }, [=](int error_code, const V2TIMString& error_message) { std::cout << "error" << std::endl; delete beforeCallback; });V2TIMManager::GetInstance()->GetMessageManager()->GetHistoryMessageList(beforeOption, beforeCallback);// 拉取指定消息之后的消息V2TIMMessageListGetOption afterOption;afterOption.getType = V2TIMMessageGetType::V2TIM_GET_CLOUD_NEWER_MSG; // 拉取比指定消息更晚的消息afterOption.count = 20; // 拉取 20 条消息afterOption.lastMsg = lastMsg; // 从指定消息开始拉取,不包括该消息afterOption.userID = "you group id"; // 拉取群聊消息auto afterCallback = new ValueCallback<V2TIMMessageVector>{};afterCallback->SetCallback( [=](const V2TIMMessageVector& messageList) mutable { // 返回的消息列表中不包括 lastMsg std::cout << "success" << std::endl; delete afterCallback; }, [=](int error_code, const V2TIMString& error_message) { std::cout << "error" << std::endl; delete afterCallback; });V2TIMManager::GetInstance()->GetMessageManager()->GetHistoryMessageList(afterOption, afterCallback);
十三、解析信令消息
如果你使用了 IM SDK 的信令相关接口(Java / Swift / Objective-C),调用 invite/inviteInGroup 时,设置了 onlineUserOnly 为 false(Java) / NO(iOS),那么每次信令操作(包括 invite、cancel、accept、reject、timeout)都会产生一条自定义消息,该消息会通过 V2TIMAdvancedMsgListener 的 onRecvNewMessage 回调抛给用户,也可以通过历史消息拉取。
如果你需要根据信令信息做自定义化文本展示,可以使用信令解析接口 getSignalingInfo(Java / Swift / Objective-C / C++)获取信令信息。
接口原型
JavaSwiftObjective-CC++/** * 获取信令信息 * * 如果 invite 设置 onlineUserOnly 为 false,每次信令操作(包括 invite、cancel、accept、reject、timeout)都会产生一条自定义消息, * 该消息会通过 V2TIMAdvancedMsgListener -> onRecvNewMessage 抛给用户,用户也可以通过历史消息拉取,如果需要根据信令信息做自定义化文本展示,可以调用下面接口获取信令信息。 * * @param msg 消息对象 * @return V2TIMSignalingInfo 信令信息,如果为 null,则 msg 不是一条信令消息。 */public abstract V2TIMSignalingInfo getSignalingInfo(V2TIMMessage msg);/** * 获取信令信息 * * 如果 invite 设置 onlineUserOnly 为 false,每次信令操作(包括 invite、cancel、accept、reject、timeout)都会产生一条自定义消息,该消息会通过 V2TIMAdvancedMsgListener -> onRecvNewMessage 抛给用户,用户也可以通过历史消息拉取,如果需要根据信令信息做自定义化文本展示,可以调用下面接口获取信令信息。 * * @param msg 消息对象 * @return V2TIMSignalingInfo 信令信息,如果为 nil,则 msg 不是一条信令消息。 */public func getSignallingInfo(msg: V2TIMMessage) -> V2TIMSignalingInfo? /** * 获取信令信息 * * 如果 invite 设置 onlineUserOnly 为 NO,每次信令操作(包括 invite、cancel、accept、reject、timeout)都会产生一条自定义消息,该消息会通过 V2TIMAdvancedMsgListener -> onRecvNewMessage 抛给用户,用户也可以通过历史消息拉取,如果需要根据信令信息做自定义化文本展示,可以调用下面接口获取信令信息。 * * @param msg 消息对象 * @return V2TIMSignalingInfo 信令信息,如果为 nil,则 msg 不是一条信令消息。 */- (V2TIMSignalingInfo *)getSignallingInfo:(V2TIMMessage *)msg;/** * 获取信令信息 * * 如果 Invite 设置 onlineUserOnly 为 false,每次信令操作(包括 * Invite、Cancel、Accept、Reject、Timeout)都会产生一条自定义消息, 该消息会通过 * V2TIMAdvancedMsgListener -> onRecvNewMessage * 抛给用户,用户也可以通过历史消息拉取,如果需要根据信令信息做自定义化文本展示,可以调用下面接口获取信令信息。 * * @param msg 消息对象 * @return V2TIMSignalingInfo 信令信息,如果 V2TIMSignalingInfo::inviteID 为空字符串,则 msg 不是一条信令消息。 */virtual V2TIMSignalingInfo GetSignalingInfo(const V2TIMMessage& msg) = 0;
示例代码将演示:拉取到历史消息之后,解析信令消息的显示文本。
JavaSwiftObjective-CC++/// 信令消息对应的自定义文本public String getCallSignalingContentWithMessage(V2TIMMessage message) { if (message == null) { Log.e(TAG, " invalid param "); return ""; } V2TIMSignalingInfo signalingInfo = V2TIMManager.getSignalingManager().getSignalingInfo(message); if (signalingInfo == null) { Log.e(TAG, " signalingInfo is null "); return ""; } String content = ""; Gson gson = new Gson(); Object businessIdObj = null; String businessId = null; try { HashMap signalDataMap = gson.fromJson(signalingInfo.getData(), HashMap.class); if (signalDataMap != null) { businessIdObj = signalDataMap.get(TUIConstants.Message.CUSTOM_BUSINESS_ID_KEY); } else { Log.e(TAG, " signalDataMap is null "); return ""; } } catch (JsonSyntaxException e) { Log.e(TAG, " get signalingInfoCustomJsonMap error "); } if (businessIdObj instanceof String) { businessId = (String) businessIdObj; } if (TextUtils.equals(businessId, "av_call")) { if (signalingInfo.getActionType() == V2TIMSignalingInfo.SIGNALING_ACTION_TYPE_INVITE) { // 邀请通话 content = "@邀请通话"; } else if (signalingInfo.getActionType() == V2TIMSignalingInfo.SIGNALING_ACTION_TYPE_ACCEPT_INVITE) { // 同意邀请 content = "@同意通话"; } else { // 其他 // … } } return content;}/// 信令消息对应的自定义文本class func getCallSignalingContent(with message: V2TIMMessage) -> String? { guard let info = V2TIMManager.shared.getSignallingInfo(msg: message) else { return nil } // 解析透传的 data 字段 var param: [String: Any]? if let data = info.data { if let jsonData = data.data(using: .utf8) { do { param = try JSONSerialization.jsonObject(with: jsonData, options: .mutableContainers) as? [String: Any] } catch { print("JSON parsing error: \\(error)") } } } guard let parameters = param else { return nil } // 判断业务类型 guard let businessId = parameters["businessID"] as? String else { return nil } // 判断是否为音视频通话信令 var content: String? if businessId == "av_call" { switch info.actionType { case .V2TIMSignalingActionType_Invite: // 邀请通话 content = "邀请通话" case .V2TIMSignalingActionType_Accept_Invite: // 同意邀请 content = "同意通话" default: // 其他 // … break } } return content}/// 信令消息对应的自定义文本+ (NSString *)getCallSignalingContentWithMessage:(V2TIMMessage *)message{ V2TIMSignalingInfo *info = [[V2TIMManager sharedInstance] getSignallingInfo:message]; if (!info) { return nil; } // 解析透传的data字段 NSError *err = nil; NSDictionary *param = nil; if (info.data != nil) { param = [NSJSONSerialization JSONObjectWithData:[info.data dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONReadingMutableContainers error:&err]; } if (!param || ![param isKindOfClass:[NSDictionary class]]) { return nil; } // 判断业务类型 NSArray *allKeys = param.allKeys; if (![allKeys containsObject:@"businessID"]) { return nil; } NSString *businessId = [param objectForKey:@"businessID"]; // 判断是否为音视频通话信令 NSString *content = nil; if ([businessId isEqualToString:@"av_call"]) { if (info.actionType == SignalingActionType_Invite) { // 邀请通话 content = @"邀请通话"; } else if (info.actionType == SignalingActionType_Accept_Invite) { // 同意邀请 content = @"同意通话"; } else { // 其他 // … } } return content;}信令消息对应的自定义文本std::string GetCallSignalingContentWithMessage(const V2TIMMessage& message) { V2TIMSignalingInfo signalingInfo = V2TIMManager::GetInstance()->GetSignalingManager()->GetSignalingInfo(message); if (signalingInfo.inviteID.Empty()) { // 如果 V2TIMSignalingInfo::inviteID 为空,则 message 不是一条信令消息 return {}; } // 解析透传的 data 字段,使用开源库 RapidJSON :https://github.com/Tencent/rapidjson/ rapidjson::Document document; document.Parse(signalingInfo.data.CString(), signalingInfo.data.Size()); if (!document.HasMember("businessId") || !document["businessId"].IsString()) { return {}; } const char* businessId = document["businessId"].GetString(); // 判断是否为音视频通话信令 std::string content; if (businessId == "av_call") { if (signalingInfo.actionType == V2TIMSignalingActionType::SignalingActionType_Invite) { // 邀请通话 content = u8"邀请通话"; } else if (signalingInfo.actionType == 2TIMSignalingActionType::SignalingActionType_Accept_Invite) { // 同意邀请 content = u8"同意通话"; } else { // 其他 … } } return content;}
十四、1. 拉历史消息时,日志中出现 "total count of request cloud message exceed max limit" 信息
SDK 目前的策略是:
1. 当 getType 设置成拉云端历史消息,且拉取 count 条消息时,SDK 会从云端拉取 count 条消息。
2. SDK 过滤无效的消息,例如消息被删除、非当前用户关心的消息等。
3. 当云端历史消息中无效的消息过多,会触发 SDK 多次分页拉取。
为了提供系统的稳定性和健壮性,SDK 最多触发 3 次自动分页。当超过限制后,会出现 “total count of request cloud message exceed max limit” 的日志信息。
为了尽可能地减少此类限频机制对业务层的影响,你可以使用如下措施来减少无效消息的产生:
·你可以使用在线消息,即发送消息时设置 onlineUserOnly 为 YES/true 。
·如果是群聊消息,可以使用群定向消息指定消息的接收者,避免产生无效消息。
十五、2. 拉云端历史消息时,消息 “丢失” ?
当 getType 设置成拉云端历史消息,且拉取 count 条消息时,SDK 会做如下操作:
1. SDK 先从本地拉取 count 条消息。
2. SDK 再次云端拉取 count 条消息,过滤掉被删除等无效的消息,如果不够 count 条,SDK 内部触发分页拉取。
3. 将本地和云端消息进行合并,更新消息状态等信息。
4. 从合并的消息列表中,返回 count 条消息。
一般出现消息 “丢失” 时,指的是在第 2 步中拉取的无效消息过多,导致触发了问题 1 中的限频机制,从而导致实际拉取的云端消息不够。
建议按照 问题 1 中的解决方法来处理,如果还是不能解决问题,提交工单 进行交流。
十六、3. 拉取的历史消息,群名片等群成员信息没有实时更新?
·SDK 会在消息产生时,更新当前的群名片、role 等群成员信息并存储在本地数据库中。
·当拉取群历史消息时,会直接查询消息产生时的群成员信息,不会实时向后台请求更新。
如果你需要获取最新的群成员信息,你可以使用 getGroupMembersInfo(Java / Swift / Objective-C / C++)。
十七、4. 拉取历史消息时卡顿
SDK 内部已对消息拉取做了性能优化,你如果碰到消息卡顿的情况,可以先尝试减少拉取的消息数 count。