更新记录

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>

隐私、权限声明

1. 本插件需要申请的系统权限列表:

ohos.permission.CUSTOM_SCREEN_CAPTURE, ohos.permission.MICROPHONE, ohos.permission.INTERNET, ohos.permission.KEEP_BACKGROUND_RUNNING

2. 本插件采集的数据、发送的服务器地址、以及数据用途说明:

插件不采集任何数据

3. 本插件是否包含广告,如包含需详细说明广告表达方式、展示频率:

暂无用户评论。