更新记录
1.0.0(2026-08-30)
平台兼容性
uni-app(5.24)
| Vue2 |
Vue3 |
Chrome |
Safari |
app-vue |
app-nvue |
Android |
iOS |
鸿蒙 |
| - |
√ |
- |
- |
- |
- |
5.0 |
- |
- |
| 微信小程序 |
支付宝小程序 |
抖音小程序 |
百度小程序 |
快手小程序 |
京东小程序 |
鸿蒙元服务 |
QQ小程序 |
飞书小程序 |
小红书小程序 |
快应用-华为 |
快应用-联盟 |
| - |
- |
- |
- |
- |
- |
- |
- |
- |
- |
- |
- |
uni-app x(5.24)
| Chrome |
Safari |
Android |
iOS |
鸿蒙 |
微信小程序 |
| - |
- |
5.0 |
- |
- |
- |
温馨提示 如何调用插件
import {
init,
startScreenStream,
stopScreenStream,
isStreaming
} from "@/uni_modules/yuange-screenrtmp"
开始录屏推流
startScreenStream({
rtmpUrl: 'rtmp://192.168.1.100:1935/live/livestream', // 必填
width: 1280, // 可选,默认 1280
height: 720, // 可选,默认 720
videoBitrate: 2000000, // 可选,视频码率,默认 2Mbps
fps: 30, // 可选,默认 30
iframeInterval: 2, // 可选,I帧间隔秒,默认 2
audioEnabled: true, // 可选,是否采集麦克风,默认 true
audioBitrate: 128000, // 可选,默认 128kbps
audioSampleRate: 44100, // 可选,默认 44100
audioChannels: 1, // 可选,默认单声道
notificationTitle: '屏幕推流', // 可选,通知栏标题
notificationContent: '正在录屏推流' // 可选,通知栏内容
}, {
onCallback(res) {
console.log(JSON.stringify(res));
// 成功: {code:0, msg:'推流已启动', data:{rtmpUrl, width, height, audioEnabled}}
// 失败: {code:-4, msg:'屏幕录制权限被拒绝', data:{}} 等
}
});
停止推流
stopScreenStream({
onCallback(res) {
console.log(JSON.stringify(res));
// {code:0, msg:'推流已停止', data:{}}
}
});
查询推流状态
isStreaming({
onCallback(res) {
console.log(JSON.stringify(res));
// {code:0, msg:'推流中', data:{streaming, connected, durationMs, bytesSent, frameCount, fps}}
}
});
错误码
| code |
说明 |
| 0 |
成功 |
| -1 |
通用失败 |
| -3 |
参数无效(rtmpUrl 缺失/格式错误) |
| -4 |
屏幕录制权限被拒绝 |
| -5 |
录音权限被拒绝 |
| -6 |
RTMP 连接失败 |
| -7 |
编码器创建失败 |
| -8 |
采集启动失败 |
完整Demo示例
<template>
<view class="page">
<view class="title">RTMP 录屏推流(屏幕+麦克风)</view>
<input class="input" v-model="rtmpUrl" placeholder="请输入 rtmp:// 推流地址" />
<button @click="start_" class="button">开始推流</button>
<button @click="stop_" class="button">停止推流</button>
<button @click="query_" class="button">查询状态</button>
<view class="stats">
<text>状态:{{ statusText }}</text>
<text>连接:{{ connectedText }} / 推流中:{{ streamingText }}</text>
<text>时长:{{ durationText }}</text>
<text>已发送:{{ sizeText }}</text>
<text>帧数:{{ frameCountText }} / FPS:{{ fpsText }}</text>
</view>
<view class="log">{{ log }}</view>
</view>
</template>
<script>
import {
startScreenStream,
stopScreenStream,
isStreaming
} from "@/uni_modules/yuange-screenrtmp"
export default {
data() {
return {
rtmpUrl: 'rtmp://192.168.31.12:1935/live/livestream',
log: '',
stats: null,
timer: null
}
},
computed: {
statusText() {
if (!this.stats) return '未查询';
return this.stats.msg;
},
streamingText() {
return (this.stats && this.stats.data && this.stats.data.streaming) ? '是' : '否';
},
connectedText() {
return (this.stats && this.stats.data && this.stats.data.connected) ? '是' : '否';
},
durationText() {
const ms = (this.stats && this.stats.data && this.stats.data.durationMs) || 0;
const s = Math.floor(ms / 1000);
const mm = Math.floor(s / 60);
const ss = s % 60;
return mm + '分' + ss + '秒';
},
sizeText() {
const bytes = (this.stats && this.stats.data && this.stats.data.bytesSent) || 0;
return (bytes / 1024 / 1024).toFixed(2) + ' MB';
},
frameCountText() {
return (this.stats && this.stats.data && this.stats.data.frameCount) || 0;
},
fpsText() {
return (this.stats && this.stats.data && this.stats.data.fps) || 0;
}
},
onUnload() {
this.stopPolling();
},
methods: {
appendLog(msg) {
this.log = msg + '\n' + this.log;
},
start_() {
let that = this;
startScreenStream({
rtmpUrl: that.rtmpUrl,
width: 1280,
height: 720,
videoBitrate: 2000000,
fps: 30,
iframeInterval: 2,
audioEnabled: true,
audioBitrate: 128000,
audioSampleRate: 44100,
audioChannels: 1,
notificationTitle: '屏幕推流',
notificationContent: '正在录屏推流'
}, {
onCallback(res) {
that.appendLog('start: ' + JSON.stringify(res));
if (res.code == 0) {
that.startPolling();
}
}
});
},
stop_() {
let that = this;
stopScreenStream({
onCallback(res) {
that.appendLog('stop: ' + JSON.stringify(res));
that.stopPolling();
}
});
},
query_() {
let that = this;
isStreaming({
onCallback(res) {
that.appendLog('status: ' + JSON.stringify(res));
that.stats = res;
}
});
},
startPolling() {
let that = this;
this.stopPolling();
this.timer = setInterval(() => {
isStreaming({
onCallback(res) {
that.stats = res;
if (!res.data || !res.data.streaming) {
that.stopPolling();
}
}
});
}, 2000);
},
stopPolling() {
if (this.timer) {
clearInterval(this.timer);
this.timer = null;
}
}
}
}
</script>
<style>
.page {
padding: 20rpx;
}
.title {
font-size: 34rpx;
font-weight: bold;
margin-bottom: 20rpx;
}
.input {
border: 1rpx solid #ddd;
border-radius: 8rpx;
padding: 16rpx;
margin-bottom: 20rpx;
font-size: 26rpx;
}
.button {
background-color: dodgerblue;
color: white;
margin-bottom: 16rpx;
}
.stats {
margin-top: 20rpx;
padding: 16rpx;
background-color: #f5f5f5;
border-radius: 8rpx;
display: flex;
flex-direction: column;
}
.log {
margin-top: 20rpx;
padding: 16rpx;
background-color: #2b2b2b;
color: #9cdca9;
font-size: 22rpx;
min-height: 200rpx;
border-radius: 8rpx;
word-break: break-all;
}
</style>