uniapp 集成腾讯云 IM 富媒体消息(地理位置/文件)

UniApp 集成腾讯云 IM 富媒体消息全攻略(地理位置/文件)

一、功能实现原理

腾讯云 IM 通过 消息扩展机制 支持富媒体类型,核心实现方式:

  1. 标准消息类型:直接使用 SDK 内置类型(文件、图片等)
  2. 自定义消息类型 :通过 TIM.TYPES.MSG_CUSTOM 承载结构化数据
  3. 文件上传服务 :集成 tim-upload-plugin 处理大文件分片上传
  4. 多端渲染:通过消息 payload 解析实现跨平台展示

二、地理位置消息实现

1. 获取设备定位(条件编译)

javascript 复制代码
// utils/location.js
export function getCurrentPosition() {
  return new Promise((resolve, reject) => {
    // 微信小程序环境
    #ifdef MP-WEIXIN
    wx.getLocation({
      type: 'gcj02',
      success: res => resolve(res),
      fail: err => reject(err)
    })
    #endif

    // H5 环境
    #ifdef H5
    if (navigator.geolocation) {
      navigator.geolocation.getCurrentPosition(
        pos => resolve(pos.coords),
        err => reject(err)
      )
    } else {
      reject(new Error('Geolocation not supported'))
    }
    #endif
  })
}

2. 构造地理位置消息

javascript 复制代码
// services/im.js
export function createLocationMessage(options) {
  const tim = initIM()
  
  return tim.createCustomMessage({
    to: options.to,
    conversationType: options.type || 'C2C',
    payload: {
      data: JSON.stringify({
        type: 'location',
        latitude: options.latitude,
        longitude: options.longitude,
        address: options.address || '',
        description: options.description || '当前位置'
      }),
      extension: ''
    }
  })
}

3. 消息解析与展示

html 复制代码
<template>
  <view v-if="msg.type === 'TIMCustomElem'" class="location-message">
    <map 
      :latitude="location.latitude"
      :longitude="location.longitude"
      :markers="markers"
      style="width: 100%; height: 300rpx;"
    ></map>
    <view class="address">{{ location.address }}</view>
  </view>
</template>

<script>
export default {
  props: ['msg'],
  computed: {
    location() {
      try {
        return JSON.parse(this.msg.payload.data)
      } catch (error) {
        return {
          latitude: 0,
          longitude: 0,
          address: '位置信息解析失败'
        }
      }
    },
    markers() {
      return [{
        id: 1,
        latitude: this.location.latitude,
        longitude: this.location.longitude,
        iconPath: '/static/location-marker.png',
        width: 40,
        height: 40
      }]
    }
  }
}
</script>

三、文件消息实现

1. 文件选择与上传

javascript 复制代码
// services/file-uploader.js
import { initIM } from './im'

const tim = initIM()
const uploadPlugin = tim.getPlugin('tim-upload-plugin')

export function uploadFile(filePath) {
  return new Promise((resolve, reject) => {
    uploadPlugin.upload({
      filePath,
      onProgress: percent => {
        uni.$emit('upload-progress', { percent })
      }
    }).then(res => {
      resolve({
        url: res.data.url,
        fileKey: res.data.fileKey
      })
    }).catch(err => {
      reject(err)
    })
  })
}

2. 发送文件消息

javascript 复制代码
export async function sendFileMessage(to, filePath) {
  const tim = initIM()
  
  try {
    // 上传文件
    const fileInfo = await uploadFile(filePath)
    
    // 创建文件消息
    const message = tim.createFileMessage({
      to,
      conversationType: 'C2C',
      payload: {
        fileName: filePath.split('/').pop(),
        fileSize: uni.getFileSystemManager().getFileInfoSync(filePath).size,
        url: fileInfo.url,
        fileKey: fileInfo.fileKey
      }
    })
    
    // 发送消息
    return tim.sendMessage(message)
  } catch (error) {
    uni.showToast({ title: '文件发送失败', icon: 'none' })
    throw error
  }
}

3. 文件预览组件

html 复制代码
<template>
  <view v-if="msg.type === 'TIMFileElem'" class="file-message">
    <view class="file-info">
      <image src="/static/file-icon.png" class="file-icon" />
      <view class="file-details">
        <view class="file-name">{{ fileName }}</view>
        <view class="file-size">{{ fileSize }}</view>
      </view>
    </view>
    <button @click="handlePreview">预览</button>
  </view>
</template>

<script>
export default {
  props: ['msg'],
  computed: {
    fileName() {
      return this.msg.payload.fileName || '未知文件'
    },
    fileSize() {
      return (this.msg.payload.fileSize / 1024).toFixed(1) + 'KB'
    }
  },
  methods: {
    handlePreview() {
      // 调用腾讯云文件预览服务
      window.open(this.msg.payload.url)
    }
  }
}
</script>

