当前位置: 首页 > news >正文

直播互动小程序端Web运营端接入指南

概述

直播互动使用阿里云的直播互动消息(新)。

使用该服务后,小程序端的直播互动消息只需要调用 service 获取长链接的 token,再根据景区ID 获取互动群组的信息后,即可加入互动聊天群,后续发送/接收消息就直接与阿里云的服务交互即可。

在互动之外,有一项安全措施,如果用户发送的内容触发了敏感词,阿里云会阻止发送,并返回报错信息,小程序端需要处理这个情况,上报给 service 端存储记录,方便后续审查故意捣乱的用户。

小程序端接入准备

微信小程序参考阿里云的官方文档 https://help.aliyun.com/zh/live/user-guide/wechat-applet-integration

需要做的事情:

  • 配置 request 合法域名和 socket 合法域名;

  • 集成 SDK 文件

暂时无法在飞书文档外展示此内容

 

// 远程地址 https://dji-files.oss-cn-shanghai.aliyuncs.com/mini/libs/alivc-im/alivc-im.wasm.br https://dji-files.oss-cn-shanghai.aliyuncs.com/mini/libs/alivc-im/alivc-im.js

小程序端初始化 SDK

下载 sdk 导入后,就可以开始准备初始化 SDK。

首先调用接口 【小程序】获取直播互动消息的Token 即可获取初始化 SDK 所需的数据,包括 appId, appSign,appToken 等,结构如下:

 

{ "code": 100000, "msg": "success", "data": { "appId": "7d86bc441d4d", "appSign": "H4sIAAAAAAAE\/wCQAG\/\/zguHB+lYCilkv7diSkk4GjyyatdBTE9ppMH5vtkzCENzFWzFkPDr9kLwV2xWwKQMHpj32qeU68PPqz9HxpUBWjQrFLtYfkvpHd8It\/HtTjHbZ998XlCYz24UbbtRa2ZWLo5HSUnpq7XJtWA7ya8dpGoFA\/jkXEMddTEr+lrepRpJZETW70EvLRSCMWlCeAAsAAAA\/\/8BAAD\/\/9yRFrGQAAAA", "appToken": "9e9859da5add60fd81824279d3fcdf1770801f0dee7a0ed957724ff221c05139", "auth": { "userId": "u108386", "nonce": "AK-143e213afa5700b4b4367ebd66ad9130", "timestamp": 1760409785, "role": "user", "token": "9e9859da5add60fd81824279d3fcdf1770801f0dee7a0ed957724ff221c05139" }, "user": { "user_id": "u108386", "nickname": "陆晋2025", "avatar": "https:\/\/fly-picture.tos-cn-beijing.volces.com\/202506\/17498196995615.jpg", "role": "user" } }, "time": "2025-10-13 10:43:05" }

小程序端的初始化代码参考:

 

