更新记录

1.0.0(2026-07-18)

  • 首次发布。
  • 支持 ONVIF 设备服务地址接入、媒体 Profile 与 RTSP/Snapshot URI 获取。
  • 支持 Android、iOS RTSP 原生预览、暂停、停止和实时流本地录像。
  • 支持 ONVIF Snapshot URI 抓拍并保存到应用沙盒。

平台兼容性

uni-app(3.8.0)

Vue2 Vue3 Chrome Safari app-vue app-nvue app-nvue插件版本 Android Android插件版本 iOS iOS插件版本 鸿蒙
- - - - - 1.0.0 6.0 1.0.0 12 1.0.0 -
微信小程序 支付宝小程序 抖音小程序 百度小程序 快手小程序 京东小程序 鸿蒙元服务 QQ小程序 飞书小程序 小红书小程序 快应用-华为 快应用-联盟
- - - - - - - - - - - -

uni-app x(3.8.0)

Chrome Safari Android Android插件版本 iOS iOS插件版本 鸿蒙 微信小程序
- - 6.0 1.0.0 12 1.0.0 - -

kongbai-onvif

面向 uni-app App nvueuni-app x 的 Android、iOS UTS 标准组件。组件通过 ONVIF Device/Media Service 获取摄像头媒体配置,再使用 VLC 原生 SDK 播放 RTSP、保存抓拍和录制实时流。

支持范围

  • ONVIF 设备服务地址、用户名和密码接入。
  • WS-Security UsernameToken PasswordDigest。
  • HTTP Basic / Digest 鉴权。
  • GetCapabilitiesGetProfilesGetStreamUriGetSnapshotUri
  • RTSP TCP 预览、暂停、继续播放和停止。
  • ONVIF Snapshot URI 抓拍,保存到应用沙盒。
  • 将当前 RTSP 实时流录制到应用沙盒,停止后返回实际文件路径。

当前版本的“录像下载”指实时 RTSP 流本地录像。暂不包含摄像机或 NVR 存储卡中的历史录像检索、时间轴查询、ONVIF Search/Replay 服务和历史文件下载。

平台要求

使用方式 支持情况 最低版本 原生依赖
uni-app App nvue + Android 支持 API 23 org.videolan.android:libvlc-all:3.7.5
uni-app App nvue + iOS 支持 iOS 12.0 MobileVLCKit 3.6.0
uni-app x App + Android 支持 API 23 org.videolan.android:libvlc-all:3.7.5
uni-app x App + iOS 支持 iOS 12.0 MobileVLCKit 3.6.0
H5、各类小程序、HarmonyOS 不支持 - 未提供对应原生实现

VLC 依赖体积较大,标准基座通常不包含这些原生库。请制作包含本插件的自定义调试基座或云打包后真机运行。

安装

在 HBuilderX 的插件市场导入本插件,或将 kongbai-onvif 目录放入项目的 uni_modules 目录。首次安装、升级插件或修改原生依赖后,必须重新制作自定义调试基座或重新云打包,不能使用未包含 VLC 原生库的标准基座。

插件不需要额外安装 npm 依赖。Android 和 iOS 原生依赖已在插件配置中声明,打包时会自动集成。

使用前准备

  1. 摄像头或 NVR 已启用 ONVIF 服务,并创建可登录的 ONVIF 用户。
  2. 设备已启用 RTSP 服务,手机与设备可以通过局域网访问 ONVIF 和 RTSP 端口。
  3. 设备时间与手机时间基本一致。UsernameToken PasswordDigest 对时间敏感,建议启用摄像头 NTP。
  4. 先使用厂商工具确认设备能返回 Media Profile、RTSP 地址和 Snapshot 地址。不同厂商的 ONVIF 实现可能存在差异。

默认使用设备返回的第一个 Media Profile;当前版本不提供多码流或指定 Profile 的选择。

示例入口

当前示例工程已经接入入口:

  • 首页入口:pages/index/index.uvue,点击“ONVIF 摄像头”。
  • 演示页:pages/onvif/demo.uvue
  • 页面路径:/pages/onvif/demo
  • 路由配置:pages.json 中的 pages/onvif/demo

打开演示页后,填写摄像头的 ONVIF 地址、用户名和密码,点击“连接并预览”,再使用抓拍、开始录像和结束录像按钮。录像结束后,组件会通过 record 事件返回实际文件路径。

基础用法

