更新记录
1.0.2(2026-07-09)
文档补充
1.0.1(2026-07-09)
首次提交
平台兼容性
uni-app(4.73)
| Vue2 | Vue3 | Chrome | Safari | app-vue | app-nvue | Android | Android插件版本 | iOS | iOS插件版本 | 鸿蒙 |
|---|---|---|---|---|---|---|---|---|---|---|
| - | - | × | × | × | √ | 5.1 | 1.0.2 | √ | 1.0.2 | - |
| 微信小程序 | 支付宝小程序 | 抖音小程序 | 百度小程序 | 快手小程序 | 京东小程序 | 鸿蒙元服务 | QQ小程序 | 飞书小程序 | 小红书小程序 | 快应用-华为 | 快应用-联盟 |
|---|---|---|---|---|---|---|---|---|---|---|---|
| - | - | - | - | - | - | - | - | - | - | - | - |
uni-app x(4.84)
| Chrome | Safari | Android | iOS | 鸿蒙 | 微信小程序 |
|---|---|---|---|---|---|
| - | - | - | - | - | - |
hl-hik-player
海康 iSecure Center 视频播放 UTS 原生插件。基于 HatomPlayer SDK(V2.4.6),在 nvue 页面中以原生组件方式使用。
- 支持平台:Android、iOS(真机;iOS 模拟器不支持)
- 使用方式:组件标签 +
$ref调方法 +@event收事件
插件只负责播放。预览 / 回放 / 对讲的 URL 和 header(如 token)由业务层向平台 OpenAPI 获取后传入。
一、能做什么
| 能力 | 说明 |
|---|---|
| 实时预览 | 传入预览取流 URL,支持主/子/流畅等码流切换 |
| 录像回放 | 传入回放 URL + 起止时间,支持拖动、进度回调、倍速 |
| 抓图 | 截图保存到指定目录,成功后回调路径 |
| 本地录像 | 开始/停止录像,可选转码为 MP4 |
| 声音 | 开启 / 关闭播放声音 |
| 语音对讲 | 与设备双向语音(需麦克风权限) |
| 鱼眼 | 开关、展开模式(180° / 360° 等) |
| 电子放大 | 指定源区域放大到目标区域 |
| 全屏 | 原生全屏进入 / 退出 |
二、接入前必读
1. 必须打自定义基座
本插件是 UTS 原生插件,标准基座加载不了。请用 HBuilderX 制作「自定义调试基座」后再运行。
修改了插件原生代码、Frameworks、Resources 后,需要重新打基座,热更新不够。
2. 页面类型
组件只能用在 nvue 页面,不要放在普通 vue 页面里。
3. 取流地址
- 插件不请求 OpenAPI,不帮你换 token。
src、header、对讲 URL 都由业务传入。- SDK 初始化时 accessToken 传空串(插件内部已处理,全局只初始化一次)。
4. 权限
Android(Manifest 已声明):网络、录音、存储/媒体、WAKE_LOCK。对讲时的 RECORD_AUDIO 需运行时申请。
iOS(Info.plist 已声明):麦克风(对讲)、相册读写(抓图/录像存相册)。纯播放一般不弹权限;对讲/存相册时由系统弹窗。
三、快速上手
1. 模板
<template>
<view>
<hl-hik-player
ref="playerRef"
class="player"
:src="videoUrl"
:autoplay="0"
:play-mode="playMode"
:playback-time="playbackTime"
:header="header"
:player-options="playerOptions"
@event="handleEvent" />
<button @click="onPlay">播放</button>
<button @click="onStop">停止</button>
</view>
</template>
2. 脚本示例
import { ref } from 'vue'
const playerRef = ref(null)
const videoUrl = ref('rtsp://你的预览地址')
const playMode = ref('live') // live | playback
const header = ref({}) // 如 { token: 'xxx' }
const playbackTime = ref({
start: Date.now() - 60 * 60 * 1000,
end: Date.now()
})
const playerOptions = ref({
hardDecode: true,
privateData: false,
qualityType: 1, // 0 主码流,1 子码流(子码流通常首帧更快)
timeout: 10,
// Android 缓冲(毫秒)
// playBuffer: 200,
// iOS 缓冲(字节,建议 >= 64KB;官方常用 5*1024*1024)
bufferLength: 1024 * 1024
})
const getPlayer = () => playerRef.value
const onPlay = () => {
getPlayer()?.playVideo()
}
const onStop = () => {
getPlayer()?.stopVideo()
}
const handleEvent = (payload) => {
// nvue 里真正数据常在 detail 里
const detail = payload?.detail?.dynamicJSONFields
?? payload?.detail
?? payload
?? {}
const event = detail.event || ''
switch (event) {
case 'playStatusChanged':
console.log('状态', detail.state, detail.errorCode)
break
case 'playbackTimeUpdate':
// detail.osdTime / playedTime / totalTime(毫秒)
break
case 'error':
console.log('错误', detail.message, detail.action)
break
case 'debugLog':
// 插件诊断信息(含分步耗时等)
console.log('[插件]', detail.message, detail)
break
default:
if (event) console.log(event, detail)
}
}
3. 样式注意(nvue)
播放器区域需要明确宽高,例如:
.player {
width: 750rpx;
height: 420rpx;
background-color: #000000;
}
四、属性(Props)
| 属性 | 类型 | 默认 | 说明 |
|---|---|---|---|
src |
String | '' |
取流地址(预览或回放 URL) |
autoplay |
Number | 0 |
1 自动播放,0 不自动 |
playMode |
String | 'live' |
live 实时预览;playback 录像回放 |
playbackTime |
Object | {} |
回放时间:{ start: 毫秒时间戳, end: 毫秒时间戳 } |
header |
Object | {} |
取流 header,如 { token: '...' } |
playerOptions |
Object | {} |
播放器配置,见下表 |
playerOptions
| 字段 | 类型 | 默认 | 说明 |
|---|---|---|---|
hardDecode |
Boolean | true |
是否硬解码 |
privateData |
Boolean | false |
是否解析智能信息 / 私有数据(开启会增加开销) |
timeout |
Number | SDK 默认约 20 | 取流超时(秒),主要影响失败反馈速度 |
qualityType |
Number | - | 0 主码流,1 子码流 |
playBuffer |
Number | - | 仅 Android:播放缓冲(毫秒) |
bufferLength |
Number | SDK 默认约 5MB | 仅 iOS:流缓冲区大小(字节)。小于 64KB 会被忽略 |
secretKey |
String | - | 加密码流密钥 |
fetchStreamType |
Number | - | 取流方式(按海康 SDK 文档) |
useSysAEC |
Boolean | - | 系统回声消除(Android) |
writePlayData |
Boolean | - | 写原始码流,调试用(Android) |
openPlayerLog |
Boolean | - | 打开播放器日志(Android) |
注意:playBuffer(毫秒)和 bufferLength(字节)不是一回事,不要把 Android 的毫秒值直接塞给 iOS。
五、方法(通过 ref 调用)
对外方法都有返回值(boolean 或 number),避免 nvue 对无返回值方法派发不稳定。
重要: 播放控制请用 playVideo / stopVideo / pauseVideo / resumeVideo,不要用 play / stop 这类容易和原生或其它 API 冲突的名字。
播放控制
| 方法 | 参数 | 返回 | 说明 |
|---|---|---|---|
playVideo() |
- | boolean | 按当前 playMode 开始播放 |
stopVideo() |
- | boolean | 停止 |
pauseVideo() |
- | boolean | 暂停 |
resumeVideo() |
- | boolean | 恢复 |
switchStream(quality) |
main / sub / low / super |
boolean | 码流切换(多用于预览) |
seekPlayback(timeMillis) |
number | boolean | 回放拖动到指定时间(毫秒) |
setPlaybackSpeed(speed) |
number | boolean | 倍速,约 0.125 ~ 32 |
getPlaybackSpeed() |
- | number | 当前倍速 |
playFile(path) |
string | boolean | 播放本地录像文件 |
抓图 / 录像 / 声音 / 对讲
| 方法 | 参数 | 返回 | 说明 |
|---|---|---|---|
takeSnapshot(path, name) |
目录, 文件名 | boolean | 抓图 |
startRecord(path, convert) |
路径, 是否转码 MP4 | boolean | 开始录像 |
stopRecord() |
- | boolean | 停止录像 |
setSoundEnabled(enabled) |
boolean | boolean | 声音开关 |
startVoiceTalk(url, header) |
对讲 URL, header 或 null | boolean | 开始对讲 |
stopVoiceTalk() |
- | boolean | 停止对讲 |
鱼眼 / 电子放大 / 全屏
| 方法 | 参数 | 返回 | 说明 |
|---|---|---|---|
setFishEyeEnabled(enabled) |
boolean | boolean | 鱼眼开关 |
setFishEyeMode(correctType, placeType) |
number, number | boolean | 展开模式,见下方枚举 |
handleFishEyeCorrect(down, x1, y1, x2, y2) |
boolean + 4 个 number | boolean | 鱼眼手势校正(归一化坐标) |
setOriginalFECParam(cx, cy, rx, ry) |
number×4 | number | 鱼眼 FEC 参数(iOS 不支持,返回 -1) |
openDigitalZoom(srcL, srcT, srcR, srcB, dstL, dstT, dstR, dstB) |
number×8 | boolean | 电子放大 |
closeDigitalZoom() |
- | boolean | 关闭电子放大 |
enterFullscreen() |
- | boolean | 进入全屏 |
exitFullscreen() |
- | boolean | 退出全屏 |
isFullscreen() |
- | boolean | 是否全屏 |
时间 / 帧率 / 解码
| 方法 | 参数 | 返回 | 说明 |
|---|---|---|---|
getPlayedTime() |
- | number | 已播放时长(毫秒) |
getTotalTime() |
- | number | 总时长(毫秒) |
getOSDTime() |
- | number | OSD 时间(毫秒) |
setCurrentFrame(progress) |
0~100 | number | 单帧定位,返回结果码 |
getFrameRate() |
- | number | 当前帧率 |
setDecodeThreadNum(num) |
number | number | 解码线程数,返回结果码 |
setExpectedFrameRate(rate) |
number | number | 期望帧率,返回结果码 |
setPrivateFatio(ratio) |
number | number | 私有画面比例(iOS 不支持,返回 -1) |
鱼眼枚举
correctType:
| 值 | 含义 |
|---|---|
| 0 | PTZ |
| 1 | 180° |
| 2 | 360° |
| 3 | 左右 |
| 4 | 半球 |
| 5 | 圆柱 |
| 6 | 平铺 |
| 7 | 圆柱拼接 |
placeType:
| 值 | 含义 |
|---|---|
| 0 | 无 |
| 1 | 墙面 |
| 2 | 地面 |
| 3 | 顶面 |
调用示例
const p = playerRef.value
if (!p) return
p.playVideo()
p.switchStream('sub')
p.setSoundEnabled(true)
p.takeSnapshot(saveDir, `snap_${Date.now()}.jpg`)
p.startRecord(`${saveDir}record_${Date.now()}.mp4`, true)
p.enterFullscreen()
iOS 上部分「有返回值」的 ref 方法可能拿不到同步返回值(表现为 undefined),但方法本身一般会执行。以 @event 回调为准更稳妥。
六、事件(@event)
统一走一个事件名:@event="handleEvent"。业务字段在 payload 里,关键字段是 event。
nvue 解析建议:
const detail = payload?.detail?.dynamicJSONFields
?? payload?.detail
?? payload
?? {}
const event = detail.event || ''
| event | 主要字段 | 说明 |
|---|---|---|
componentReady |
timestamp | 组件初始化完成 |
sourceSet |
url | 已设置取流地址 |
playStatusChanged |
state, errorCode, firstFrameMs? | 播放状态变化;首次 playing 时可能带首帧耗时 |
playbackTimeUpdate |
osdTime, playedTime, totalTime | 进度(约每秒一次,单位毫秒) |
streamChanged |
quality, ret | 码流切换结果 |
playbackSpeedChanged |
speed, success | 倍速设置结果 |
snapshotTaken |
path | 抓图成功 |
recordingStarted |
path | 录像开始 |
recordingStopped |
code | 录像停止 |
recordTime |
time | 录像时长(秒) |
soundChanged |
enabled, ret | 声音开关结果 |
voiceTalkStatus |
success, errorCode | 对讲状态 |
fishEyeChanged |
enabled / correctType / placeType, ret | 鱼眼变化 |
fullscreenChanged |
fullscreen | 全屏状态变化 |
debugLog |
message, 以及各类耗时字段 | 插件诊断日志 |
error |
action, message, errorCode / code | 错误 |
playStatusChanged.state
| state | 含义 |
|---|---|
idle |
空闲 |
loading |
取流 / 加载中 |
playing |
播放中(通常表示已出画) |
paused |
暂停 |
stopped |
已停止 |
finished |
播放结束 |
failed |
失败,可看 errorCode |
debugLog 常见耗时字段(便于排查首帧慢)
| 字段 | 含义 |
|---|---|
setDataSourceMs |
设置数据源耗时 |
setPlayConfigMs |
设置播放配置耗时 |
setVideoWindowMs |
绑定渲染窗口耗时(iOS) |
startMs |
调用 start 耗时 |
submitTotalMs |
本地提交 SDK 总耗时 |
firstFrameMs |
从 start 提交到 SUCCESS 的耗时(接近「等流 + 解码出画」) |
若 submitTotalMs 很小、firstFrameMs 很大,瓶颈多半在网络 / 平台取流,而不是本地 API 调用。
七、Android 与 iOS 差异
前端方法名一致,内部做了适配。需要知道的差异:
| 项目 | Android | iOS |
|---|---|---|
| 渲染 | TextureView + SurfaceTexture | setVideoWindow(UIView) |
playBuffer |
毫秒缓冲 | 忽略 |
bufferLength |
无此前端映射 | 字节缓冲 |
setOriginalFECParam |
支持 | 不支持,返回 -1 |
setPrivateFatio |
支持 | 不支持,返回 -1 |
handleFishEyeCorrect |
(down, x1, y1, x2, y2) |
近似映射为 SDK 的点/缩放参数 |
setExpectedFrameRate / setDecodeThreadNum |
返回 int | SDK 返回 BOOL,插件转成 0 / -1 |
getPlaybackSpeed |
float | int,对外仍是 number |
| 回放时间字符串 | ISO8601(带时区) | yyyy-MM-dd'T'HH:mm:ss.SSSxxx |
| metallib 资源 | 不需要 | 必须打包,否则首帧可能闪退 |
八、常见问题
1. 黑屏 / 一直 loading
- 确认自定义基座已安装,且是最新打的。
- 确认
src有效;预览/回放 URL 是否过期(openUrl 临时码常有时效)。 - 回放模式是否传了正确的
playbackTime.start/end。 - header 里的 token 是否有效;不要误传干扰鉴权的字段。
2. iOS 播放一会儿闪退
优先检查 App 包内是否有:
com.hri.hpc.mobile.ios.player.metallib
该文件应来自插件目录:
uni_modules/hl-hik-player/utssdk/app-ios/Resources/
缺失时,SDK 在 Metal 渲染初始化阶段会断言崩溃。
3. 事件来了但 detail 是空对象
iOS 侧事件必须用 UTSJSONObject 再 $emit。当前插件已按此实现。若仍为空,多半是旧基座,请重打自定义基座。
解析时请使用:
payload.detail.dynamicJSONFields ?? payload.detail ?? payload
4. Android 加载 so 失败
确认自定义基座,且 ABI 只有 armeabi-v7a、arm64-v8a。
5. 对讲无声
确认已授予录音权限,设备扬声器已开,对讲 URL 正确。
6. 首帧很慢(例如接近 10 秒)
可尝试:
qualityType: 1(子码流)privateData: false- iOS 适当减小
bufferLength(如1 * 1024 * 1024),观察是否花屏/卡顿再回调

收藏人数:
购买普通授权版(
试用
赞赏(0)
下载 276
赞赏 2
下载 12409564
赞赏 1930
赞赏
京公网安备:11010802035340号