微信小程序(uniapp)实现腾讯云 IM 消息撤回

uniapp 实现腾讯云 IM 消息撤回功能实战指南

一、功能实现原理

腾讯云 IM 的消息撤回功能通过 消息修订(Message Revision) 机制实现,核心流程如下:

  1. 发送方调用撤回 API 删除指定消息
  2. 云端生成撤回通知消息(类型为 TIM.TYPES.MSG_REVOKED
  3. 接收方收到通知后执行本地消息删除
  4. 全平台自动同步消息状态(需开启消息漫游)

二、核心实现步骤

1. 发送方撤回逻辑

javascript 复制代码
// services/im.js
export async function revokeMessage(message) {
  const tim = initIM()
  
  try {
    // 执行消息撤回操作
    const res = await tim.revokeMessage(message)
    
    // 更新本地消息状态(立即生效)
    if (res.data.revokeMessage) {
      const conv = tim.getConversationProfile(message.conversationID)
      conv.setMessageRevoked(message.clientMsgID)
    }
    
    return res
  } catch (error) {
    console.error('撤回失败:', error)
    throw new Error('消息撤回失败,请检查网络')
  }
}

2. 接收方消息处理

javascript 复制代码
// 消息监听器(全局注册)
export function setupMessageListener(callback) {
  const tim = initIM()
  
  tim.on(tim.EVENT.MESSAGE_RECEIVED, (event) => {
    event.data.forEach(msg => {
      // 处理撤回通知
      if (msg.type === tim.TYPES.MSG_REVOKED) {
        handleRevokeNotice(msg)
        return
      }
      
      callback(msg)
    })
  })
}

// 撤回通知处理
function handleRevokeNotice(notice) {
  const { revokedMessageClientMsgID, operator } = notice.payload
  
  // 查找本地对应消息
  const conversation = tim.getConversationProfile(notice.conversationID)
  const originalMsg = conversation.getMessage(revokedMessageClientMsgID)
  
  if (!originalMsg) return
  
  // 权限验证(仅允许发送者撤回)
  if (originalMsg.from !== operator.userID) {
    console.warn('非法撤回操作', operator)
    return
  }
  
  // 执行本地删除
  conversation.deleteMessage(revokedMessageClientMsgID)
  
  // 触发UI更新(示例)
  uni.$emit('message-revoked', {
    conversationID: notice.conversationID,
    clientMsgID: revokedMessageClientMsgID
  })
}

3. UI 层集成示例

html 复制代码
<template>
  <view class="message-list">
    <view 
      v-for="(msg, index) in messages"
      :key="msg.clientMsgID"
      class="message-item"
    >
      <!-- 消息内容 -->
      <template v-if="!msg.isRevoked">
        {{ msg.payload.text }}
      </template>
      
      <!-- 撤回提示 -->
      <view v-else class="revoked-tip">
        "{{ msg.payload.description }}" 已被撤回
      </view>
      
      <!-- 长按操作菜单 -->
      <view 
        v-if="canRevoke(msg)"
        class="action-menu"
        @longpress="showActionSheet(msg)"
      >
        ⋮
      </view>
    </view>
  </view>
</template>

<script>
export default {
  data() {
    return {
      messages: []
    }
  },
  methods: {
    // 权限校验
    canRevoke(msg) {
      return msg.from === this.currentUser.userID && 
             !msg.isRevoked &&
             Date.now() - msg.time < 2 * 60 * 1000 // 2分钟内可撤回
    },
    
    // 执行撤回
    async handleRevoke(msg) {
      try {
        await revokeMessage(msg)
        uni.showToast({ title: '撤回成功', icon: 'none' })
      } catch (error) {
        uni.showToast({ title: error.message, icon: 'none' })
      }
    }
  }
}
</script>

三、关键问题处理

1. 撤回时间限制

javascript 复制代码
// 配置中心(建议)
const IM_CONFIG = {
  REVOKE_TIME_LIMIT: 2 * 60 * 1000 // 2分钟
}

// 权限校验时使用
if (Date.now() - msg.time > IM_CONFIG.REVOKE_TIME_LIMIT) {
  throw new Error('超过可撤回时间')
}

2. 消息状态同步

javascript 复制代码
// 消息漫游配置(初始化时)
tim = TIM.create({
  SDKAppID: config.SDKAppID
})

// 开启消息漫游(需在控制台配置)
tim.setMessageRevokeMode({
  mode: TIM.TYPES.REVOKE_MODE_SENDER, // 仅发送方可撤回
  syncOtherMachine: true // 同步到其他端
})

3. 异常场景处理

javascript 复制代码
// 撤回失败重试机制
export async function revokeWithRetry(msg, retries = 3) {
  try {
    return await revokeMessage(msg)
  } catch (error) {
    if (retries <= 0) throw error
    
    await new Promise(resolve => setTimeout(resolve, 1000))
    return revokeWithRetry(msg, retries - 1)
  }
}

四、高级功能扩展

1. 富媒体消息撤回

javascript 复制代码
// 自定义撤回描述(图片/文件等)
function getRevokeDescription(msg) {
  switch(msg.type) {
    case TIM.TYPES.MSG_IMAGE:
      return '[图片]'
    case TIM.TYPES.MSG_FILE:
      return '[文件]'
    case TIM.TYPES.MSG_CUSTOM:
      return JSON.parse(msg.payload.data).description || '[自定义消息]'
    default:
      return msg.payload.text || '[未知消息]'
  }
}

2. 撤回动画效果

css 复制代码
/* 添加CSS过渡 */
.message-item.revoking {
  animation: fadeOut 0.3s forwards;
}

@keyframes fadeOut {
  to {
    opacity: 0;
    transform: translateX(20px);
  }
}

3. 服务端日志记录

javascript 复制代码
// 撤回事件上报(示例)
async function logRevokeEvent(msg, operator) {
  await axios.post('/api/im/revoke-log', {
    sdk_app_id: process.env.SDKAppID,
    group_id: msg.groupID,
    operator_id: operator.userID,
    target_msg_id: msg.clientMsgID,
    timestamp: Date.now()
  })
}

五、常见问题排查

  1. Q: 撤回后对方仍显示消息

    A: 检查消息漫游是否开启,确认双方客户端版本 ≥ 2.15.0

  2. Q: 无法撤回超过2分钟的消息

    A: 腾讯云默认限制为2分钟,需在控制台申请延长权限

  3. Q: 群聊中非群主成员撤回失败

    A: 确认群类型是否为 Private(私有群),Public 群需群主操作

  4. Q: 撤回通知不显示描述

    A: 检查自定义消息解析逻辑,确保 payload 格式正确

六、性能优化建议

  1. 使用 tim.getMessageRevokeStatus() 批量查询消息状态
  2. 对已撤回消息进行本地缓存,避免重复查询
  3. 添加防抖处理,防止快速连续撤回导致性能问题
相关推荐
^Rocky2 小时前
uniapp 实现腾讯云 IM 消息已读回执
uni-app·云计算·腾讯云
Estar.Lee2 小时前
腾讯云开发者社区文章内容提取免费API接口教程
android·云计算·腾讯云·api·免费api·api大全
lqj_本人5 小时前
鸿蒙OS&UniApp导航栏组件开发:打造清新简约的用户界面#三方框架 #Uniapp
ui·uni-app·harmonyos
lyz2468596 小时前
动态报表筛选多项时的优化处理
javascript·uni-app·view design
obiwan7 小时前
Jenkins CI/CD 自动化构建部署微信小程序体验版
微信小程序
lqj_本人8 小时前
鸿蒙OS&UniApp 开发的图文混排展示组件#三方框架 #Uniapp
华为·uni-app·harmonyos
lqj_本人12 小时前
鸿蒙OS&UniApp页面切换动效实战:打造流畅精致的转场体验#三方框架 #Uniapp
华为·uni-app·harmonyos
lqj_本人14 小时前
鸿蒙OS&UniApp 移动端直播流播放实战:打造符合鸿蒙设计风格的播放器#三方框架 #Uniapp
华为·uni-app·harmonyos
lqj_本人14 小时前
鸿蒙OS&UniApp复杂表单与动态验证实践:打造高效的移动端表单解决方案#三方框架 #Uniapp
华为·uni-app·harmonyos
前端小配角14 小时前
微信小程序开发——Skyline中Worklet动画
微信小程序