<template>
  <kongbai-onvif
    ref="cameraRef"
    class="camera"
    :autoPlay="true"
    :networkCaching="600"
    @connected="onConnected"
    @snapshot="onSnapshot"
    @record="onRecord"
    @error="onError"
  />
</template>

<script setup lang="uts">
const cameraRef = ref<KongbaiOnvifElement | null>(null)

const connect = () => {
  cameraRef.value?.connect('192.168.1.10', 'admin', 'password')
}

const snapshot = () => {
  cameraRef.value?.snapshot('')
}

const startRecord = () => {
  cameraRef.value?.startRecord('')
}

const stopRecord = () => {
  cameraRef.value?.stopRecord()
}
</script>

<style>
.camera {
  width: 750rpx;
  height: 422rpx;
}
</style>

uni-app nvue 示例

在 nvue 页面中直接使用同名组件,方法和事件保持一致:

<template>
  <view class="page">
    <kongbai-onvif ref="cameraRef" class="camera" :autoPlay="true"
      @connected="onConnected" @snapshot="onSnapshot" @record="onRecord" @error="onError" />
    <button @click="connect">连接摄像头</button>
    <button @click="snapshot">抓拍</button>
    <button @click="startRecord">开始录像</button>
    <button @click="stopRecord">结束录像</button>
  </view>
</template>

<script>
export default {
  methods: {
    connect() { this.$refs.cameraRef.connect('192.168.1.10', 'admin', 'password') },
    snapshot() { this.$refs.cameraRef.snapshot('') },
    startRecord() { this.$refs.cameraRef.startRecord('') },
    stopRecord() { this.$refs.cameraRef.stopRecord() },
    onConnected(event) { console.log('ONVIF connected', event.detail || event) },
    onSnapshot(event) { console.log('snapshot path', event.detail || event) },
    onRecord(event) { console.log('record result', event.detail || event) },
    onError(event) { console.error('ONVIF error', event.detail || event) }
  }
}
</script>

<style>
.page { flex: 1; }
.camera { width: 750rpx; height: 422rpx; }
</style>

uni-app x 示例

uni-app x 使用 script setup 和强类型 ref:

<template>
  <view>
    <kongbai-onvif ref="cameraRef" class="camera" @connected="onConnected" />
    <button @click="connect">连接</button>
    <button @click="cameraRef?.snapshot('')">抓拍</button>
    <button @click="cameraRef?.startRecord('')">开始录像</button>
    <button @click="cameraRef?.stopRecord()">结束录像</button>
  </view>
</template>

<script setup lang="uts">
const cameraRef = ref<KongbaiOnvifElement | null>(null)

const connect = () => {
  cameraRef.value?.connect('192.168.1.10', 'admin', 'password')
}

const onConnected = (event : any) => {
  const detail = event as UTSJSONObject
  console.log('RTSP:', detail['rtspUrl'] as string)
}
</script>

<style>
.camera { width: 750rpx; height: 422rpx; }
</style>

connect 的地址可传:

  • 192.168.1.10
  • 192.168.1.10:80
  • http://192.168.1.10/onvif/device_service
  • https://camera.example.com/onvif/device_service

只需要 RTSP 播放时,可直接设置 rtspUrl,或调用 play(url),无需先执行 ONVIF 连接。

Props

属性 类型 默认值 说明
address String '' ONVIF 设备地址或完整 Device Service URL
username String '' 摄像头用户名
password String '' 摄像头密码
rtspUrl String '' 跳过 ONVIF 时直接播放的 RTSP URL
autoConnect Boolean false 组件加载后自动执行 ONVIF 连接
autoPlay Boolean true ONVIF 连接成功后自动播放 RTSP
networkCaching Number 600 VLC 网络缓存毫秒数

方法

方法 参数 说明
connect address, username, password 连接 ONVIF,读取第一个媒体 Profile
play rtspUrl 播放指定地址;传空字符串时使用已连接设备地址
pause 暂停预览
stop 停止预览
snapshot targetPath 抓拍;传空字符串时自动生成沙盒路径
startRecord directory 开始实时流录像;传空字符串时使用默认沙盒目录
stopRecord 停止录像,最终路径通过 record 事件返回
getState 获取当前地址、Profile、RTSP 与播放状态

connectsnapshot 等网络操作通过事件异步返回结果,不要依赖方法返回值判断完成状态。只播放已有 RTSP 地址时,可以设置 rtspUrl 或直接调用 play(url),不需要先调用 connect

事件