四、关键问题处理

1. 大文件分片上传

javascript 复制代码
// 上传插件配置
const uploadPlugin = tim.registerPlugin({
  'tim-upload-plugin': require('tim-upload-plugin')
})

uploadPlugin.setConfig({
  maxRetryTimes: 3,        // 最大重试次数
  maxChunkSize: 4 * 1024 * 1024, // 4MB分片
  timeout: 60 * 1000       // 超时时间
})

2. 消息类型安全校验

javascript 复制代码
// 消息接收时的类型校验
function validateMessage(msg) {
  try {
    if (msg.type === 'TIMCustomElem') {
      const data = JSON.parse(msg.payload.data)
      if (data.type !== 'location') throw new Error('Invalid custom type')
    }
  } catch (error) {
    console.warn('非法消息格式:', msg)
    return false
  }
  return true
}

3. 跨平台文件路径处理

javascript 复制代码
// 路径标准化工具
export function normalizeFilePath(path) {
  // 微信小程序临时路径处理
  #ifdef MP-WEIXIN
  return path.replace('wxfile://', '/wxaf')
  #endif

  // H5环境直接返回
  #ifdef H5
  return path
  #endif
}

五、高级功能扩展

1. 地理位置消息导航

javascript 复制代码
// 调用系统地图应用
export function openMapApp(location) {
  #ifdef MP-WEIXIN
  wx.openLocation({
    latitude: location.latitude,
    longitude: location.longitude,
    name: location.address,
    scale: 18
  })
  #endif

  #ifdef H5
  window.open(`https://uri.amap.com/marker?position=${location.longitude},${location.latitude}`)
  #endif
}

2. 文件消息安全检测

javascript 复制代码
// 集成腾讯云内容安全检测
export async function checkFileSecurity(fileKey) {
  const res = await axios.post('https://cis.tencentcloudapi.com/', {
    Action: 'TextModeration',
    Content: fileKey,
    // 其他必要参数...
  })

  return res.data.Suggestion === 'Block' ? false : true
}

3. 消息附件管理

javascript 复制代码
// 消息附件存储方案
const ATTACHMENT_STORAGE = {
  images: [],
  files: [],
  locations: []
}

// 消息接收时自动归档
tim.on(tim.EVENT.MESSAGE_RECEIVED, (event) => {
  event.data.forEach(msg => {
    if (msg.type === 'TIMImageElem') {
      ATTACHMENT_STORAGE.images.push(msg.payload.imageInfoArray[0].url)
    }
    // 其他类型处理...
  })
})

六、常见问题排查

  1. Q: 地理位置消息显示空白

    A: 检查小程序定位权限设置,H5需使用HTTPS协议

  2. Q: 文件上传进度不更新

    A: 确认使用了最新版 tim-upload-plugin(≥1.1.0),检查事件监听代码

  3. Q: 跨平台文件路径不兼容

    A: 必须使用 normalizeFilePath 处理不同平台路径差异

  4. Q: 自定义消息解析失败

    A: 检查JSON格式有效性,建议使用Protocol Buffers进行序列化

七、性能优化建议

  1. 对超过50MB的文件启用分片上传断点续传
  2. 使用WebP格式压缩图片消息(需服务端支持)
  3. 实现消息附件本地缓存策略(使用uni.setStorage)
  4. 对高频地理位置消息进行采样合并
相关推荐
狼性书生2 小时前
uniapp实现的简约美观的星级评分组件
前端·uni-app·vue·组件
红米饭配南瓜汤8 小时前
WebRTC中的几个Rtp*Sender
网络·网络协议·音视频·webrtc·媒体
Jiaberrr9 小时前
uniapp 安卓 APP 后台持续运行(保活)的尝试办法
android·前端·javascript·uni-app·app·保活
不老刘9 小时前
uniapp+vue3实现CK通信协议(基于jjc-tcpTools)
前端·javascript·uni-app
CRMEB定制开发10 小时前
CRMEB 框架中 PHP 上传扩展开发:涵盖本地上传及阿里云 OSS、腾讯云 COS、七牛云
阿里云·php·腾讯云·微信商城·php商城源码
疯狂的沙粒11 小时前
uni-app 如何实现选择和上传非图像、视频文件?
前端·javascript·uni-app
$程11 小时前
Uniapp 二维码生成与解析完整教程
前端·uni-app
tryCbest11 小时前
UniApp系列
uni-app·web
Clownseven11 小时前
“轻量应用服务器” vs. “云服务器CVM”:小白入门腾讯云,哪款“云机”更适合你?(场景、配置、价格对比解析)
运维·服务器·腾讯云