// 请结合您项目实际情况引入 SDK import { ImEngine, ImLogLevel, ImMessageLevel } from '../../lib/alivc-im.js' const engine = ImEngine.createEngine(); let messageManager; Page({ data: { message: '', messageList: [], authData: {}, userInfo: { avatar: '', nickname: '', userId: '' }, groupId: '', formatTime: (timestamp) => { const date = new Date(timestamp); return `${date.getHours()}:${date.getMinutes()}`; } }, onLoad() { console.info('home page on load!') const _this = this wx.request({ url: 'http://localhost:8000/api/mini/live/get-message-token', data: { debug_mode: 1 }, header: { token: 'xxx' }, success: async function (res) { console.info(res) const resp = res.data _this.setData({ authData: resp.data.auth, userInfo: { avatar: resp.data.user.avatar, nickname: resp.data.user.nickname, userId: resp.data.user.user_id } }) console.info('authData', _this.data.authData) console.info('userInfo', _this.data.userInfo) await engine.init({ appId: resp.data.appId, appSign: resp.data.appSign, logLevel: ImLogLevel?.ERROR || 0, locateFile: (url) => { if (url.endsWith('.wasm')) { return '/lib/alivc-im.wasm.br'; } return url; }, }) await _this.login() // 获取groupId wx.request({ url: 'http://localhost:8000/api/mini/live/get-message-group-info', data: { scenic_id: 119 }, success: async function (res2) { console.info(res2) _this.setData({ groupId: res2.data.data.group_id }) await _this.joinGroup() await _this.loadRecentMessages() } }) } }) }, onReady() { console.info('home page on ready!') }, onShow() { }, async login() { try { const _this = this; const authData = _this.data.authData; console.info('login - authData', authData) await engine.login({ user: { userId: _this.data.userInfo.userId, userExtension: JSON.stringify(_this.data.userInfo) }, userAuth: authData }); console.info('互动消息登录成功'); } catch (error) { console.info('互动消息登录失败', error); } }, async joinGroup() { const groupManager = engine.getGroupManager(); groupManager.joinGroup(this.data.groupId); messageManager = engine.getMessageManager(); // 提取回调函数为独立方法 messageManager.on('recvgroupmessage', this.handleGroupMessage.bind(this)); }, handleGroupMessage(msg, groupId) { const _this = this; if (groupId === _this.data.groupId) { let senderInfo = {}; try { senderInfo = JSON.parse(msg.sender.userExtension || '{}'); } catch (e) { console.error('Failed to parse sender userExtension:', e); } const newMessage = { sender: senderInfo, data: msg.data, time: msg.timestamp }; // 根据消息的 type 去展示消息 // 使用 setData 更新 messageList _this.setData({ messageList: [..._this.data.messageList, newMessage] }); } }, async loadRecentMessages() { const _this = this; const resp = await messageManager.listRecentMessage({ groupId: _this.data.groupId }); console.info('load recent messages...') resp.messageList.forEach(item => { const sender = JSON.parse(item.sender.userExtension) _this.data.messageList.push({ sender, data: item.data, time: item.timestamp }) }) _this.setData({ messageList: _this.data.messageList }) }, formatTime(timestamp) { if (!timestamp) return '' const date = new Date(timestamp) return `${date.getHours().toString().padStart(2, '0')}:${date.getMinutes().toString().padStart(2, '0')}` }, async sendMessage() { const _this = this console.info('发送消息...', _this.data.message) // 发群组消息前请确保已加入群组 try { const messageId = await messageManager.sendGroupMessage({ groupId: _this.data.groupId, data: _this.data.message, type: 100000, // 自定义消息类型,需大于10000 skipAudit: false, skipMuteCheck: false, level: ImMessageLevel.NORMAL, noStorage: false, repeatCount: 1 }) console.log('send success, messageId: ', messageId, _this.data.message) _this.setData({ message: '' }) } catch (e) { // error.code 为 425 时为未加入群组 console.log('send fail', e, e.code, e.message) // 406 if (e.code === 406) { // todo 触发敏感词,调用接口上报! wx.showToast({ title: '请文明发言!', icon: 'error' }) } if (e.code === 442) { wx.showToast({ title: '直播已禁言', icon: 'error' }) } } }, onInputMessage(e) { console.info('正在输入...', e.detail.value) const val = e.detail.value this.setData({ message: val }) }, })

上面的 demo 中,上报敏感词接口(【小程序】直播互动敏感词上报接口)未接入,需要接入一下。

官方文档参见:微信小程序集成 。

示例页面源码参考(小程序原生开发,无第三方依赖):

暂时无法在飞书文档外展示此内容

Web 端飞控页面接入

引入sdk : 在 public/index.html 页面的 head 标签内添加 js 引用:

 

<script src="https://g.alicdn.com/apsara-media-box/imp-interaction/1.8.0/alivc-im.iife.js"></script>

下面是基于 vue2 的完整使用示例:

 

