UniApp 集成腾讯云 IM 富媒体消息全攻略(地理位置/文件)
一、功能实现原理
腾讯云 IM 通过 消息扩展机制 支持富媒体类型,核心实现方式:
- 标准消息类型:直接使用 SDK 内置类型(文件、图片等)
- 自定义消息类型 :通过
TIM.TYPES.MSG_CUSTOM
承载结构化数据 - 文件上传服务 :集成
tim-upload-plugin
处理大文件分片上传 - 多端渲染:通过消息 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)
}
// 其他类型处理...
})
})
六、常见问题排查
-
Q: 地理位置消息显示空白
A: 检查小程序定位权限设置,H5需使用HTTPS协议
-
Q: 文件上传进度不更新
A: 确认使用了最新版
tim-upload-plugin
(≥1.1.0),检查事件监听代码 -
Q: 跨平台文件路径不兼容
A: 必须使用
normalizeFilePath
处理不同平台路径差异 -
Q: 自定义消息解析失败
A: 检查JSON格式有效性,建议使用Protocol Buffers进行序列化
七、性能优化建议
- 对超过50MB的文件启用分片上传断点续传
- 使用WebP格式压缩图片消息(需服务端支持)
- 实现消息附件本地缓存策略(使用uni.setStorage)
- 对高频地理位置消息进行采样合并