事件 主要字段 说明
connecting address 开始连接设备
connected deviceService, mediaService, profileToken, rtspUrl, snapshotUrl ONVIF 连接成功
playing - RTSP 已开始播放
pause - 播放暂停
stop - 播放停止或结束
buffering percent Android VLC 缓冲进度
snapshot path, url 抓拍文件已写入
record recording, path 录像状态变化;结束时 path 为文件路径
error code, message ONVIF、抓拍、播放或录像失败

事件回调示例:

const onConnected = (event : Map<string, any>) => {
  console.log('RTSP:', event.get('rtspUrl'))
  console.log('Snapshot:', event.get('snapshotUrl'))
}

const onSnapshot = (event : Map<string, any>) => {
  console.log('图片路径:', event.get('path'))
}

const onRecord = (event : Map<string, any>) => {
  if (event.get('recording') == false) {
    console.log('录像路径:', event.get('path'))
  }
}

const onError = (event : Map<string, any>) => {
  console.error(event.get('code'), event.get('message'))
}

常见错误码

错误码 处理建议
empty_addressempty_usernameempty_password 检查连接参数是否为空
onvif_connect_failed 检查设备地址、账号密码、ONVIF 服务和局域网连通性
empty_rtsp_urlrtsp_play_failed 检查 RTSP 地址、设备 RTSP 服务和账号权限
snapshot_unavailablesnapshot_failed 检查设备是否提供 Snapshot URI 及 HTTP 鉴权
not_playingrecord_start_failed 先等待 playing 事件,再开始录像
missing_vlc_dependency 重新制作包含插件的自定义基座或重新云打包

iOS 配置

访问局域网摄像头时,宿主 App 的 Info.plist 需要提供本地网络用途说明:

<key>NSLocalNetworkUsageDescription</key>
<string>用于连接局域网内的 ONVIF 摄像头并预览视频</string>

如果摄像头只提供明文 http:// 抓拍地址,还需要按宿主安全要求配置 ATS。生产环境建议对指定摄像头域名或局域网范围做最小例外,不建议全局关闭 ATS。

文件与权限

  • Android 默认将录像写入应用专属 Movies 目录;iOS 默认写入应用缓存目录下的 kongbai-onvif/records
  • 未传入目标路径时,抓拍默认写入应用缓存目录下的 kongbai-onvif 子目录。
  • 插件不申请系统相册或公共存储权限,也不会自动把图片、录像或摄像头凭据上传到第三方服务。需要展示、分享或上传文件时,请由宿主 App 自行处理。
  • 文件路径是本地沙盒路径,清理缓存或卸载 App 后可能失效;需要长期保存时请复制到宿主 App 自己管理的目录。

常见问题

标准基座启动后黑屏或提示缺少 VLC

这是因为标准基座没有包含 libvlc-allMobileVLCKit。重新制作自定义调试基座,或使用云打包生成包含插件原生依赖的安装包。

ONVIF 连接成功但没有画面

先监听 connected 事件确认 rtspUrl 非空,再监听 playingerror。确认手机能直接访问 RTSP 地址、设备允许当前用户播放,并优先使用 TCP 传输可用的 RTSP 服务。

录像结束后找不到文件

必须监听 record 事件,在 recordingfalse 时读取 path。不要在调用 stopRecord() 后立即假设文件已经写完。

设备认证失败

确认 ONVIF 用户和 RTSP 用户权限,校准设备时间,并确认设备支持 WS-Security UsernameToken PasswordDigest。部分设备只支持特定鉴权组合,需按设备厂商配置启用。

使用注意

  • ONVIF 设备时间与手机时间偏差过大时,UsernameToken Digest 可能被设备拒绝,请先校准摄像头 NTP。
  • 组件默认使用设备返回的第一个 Media Profile。多码流选择和指定 Profile 将在后续版本扩展。
  • 不同厂商对 ONVIF 与 RTSP 的实现存在差异,接入前应确认设备已启用 ONVIF 用户、RTSP 服务及对应网络端口。
  • 录像文件由 VLC 根据输入流容器生成,文件扩展名和编码取决于设备流,不进行二次转码。

版本记录

详见 changelog.md。当前版本为 1.0.0

隐私、权限声明

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

需要网络访问权限;保存抓拍和录像时写入应用沙盒目录,不申请系统相册权限

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

组件仅连接开发者指定的 ONVIF/RTSP 摄像头地址,凭据只在本机用于设备鉴权,不上传到第三方服务

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

无广告内容

暂无用户评论。