const { ImEngine, ImLogLevel, ImMessageLevel } = AliVCInteraction import { getLiveMessageToken, getLiveMessageGroups, getLiveMessageGroupInfo, getGroupAdminPrivilege } from '@/api/live' const engine = ImEngine.createEngine() export default { name: 'LiveMessage', data() { return { messageManager: null, groups: [], message: '', messageList: [], authData: {}, groupId: '', userInfo: { userId: '', nickname: '', avatar: '' }, currentGroupId: '' } }, async mounted() { const tokenResp = await getLiveMessageToken() console.info('tokenResp', tokenResp) this.authData = tokenResp.data.auth this.userInfo = { userId: tokenResp.data.user.user_id, nickname: tokenResp.data.user.nickname, avatar: tokenResp.data.user.avatar } await engine.init({ // deviceId: deviceId, //[选填] appId: tokenResp.data.appId, //[必填]传空会返回初始化失败-2;请务必在创建应用后,将示例中的APP_ID替换为您应用的AppId,否则无法使用; appSign: tokenResp.data.appSign, //[必填]传空会返回初始化失败-2;请务必在创建应用后,将示例中的APP_SIGN替换为您应用的AppSign,否则无法使用; logLevel: ImLogLevel?.ERROR || 0 //[选填],指定Log日志可输出的最小等级,默认是ImLogLevel.DEBUG;若需要关闭Log日志,则设置为ImLogLevel.NONE; }) const result = await this.login() console.info('login result', result) // 加载群组 const resp = await getLiveMessageGroups() this.groups = resp.data.groups // 默认加载第一个群组 if (this.groups.length > 0) { await this.joinGroup(this.groups[0].group_id) } // 监听群聊消息 const _this = this this.messageManager.on('recvgroupmessage', (msg, gid) => { console.log('recvgroupmessage', msg, gid) if (this.currentGroupId === gid) { // 使用currentGroupId而不是groupId _this.messageList.push({ sender: JSON.parse(msg.sender.userExtension), data: msg.data, timestamp: msg.timestamp }) // 滚动到底部 _this.scrollToBottom() } }) }, beforeDestroy() { if (this.messageManager) { this.messageManager.removeAllListeners() } }, methods: { scrollToBottom() { this.$nextTick(() => { const sc = this.$refs.chatsScrollbar if (sc && sc.wrap) { sc.wrap.scrollTop = sc.wrap.scrollHeight } }) }, formatTime(timestamp) { if (!timestamp) return '' const date = new Date(timestamp) return `${date.getHours().toString().padStart(2, '0')}:${date.getMinutes().toString().padStart(2, '0')}` }, async login() { try { const _this = this return await engine.login({ user: { userId: _this.userInfo.userId, userExtension: JSON.stringify(_this.userInfo) }, userAuth: { timestamp: _this.authData.timestamp, // 服务端返回timestamp值 nonce: _this.authData.nonce, // 服务端返回nonce值 role: _this.authData.role, // 是否为admin角色,如果不需要可以设置为空 token: _this.authData.token // 服务端返回token值 } }) } catch (error) { console.info(error) } }, async joinGroup(groupId) { // 如果当前已在该群组中,则不重复加入 if (this.currentGroupId === groupId) { return } // 保存目标群组ID this.groupId = groupId const groupManager = engine.getGroupManager() // 先离开当前群组(如果已在群组中) if (this.currentGroupId) { try { await groupManager.leaveGroup(this.currentGroupId) } catch (e) { console.warn('离开群组失败:', e) } } try { await groupManager.joinGroup(groupId) // 记录当前加入的群组ID this.currentGroupId = groupId } catch (e) { console.error('加入群组失败:', e) this.$message({ type: 'error', message: '加入群组失败: ' + e.message }) return } this.messageManager = engine.getMessageManager() // 清空消息列表 this.messageList = [] // 加载历史消息 await this.loadRecentMessages() }, async loadRecentMessages() { const _this = this try { // 确保使用当前已加入的群组ID const resp = await this.messageManager.listRecentMessage({ groupId: this.currentGroupId }) console.info('resp.messageList', resp.messageList) resp.messageList.forEach(item => { _this.messageList.push({ sender: JSON.parse(item.sender.userExtension), data: item.data, timestamp: item.timestamp }) }) _this.scrollToBottom() } catch (error) { console.error('加载历史消息失败:', error) } }, async sendMessage() { const _this = this // 发群组消息前请确保已加入群组 if (!this.currentGroupId) { // 使用currentGroupId this.$message({ type: 'error', message: '请先加入群组!' }) return } try { const messageId = await _this.messageManager.sendGroupMessage({ groupId: _this.currentGroupId, // 使用currentGroupId data: _this.message, // 发送消息内容,如果是结构化可考虑使用json字符串 type: 88888, // 自定义消息类型,需大于10000 skipAudit: false, skipMuteCheck: false, level: ImMessageLevel.NORMAL, noStorage: false, // 可选(默认 false)true:表示该消息不需要存储,也无法拉取查询;false:消息进行存储,可以拉取查询。如果在直播间的弹幕场景,需要设置为 false。 repeatCount: 1 // 可选(默认 1)本消息重复数量,内容完成一样的消息可以使用该字段进行聚合,并发送一次即可。 }) _this.message = '' console.log('send success, messageId: ', messageId) } catch (e) { // error.code 为 425 时为未加入群组 // 406 if (e.code === 406) { // todo 如果是 406 表示触发了敏感词,直接静默上报给服务端 const info = e.message.replace('code:406;msg:', '') // console.info(info) console.log('触发敏感词,上报服务端: ', JSON.parse(info)) // 报错 this.$message({ type: 'error', message: '请文明发言!' }) } else { console.error('发送消息失败:', e) this.$message({ type: 'error', message: '发送消息失败: ' + e.message }) } } }, async muteGroup() { const groupManager = engine.getGroupManager() await groupManager.muteAll(this.currentGroupId) this.$message({ type: 'success', message: '全体禁言成功' }) }, async unmuteGroup() { const groupManager = engine.getGroupManager() await groupManager.cancelMuteAll(this.currentGroupId) this.$message({ type: 'success', message: '取消全体禁言成功' }) }, async muteUser(userId) { try { const groupManager = engine.getGroupManager() await groupManager.muteUser({ groupId: this.currentGroupId, // 群组ID userList: [userId] // 需要禁言的用户ID列表 }) this.$message({ type: 'success', message: '禁言成功' }) } catch (e) { this.$message({ type: 'error', message: '禁言失败' }) console.error('禁言失败:', e) } }, async unmuteUser(userId) { try { const groupManager = engine.getGroupManager() await groupManager.cancelMuteUser({ groupId: this.currentGroupId, // 群组ID userList: [userId] // 需要取消禁言的用户ID列表 }) this.$message({ type: 'success', message: '取消全体禁言成功' }) } catch (e) { this.$message({ type: 'error', message: '取消全体禁言失败' }) console.error('取消全体禁言失败:', e) } }, async getAdminPrivilege() { const gid = this.currentGroupId const resp = await getGroupAdminPrivilege({ group_id: gid }) console.info('获取群组管理员权限resp', resp) }, isSelf(item) { return item && item.sender && item.sender.userId && item.sender.userId === this.userInfo.userId } } }

示例中调用的服务端接口如下:

  • 【Web运营端】获取直播互动消息的Token

  • 【Web运营端】获取直播互动所属的聊天组信息

  • 【Web运营端】获取直播互动群组的管理权限

获取管理权限后,即可使用 groupManager 管理群组,包括用户禁言等操作。

比如全体禁言:

 

groupManager.muteAll(groupId)

撤销群体禁言:

 

groupManager.cancelMuteAll(groupId)

对部分用户禁言:

 

groupManager.muteUser({ // 取消同理用 cancelMuteUser groupId: this.currentGroupId, // 群组ID userList: [userId] // 需要禁言的用户ID列表 })

官方文档参见 Web端集成 。

消息类型

由于消息不走服务端传递,传播路径是客户端->阿里云->客户端,所以消息类型由客户端自己定义并解析。

消息类型 type 取值从 10000 开始。

下面是建议方案,非强制,不一定都用得到:

 

type=10000 文本消息 type=10001 表情消息 type=10002 图片消息 type=10003 视频消息 type=11000 点赞 type=11001 送花 type=12000 加入直播间(joinGroup)

http://www.dtcms.com/a/536340.html

相关文章:

  • Java—抽象类
  • 坛墨网站建设wordpress 邀请
  • idc网站模版百度提交
  • 树莓派3B+降低功耗及恢复脚本
  • 开源项目解读4-高性能并发缓存库Ristretto
  • 《微信小程序》第五章:登录-API封装
  • MYSQL数据库入门操作
  • 青岛建设集团网站101工业设计有限公司
  • wordpress 网站上传到服务器错误怎么建设手机网站
  • MySQL 下载、安装及配置教程(Msi安装)
  • AWS CloudTrail 可观测最佳实践
  • 商城网站设计公司十大奢侈品排名
  • 建设部网站从哪登陆网站建设学什么书
  • STM32学习(MCU控制)(NVIC)
  • C++11新特性:强类型枚举/编译期断言/元组
  • 个人做网站的注意事项动漫做暧视频网站
  • 高并发电商架构设计与落地:从微服务拆分到全链路优化
  • 无人机电调芯片替换全解析:从 AM32 架构到 STM32F072、GD32E230 与 AT32F421 的实战对比
  • 郴州市建设网站ps软件下载免费中文版
  • 选择扬中网站建设做电商一个月可以赚多少钱
  • flutter开发的音乐搜索app
  • 介绍一下Ribbon的工作原理
  • Linux系统中安装部署开源的建站、博客工具——Halo
  • 【论文精读】STREAM:视频生成模型的时空评估新指标
  • 建设网站的模板下载福田企业网站优化有用吗
  • 网站建设公司营业范围app公司是做什么的
  • KP3310SGA线性降压无电感替代阻容降压220V转5V3.3V2.7V
  • 【 国产信创系统】udev监测USB事件
  • 洒长春菩网站建设我要浏览国外网站怎么做
  • 【JUnit实战3_16】第九章:容器内测试(上)