更新记录
1.0.0(2026-07-21)
平台兼容性
uni-app x(5.15)
| Chrome |
Safari |
Android |
iOS |
鸿蒙 |
鸿蒙插件版本 |
微信小程序 |
| × |
× |
× |
× |
√ |
1.0.0 |
× |
手机录屏直播推流 UTS 插件(鸿蒙 HarmonyOS Next):
- 支持鸿蒙HarmonyOS Next录屏推流
- 支持rtmp协议
1. 调用方式
import { push, stop, ScreenPushOptions, ScreenPushCallback } from "@/uni_modules/yuange-screenPush"
2. 开始推流
const options: ScreenPushOptions = {
url: "rtmp://192.168.31.10/live/livestream", // RTMP 推流地址(必填)
width: 1280, // 视频宽,默认 1280
height: 720, // 视频高,默认 720
frameRate: 20, // 帧率,默认 20
videoBitrate: 2000000, // 视频码率(bps),默认 2Mbps
micEnabled: true, // 是否采集麦克风,默认 true
innerAudioEnabled: true // 是否采集系统声音(内录),默认 true
}
const callback: ScreenPushCallback = (state: number, msg: string) => {
// state: 0 空闲 / 1 连接中 / 2 推流中 / 3 已停止 / 4 错误
console.log(`[state=${state}] ${msg}`)
}
push(options, callback)
3. 停止推流
stop()
4. 后台长时任务 backgroundModes(切后台持续推流必需)
- uniapp x项目根目录创建:harmony-configs\entry\src\main\module.json5
- 配置 "backgroundModes": ["audioRecording"] 如下:
{
"module": {
"name": "entry",
"type": "entry",
"description": "$string:module_desc",
"mainElement": "EntryAbility",
"deviceTypes": [
"phone"
],
"deliveryWithInstall": true,
"installationFree": false,
"pages": "$profile:main_pages",
"abilities": [
{
"name": "EntryAbility",
"srcEntry": "./ets/entryability/EntryAbility.ets",
"description": "$string:EntryAbility_desc",
"icon": "$media:layered_image",
"label": "$string:EntryAbility_label",
"startWindowIcon": "$media:startIcon",
"startWindowBackground": "$color:start_window_background",
"exported": true,
"backgroundModes": [
"audioRecording"
],
"skills": [
{
"entities": [
"entity.system.home"
],
"actions": [
"ohos.want.action.home"
]
}
]
}
]
}
}
5、完整Demo示例
<template>
<view style="flex:1;background-color:#ffffff;">
<view style="padding:12px;">
<!-- 标题 + 状态 -->
<view style="flex-direction:row;align-items:center;margin-bottom:12px;">
<text style="font-size:20px;font-weight:bold;flex:1;">录屏 RTMP 推流</text>
<text :style="'font-size:16px;color:' + (isPushing ? '#4caf50' : '#999999')">{{statusText}}</text>
</view>
<!-- RTMP 推流地址 -->
<text style="font-size:14px;margin-top:8px;">RTMP 推流地址</text>
<input style="border-width:1px;border-color:#cccccc;border-radius:4px;padding:6px;font-size:14px;margin-top:4px;" type="text" v-model="url" placeholder="rtmp://192.168.31.10/live/livestream" />
<!-- 宽 / 高 / 帧率 -->
<view style="flex-direction:row;margin-top:8px;">
<view style="flex:1;margin-right:8px;">
<text style="font-size:12px;">宽</text>
<input style="border-width:1px;border-color:#cccccc;border-radius:4px;padding:6px;font-size:14px;margin-top:2px;" type="number" v-model="videoWidth" />
</view>
<view style="flex:1;margin-right:8px;">
<text style="font-size:12px;">高</text>
<input style="border-width:1px;border-color:#cccccc;border-radius:4px;padding:6px;font-size:14px;margin-top:2px;" type="number" v-model="videoHeight" />
</view>
<view style="flex:1;">
<text style="font-size:12px;">帧率</text>
<input style="border-width:1px;border-color:#cccccc;border-radius:4px;padding:6px;font-size:14px;margin-top:2px;" type="number" v-model="frameRate" />
</view>
</view>
<!-- 视频码率 -->
<text style="font-size:14px;margin-top:8px;">视频码率(bps)</text>
<input style="border-width:1px;border-color:#cccccc;border-radius:4px;padding:6px;font-size:14px;margin-top:4px;" type="number" v-model="videoBitrate" />
<!-- 音频开关 -->
<view style="flex-direction:row;margin-top:16px;">
<button style="flex:1;margin-right:6px;" :type="micEnabled ? 'primary' : 'default'" @tap="toggleMic">{{ micEnabled ? '麦克风:开' : '麦克风:关' }}</button>
<button style="flex:1;margin-left:6px;" :type="innerAudioEnabled ? 'primary' : 'default'" @tap="toggleInner">{{ innerAudioEnabled ? '内录:开' : '内录:关' }}</button>
</view>
<text style="font-size:11px;color:#999999;margin-top:4px;">提示:内录与麦克风同时开启时优先使用内录;音频固定 48kHz/2ch/96kbps</text>
<!-- 启停按钮 -->
<view style="flex-direction:row;margin-top:16px;">
<button style="flex:1;margin-right:6px;" type="primary" :disabled="isPushing" @tap="onStart">{{ isPushing ? '推流中...' : '开始推流' }}</button>
<button style="flex:1;margin-left:6px;" type="warn" :disabled="!isPushing" @tap="onStop">停止</button>
</view>
<!-- 日志 -->
<text style="font-size:14px;margin-top:16px;">日志</text>
<text style="font-size:11px;color:#666666;margin-top:4px;">{{logText}}</text>
</view>
</view>
</template>
<script lang="uts">
import { push, stop, ScreenPushOptions, ScreenPushCallback } from "@/uni_modules/yuange-screenPush";
export default {
data() {
return {
url: "rtmp://192.168.1.128/live/livestream",
videoWidth: "1280",
videoHeight: "720",
frameRate: "20",
videoBitrate: "2000000",
micEnabled: true,
innerAudioEnabled: true,
isPushing: false,
statusText: "空闲",
logText: ""
}
},
methods: {
stateText(s: number): string {
if (s === 0) return "空闲";
if (s === 1) return "连接中";
if (s === 2) return "推流中";
if (s === 3) return "已停止";
if (s === 4) return "错误";
return String(s);
},
log(msg: string): void {
const line: string = `[${new Date().toLocaleTimeString()}] ${msg}\n`;
this.logText = (this.logText + line).slice(-4096);
},
toggleMic(): void {
this.micEnabled = !this.micEnabled;
},
toggleInner(): void {
this.innerAudioEnabled = !this.innerAudioEnabled;
},
onStart(): void {
if (this.isPushing) {
return;
}
if (this.url == null || this.url.trim().length === 0) {
this.log("请填写 RTMP 推流地址");
return;
}
this.statusText = "连接中";
this.isPushing = true;
this.log("开始推流 -> " + this.url);
// 严格对齐参考工程 Index.ets:RTMP 直推,音频 48kHz/2ch/96kbps
const options: ScreenPushOptions = {
url: this.url.trim(),
width: Number(this.videoWidth) || 1280,
height: Number(this.videoHeight) || 720,
frameRate: Number(this.frameRate) || 20,
videoBitrate: Number(this.videoBitrate) || 2000000,
audioSampleRate: 48000,
audioChannels: 2,
audioBitrate: 96000,
micEnabled: this.micEnabled,
innerAudioEnabled: this.innerAudioEnabled
};
const callback: ScreenPushCallback = (state: number, msg: string): void => {
this.statusText = this.stateText(state);
this.log(`[${this.stateText(state)}] ${msg}`);
if (state === 2) {
this.isPushing = true;
} else if (state === 3 || state === 4) {
this.isPushing = false;
}
};
push(options, callback);
},
onStop(): void {
this.log("停止推流");
stop();
this.isPushing = false;
this.statusText = "已停止";
}
}
}
</script>