uniapp 实现直播功能的完整方案与实战指南
2026/5/10 1:45:14 网站建设 项目流程

随着电商带货、在线教育、秀场社交等业务爆发式增长,直播已经从"锦上添花"变成"业务刚需"。对前端团队来说,用 uniapp 一套代码覆盖 H5、微信小程序、iOS、Android 是性价比最高的选择。但直播涉及音视频采集、编解码、实时传输、CDN 分发等复杂环节,从零自建难度极高。本文从方案选型到代码落地,完整讲清楚 uniapp 实现直播的工程化路径,并以即构科技的 ZEGO Express SDK 为例给出实战代码。

一、uniapp 直播的技术方案对比

uniapp 实现直播的技术方案一般有三种,如下:

  • 方案一:基于小程序原生组件live-pusher/live-player;
  • 方案二:第三方 RTC SDK,如即构科技(ZEGO) 、腾讯云/阿里云等;
  • 方案三:WebRTC / HLS 自建。

选型阶段先搞清楚方案的差异,避免踩坑后再返工。

1.1 主流方案全景对比

对比维度方案一:原生组件live-pusher/live-player

方案二:第三方 RTC SDK / 即构科技(ZEGO) 、腾讯云等

方案三:WebRTC / HLS 自建
技术原理基于小程序宿主能力,RTMP 推流 + FLV/RTMP 拉流商用 RTC 引擎,底层自研协议 + CDN原生 WebRTC + 自建信令 + CDN
支持平台仅微信小程序、QQ 小程序、部分 App 端全端(H5 / 小程序 / App / Web)H5 / App(需自行适配)
延迟1-3 秒(RTMP)200-400ms(RTC)、1-3 秒(CDN 直播)300ms-2s(依实现而定)
连麦互动仅支持主播-观众单向,不支持多人连麦支持一对一、多人连麦、PK 连麦需自行实现混流、信令
接入成本低,直接用 uni 内置标签中,引入 SDK + 调用 API高,需音视频团队
并发能力依赖小程序平台限制商用级,百万级并发取决于自建规模
美颜 / 滤镜 / 特效基础美颜SDK 内置 + 可扩展 AI 特效需自行集成
鉴权与安全需自行搭建 RTMP 鉴权官方 Token 鉴权、房间隔离自行设计鉴权体系
弱网优化依赖基础协议,较弱有专门抗弱网算法(NACK / FEC / 自适应码率)取决于实现
费用免费(仅用带宽)按用量计费(分钟数 / 流量)带宽 + 服务器 + 人力
上线周期1-3 天1-2 周1-3 个月
适用场景简单秀场直播、只在微信内使用电商带货、在线教育、互动直播、连麦 PK有特殊定制需求的大厂

1.2 选型决策流程

只在微信小程序内使用? │ ┌────┴────┐ 是 否 │ │ 需要连麦? 需要低延迟互动? │ │ 是 / 否 是 / 否 │ │ 方案二 / 方案一 方案二(RTC) / 方案二(CDN)

结论:绝大多数"需要跨端 + 互动直播"的业务,方案二是最合理的选择。下面进入实战。

二、核心概念速览

  • 推流(Publish):主播将本地采集的音视频上传到服务器
  • 拉流(Play):观众从服务器下载并播放音视频流
  • 房间(Room):一次直播的逻辑容器,主播和观众通过 roomID 关联
  • RTC vs CDN 直播:RTC 走实时协议,延迟 400ms 内,支持双向互动;CDN 直播走 HLS/FLV,延迟 1-3 秒,成本更低
  • Token:登录房间的鉴权凭证,必须由服务端生成

三、实战:基于 ZEGO Express SDK 在 uniapp 中实现直播

ZEGO Express SDK 是即构科技(ZEGO)开发的一款实时音视频互动服务产品,能够为开发者提供便捷接入、高可靠、多平台互通的音视频服务。通过低至 200 ms 的端到端平均时延,业内领先的保障弱网质量的 QoS 策略,并结合强大的 3A 处理能力,完美支持一对多、多对多的实时音视频通话、直播、会议等场景。

本节给出一个可跑通的最小直播 Demo:主播开播 + 观众观看,覆盖 Web / 小程序 / App 三端。

3.1 环境准备

版本要求:

  • HBuilderX 3.8.0+
  • Vue 3(推荐)或 Vue 2
  • uniapp 最新稳定版

控制台申请:

  1. 登录 ZEGO 控制台创建项目,获取AppIDServerSecret
  2. 开通"实时音视频"服务
  3. ServerSecret只在服务端使用,不要放在客户端

3.2 引入 SDK

uniapp 的多端特性决定了 SDK 引入方式要按端区分:

# Web 端 npm i zego-express-engine-webrtm # 微信小程序端 npm i zego-express-engine-miniprogram # App 端(原生插件) # 在 HBuilderX 中:manifest.json → App 原生插件配置 → 选择 ZEGO Express 插件

建议封装一个统一的引擎入口,用条件编译分发:

// utils/zego-engine.js // #ifdef H5 import ZegoExpressEngine from 'zego-express-engine-webrtm' // #endif // #ifdef MP-WEIXIN import ZegoExpressEngine from 'zego-express-engine-miniprogram' // #endif // #ifdef APP-PLUS const ZegoExpressEngine = uni.requireNativePlugin('ZegoExpressUniPlugin') // #endif export default ZegoExpressEngine

3.3 权限与基础配置

manifest.json中开启必要权限:

{ "app-plus": { "distribute": { "android": { "permissions": [ "<uses-permission android:name=\"android.permission.CAMERA\"/>", "<uses-permission android:name=\"android.permission.RECORD_AUDIO\"/>", "<uses-permission android:name=\"android.permission.INTERNET\"/>", "<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>" ] }, "ios": { "privacyDescription": { "NSCameraUsageDescription": "用于直播画面采集", "NSMicrophoneUsageDescription": "用于直播声音采集" } } } }, "mp-weixin": { "requiredBackgroundModes": ["audio"], "requiredPrivateInfos": ["getLocation"] } }

小程序后台还要在"服务器域名"中配置 ZEGO 的 wss 与 https 白名单。

3.4 封装 ZEGO Engine 单例

// services/zegoService.js import ZegoExpressEngine from '@/utils/zego-engine.js' class ZegoService { constructor() { this.engine = null this.appID = 1234567890 // 替换为你的 AppID this.server = 'wss://webliveroom-api.zego.im/ws' } async init() { if (this.engine) return this.engine this.engine = new ZegoExpressEngine(this.appID, this.server) this._bindEvents() return this.engine } _bindEvents() { this.engine.on('roomStateUpdate', (roomID, state, errorCode) => { console.log('房间状态:', state, errorCode) }) this.engine.on('roomStreamUpdate', (roomID, updateType, streamList) => { if (updateType === 'ADD') { uni.$emit('stream-add', streamList) } else { uni.$emit('stream-delete', streamList) } }) this.engine.on('publisherStateUpdate', (result) => { console.log('推流状态:', result) }) } async loginRoom(roomID, user, token) { return this.engine.loginRoom(roomID, token, { userID: user.userID, userName: user.userName }) } logoutRoom(roomID) { return this.engine.logoutRoom(roomID) } destroy() { if (this.engine) { this.engine.destroyEngine?.() this.engine = null } } } export default new ZegoService()

3.5 主播端:创建直播间并推流

<!-- pages/anchor/index.vue --> <template> <view class="anchor-page"> <!-- #ifdef H5 || MP-WEIXIN --> <view id="local-preview" class="video-box"></view> <!-- #endif --> <!-- #ifdef APP-PLUS --> <ZegoView class="video-box" :streamID="localStreamID" :viewMode="0" /> <!-- #endif --> <view class="controls"> <button @click="startLive" v-if="!isLiving">开始直播</button> <button @click="stopLive" v-else>结束直播</button> </view> </view> </template> <script setup> import { ref, onUnmounted } from 'vue' import zegoService from '@/services/zegoService.js' import { fetchZegoToken } from '@/api/auth.js' const isLiving = ref(false) const localStreamID = ref('') const roomID = 'live_room_001' const user = { userID: 'anchor_001', userName: '主播A' } async function startLive() { await zegoService.init() // 1. 从服务端获取 Token const token = await fetchZegoToken(user.userID) // 2. 登录房间 await zegoService.loginRoom(roomID, user, token) // 3. 开启本地预览 const streamID = `stream_${user.userID}_${Date.now()}` localStreamID.value = streamID // #ifdef H5 || MP-WEIXIN await zegoService.engine.startPreview('local-preview') // #endif // 4. 推流 await zegoService.engine.startPublishingStream(streamID) isLiving.value = true } async function stopLive() { await zegoService.engine.stopPublishingStream() await zegoService.engine.stopPreview?.() await zegoService.logoutRoom(roomID) isLiving.value = false } onUnmounted(() => { if (isLiving.value) stopLive() }) </script> <style> .video-box { width: 750rpx; height: 1000rpx; background: #000; } </style>

3.6 观众端:进入直播间并拉流

<!-- pages/audience/index.vue --> <template> <view class="audience-page"> <!-- #ifdef H5 || MP-WEIXIN --> <view id="remote-view" class="video-box"></view> <!-- #endif --> <!-- #ifdef APP-PLUS --> <ZegoView class="video-box" :streamID="remoteStreamID" /> <!-- #endif --> <view class="status">{{ statusText }}</view> </view> </template> <script setup> import { ref, onMounted, onUnmounted } from 'vue' import zegoService from '@/services/zegoService.js' import { fetchZegoToken } from '@/api/auth.js' const remoteStreamID = ref('') const statusText = ref('连接中...') const roomID = 'live_room_001' const user = { userID: 'viewer_' + Date.now(), userName: '观众' } onMounted(async () => { await zegoService.init() const token = await fetchZegoToken(user.userID) await zegoService.loginRoom(roomID, user, token) uni.$on('stream-add', onStreamAdd) uni.$on('stream-delete', onStreamDelete) }) async function onStreamAdd(streamList) { const stream = streamList[0] remoteStreamID.value = stream.streamID // #ifdef H5 || MP-WEIXIN await zegoService.engine.startPlayingStream(stream.streamID, 'remote-view') // #endif statusText.value = '直播中' } async function onStreamDelete(streamList) { await zegoService.engine.stopPlayingStream(streamList[0].streamID) statusText.value = '主播已离开' } onUnmounted(() => { uni.$off('stream-add', onStreamAdd) uni.$off('stream-delete', onStreamDelete) zegoService.logoutRoom(roomID) }) </script>

3.7 互动能力扩展思路

  • 连麦:观众调用startPublishingStream,主播订阅stream-add事件拉对方流即可
  • 弹幕 / 礼物:引入 ZIM SDK 做消息通道,直播房间内广播 IM 消息
  • 美颜 / 滤镜:App 端通过 SDK 的美颜模块或第三方插件(FaceUnity、商汤)集成
  • 混流转 CDN:主播侧开启混流任务,观众端通过<video>或 live-player 播放 FLV / HLS 拉流地址,降低大并发成本

3.8 多端差异清单

差异点Web小程序App
视频渲染容器<view id><view id>原生ZegoView组件
权限申请时机浏览器首次推流时打开 Camera 组件时首次初始化时
后台策略Tab 切走自动暂停小程序后台 5 分钟断连需申请后台音频能力
包体积影响约 300KB约 400KB原生插件需云打包

四、常见问题排查

1. 推流黑屏 / 无声

  • 先确认权限是否授予(摄像头、麦克风)
  • 检查startPreview传入的 DOM 节点是否已渲染
  • 小程序端检查是否在真机调试,模拟器不支持音视频采集

2. 小程序提示"不在以下合法域名列表中"

  • 微信后台 → 开发 → 服务器域名 → 加入 ZEGO 提供的 wss / https 域名

3. iOS App 端后台推流中断

  • manifest.json中配置UIBackgroundModes: audio
  • 提示用户回到前台,移动端系统级限制无法完全规避

4. 延迟高、画面卡顿

  • 降低分辨率(从 720p 降到 540p)
  • 打开自适应码率
  • 检查上行带宽,优先保证推流端网络

5. Token 过期导致踢出房间

  • 监听roomTokenWillExpire事件,提前 30 秒从服务端刷新 Token 并调用renewToken

五、性能与上线建议

5.1 码率分辨率推荐

场景推荐值
视频通话分辨率 360 × 640、帧率 15 fps、码率 600 Kbps
直播分辨率 540 x 960、帧率 24 fps、码率 1500 Kbps

5.2 安全与合规

  • Token 必须服务端签发:客户端只拿到短时效 Token,ServerSecret绝不外泄
  • 接入内容审核:开播鉴黄、实时截图审核,避免违规封号
  • 隐私合规:App 首次启动前完成隐私协议弹窗,再初始化 SDK

5.3 上线前 Checklist

  • AppID / Token 区分测试和正式环境
  • 三端真机各跑通一遍开播、观看、退出
  • 弱网场景测试(4G / 模拟 200ms 丢包 5%)
  • 监控告警:推流失败、拉流失败、房间登录失败
  • 配置内容审核和录制留存

六、结语

uniapp 做直播的核心挑战不在"能不能跑起来",而在"多端一致的稳定性"和"弱网下的体验"。选一个成熟的商用 RTC SDK,把复杂的音视频栈交给专业方案,团队就能专注在业务互动玩法上。

本文演示的最小直播链路已经能覆盖 Web、小程序、App 三端。下一步如果要做连麦 PK、直播带货、AI 数字人主播这类高阶玩法,可以在这个骨架上继续扩展。

完整的 API 参数、事件回调、错误码,建议对照 ZEGO 官方文档进行查阅。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询