更新记录

1.0.18(2026-10-18)

优化插件

1.0.17(2026-07-14)

优化ios

1.0.16(2025-09-16)

优化

查看更多

平台兼容性

uni-app(4.07)

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

uni-app x(4.08)

Chrome Safari Android iOS 鸿蒙 微信小程序
× × √ √ - -

xtf-cameraview 相机组件

Android / iOS 原生相机预览组件,支持拍照、有声录像、暂停和继续录像、切换前后摄像头、持续补光及手势缩放。组件只提供相机画面,拍摄按钮、结果展示和相册保存由页面实现。

示例与接入

项目 完整示例 组件标签 页面脚本
uni-app App nvue examples/camera.nvue xtf-cameraview JavaScript,Options API
uni-app x App uvue examples/camera.uvue xtf-camera UTS,script setup

两份示例均默认打开后置摄像头,包含拍照、切换镜头、开始/停止录像、暂停/继续、查询录像状态、补光灯、启用缩放、关闭相机、预览照片及保存照片/视频到相册。不依赖全局 takePic / startVideo,统一通过组件 ref 操作当前实例。

插件使用原生相机能力,仅面向 Android / iOS App,不支持 Web、小程序或 HarmonyOS。传统 uni-app 请使用 nvue,不要在普通 vue 页面中使用。uvue 使用基于 native-view 的标准组件;兼容模式 xtf-cameraview 不支持 Vapor。标准组件在 Vapor 下的运行效果需单独验收,不能将 VDOM 编译通过视为 Vapor 已验证。

运行完整示例

将插件放在项目的 uni_modules/xtf-cameraview 下,通过 easycom 识别组件。示例页面不需要手动注册组件。

在宿主项目的 pages.json 中添加以下页面项,文件扩展名不写入路由:

{
  "path": "uni_modules/xtf-cameraview/examples/camera",
  "style": {
    "navigationBarTitleText": "相机组件示例"
  }
}

uni-app x 使用该路径下的 camera.uvue;传统 uni-app 使用 camera.nvue。当前 sample 已注册此路由,保留原首页不变。若将 demo 迁入业务页面目录,应相应调整注册路径。

当前 sample 首页也会打开相机,建议使用 uni.redirectTo 替换首页并释放旧页面的相机,避免两个页面同时占用硬件:

uni.redirectTo({ url: '/uni_modules/xtf-cameraview/examples/camera' })

请在 Android / iOS 真机运行并接受权限授权。两份 demo 使用系统默认方向,不额外传入 rotation,避免把 iOS 的竖屏值误用于 Android。

基本用法

uni-app x uvue

<template>
  <xtf-camera ref="camera" device-position="back"
    style="width: 660rpx; height: 660rpx"
    @onCameraLoad="onCameraLoad" @onCameraError="onCameraError"
    @capturePhotoCallback="onPhoto" @recoderVideoCallback="onVideo" />
</template>

<script setup lang="uts">
const camera = ref<XtfCameraComponentPublicInstance | null>(null)

function onCameraLoad() {
  console.log('相机已就绪')
}
function onCameraError(message: string) {
  console.log('相机错误', message)
}
function onPhoto(result: UTSJSONObject) {
  console.log('图片路径', result.getString('pic'))
}
function onVideo(result: UTSJSONObject) {
  console.log('视频路径', result.getString('video'))
}
onUnload(() => { camera.value?.closeCamera() })
</script>

使用 easycom 时,HBuilderX 为组件生成 XtfCameraComponentPublicInstance 类型。就绪后通过 camera.value?.takePicture() 等方法调用;完整操作见 examples/camera.uvue。App 页面需要滚动时,请像完整 demo 一样使用具有确定高度或 flex: 1 的 scroll-view。

uni-app nvue

<template>
  <xtf-cameraview ref="camera" device-position="back"
    style="width: 660rpx; height: 660rpx"
    @onCameraLoad="onCameraLoad" @onCameraError="onCameraError"
    @capturePhotoCallback="onPhoto" @recoderVideoCallback="onVideo" />
</template>

<script>
export default {
  onUnload() {
    if (this.$refs.camera) this.$refs.camera.closeCamera()
  },
  methods: {
    onCameraLoad() { console.log('相机已就绪') },
    onCameraError(event) { console.log('相机错误', event.detail.message) },
    onPhoto(event) { console.log('图片路径', event.detail.pic) },
    onVideo(event) { console.log('视频路径', event.detail.video) }
  }
}
</script>

就绪后通过 this.$refs.camera.takePicture() 等方法操作。不要将 uvue 的直接参数处理方式套到 nvue 上。

属性

属性 类型 默认值 说明
device-position string back back 后置,front 前置;初始化直接选择目标镜头,运行中支持修改该属性切换
rotation number Android 0,iOS 1 平台原生方向值,含义见下表;初始化生效
camera-mode number 0 Android 分辨率宽高比偏好,0 为 16:9,1 为 4:3;不是拍照/录像开关;iOS 当前未使用此值
view-mode number 0 Android 预览缩放与对齐,见下表;iOS 当前未使用此值

数字属性应使用数值绑定,例如 :rotation="0",不要传字符串。除 device-position 外,其余属性没有运行时监听;修改初始化参数需要销毁并重建组件。

方向值

平台 数值 含义
Android 0 Surface.ROTATION_0,自然方向;常见竖屏手机使用此值
Android 1 Surface.ROTATION_90
Android 2 Surface.ROTATION_180
Android 3 Surface.ROTATION_270
iOS 0 landscapeLeft
iOS 1 portrait,默认竖屏
iOS 2 landscapeRight

rotation 不是角度数值,不要传 90 / 180 / 270。Android 的 1 与 iOS 的 1 含义不同;通常省略属性即可。当前组件不会根据设备姿态自动更新该参数。

Android 预览模式

view-mode CameraX 模式 行为
0 FILL_CENTER 居中铺满,可能裁切
1 FIT_CENTER 完整显示并居中,可能留边
2 FILL_START 铺满并起点对齐
3 FIT_START 完整显示并起点对齐
4 FIT_END 完整显示并终点对齐
5 FILL_END 铺满并终点对齐

预览框尺寸由页面样式决定,不等于图片或视频输出分辨率。camera-mode 只是选择偏好,最终支持的尺寸由 CameraX 与设备决定。iOS 当前预览采用自身原生配置,不随上述两个模式参数变化。

实例方法

以下方法在两种组件上均可使用,建议等待 onCameraLoad 后调用。nvue 使用 this.$refs.camera,uvue 使用 camera.value。

方法 参数/返回值 说明
switchCamera(back) boolean true 指定后置,false 指定前置;不是“是否切换”开关,重复指定同一方向不翻转
takePicture() 无 请求拍照,通过 capturePhotoCallback 获取路径
startRecord() 无 请求有声录像,首次使用可能弹出麦克风授权;方法返回不代表已开始录制
pauseResumeRecordering(pause) boolean true 暂停,false 继续;保留现有 API 拼写
stopRecorder() 无 请求结束录像;文件准备好后才触发 recoderVideoCallback
isRecordering() 返回 boolean 查询插件录像状态,暂停中也视为录像;不要把它当成文件已导出的判断依据
setTorchEnable(on) boolean true 打开持续补光灯,false 关闭;不是拍照瞬间闪光
setScaleGestureDetector() 无 启用双指缩放;iOS 同时安装点击对焦手势
closeCamera() 无 关闭并释放相机;不是停止录像并交付文件的方法

补光灯受当前镜头硬件能力限制,前置摄像头通常没有补光灯。demo 在前置镜头下提示切换后置;Android 底层也会检查闪光灯能力,并通过 onCameraError 返回失败。切换镜头前,demo 先调用 setTorchEnable(false),避免灯光状态与新镜头不同步。

Android nvue 兼容组件另有 setCameraZoom(zoom)、getCameraZoom()、setAutoFocus()。这些不是两端统一接口,也未由标准 uvue 组件暴露,通用业务不应依赖它们。

组件关闭后没有重新打开的方法。需要再次预览时,重新进入页面,或通过 v-if 销毁旧实例并新建组件。不要同时打开多个相机示例页面占用同一硬件。

事件

事件 uvue 标准组件参数 nvue 兼容组件参数
onCameraLoad 无业务参数 无业务参数
onCameraError 错误字符串 message event.detail.message
capturePhotoCallback { pic: string } event.detail.pic
recoderVideoCallback { video: string } event.detail.video

recoderVideoCallback 为现有事件名,注意其拼写。uvue demo 使用 UTSJSONObject.getString() 读取 pic / video,nvue demo 使用 event.detail。兼容组件内部以 Map 发送数据,不向页面直接发送错误字符串。

当前没有单独的“录像已开始”“已暂停”“镜头切换已完成”“灯已打开”成功事件。demo 的“已请求”状态只表示已调用方法,不是原生操作成功确认。

录像生命周期

  1. 等待 onCameraLoad,再调用 startRecord();麦克风权限被拒绝时通过 onCameraError 返回,不自动降级为静音录像。
  2. 可调用 pauseResumeRecordering(true/false) 暂停或继续,也可指定镜头切换。请避免快速连续提交相互冲突的操作。
  3. 调用 stopRecorder() 后等待 recoderVideoCallback。完整 demo 在等待导出时禁用相机操作,避免重复停止或提前关闭。
  4. 回调返回路径后再保存、上传或退出页面。Android 输出 .mp4,iOS 输出 .mov;不要自行改扩展名当作格式转换。

Android 使用 CameraX persistent recording;iOS 使用分段录制并合并。录制中切换镜头可能出现短暂画面或声音间断,不保证无黑帧或无缝切换。iOS 合并可能需要额外时间。

closeCamera() 与页面退出是资源清理,不保证交付未完成录像的成功回调。demo 的“关闭相机”按钮会阻止录像/导出中关闭;onUnload 则兜底释放资源,并不能阻止系统返回。如果业务必须保留录像,应在页面离开前自行拦截导航,停止并等待最终回调后再退出。

权限与文件保存

操作 权限及注意事项
预览/拍照 Android 相机权限;iOS NSCameraUsageDescription
有声录像 Android RECORD_AUDIO;iOS NSMicrophoneUsageDescription,在开始录像时申请
保存相册 页面调用系统保存 API;需按宿主平台配置相册用途声明和权限

插件目录包含 Android Manifest 与 iOS 相机、麦克风用途声明,发布前仍需核对宿主最终打包配置。声明用途不等于启动时申请全部权限。

拍摄回调只返回本地文件,不会自动写入系统相册。两份 demo 分别使用 uni.saveImageToPhotosAlbum({ filePath }) 与 uni.saveVideoToPhotosAlbum({ filePath }) 保存,并处理成功/失败反馈。iOS 使用保存功能时应在宿主补齐 NSPhotoLibraryAddUsageDescription 等相册用途配置,具体权限以宿主版本和所用 API 要求为准。

本地缓存文件可能被系统清理;需要长期保留时,请及时保存到相册、持久目录或上传服务端。视频路径展示不等于文件已经永久保存。

旧版全局调用

插件保留从 @/uni_modules/xtf-cameraview 导入的 takePic(callback)、startVideo(callback)。回调参数为文件路径字符串,与组件事件参数不同。这些全局函数作用于最后创建的相机实例,应在相机就绪后使用,不与 demo 中的 ref 事件方式混用。

新代码优先使用实例方法,避免多页面、多实例时控制错误的相机。新旧组件标签不能互相替代。

常见问题

Android 画面旋转了 90 度

检查是否错误地使用 :rotation="1"。Android 默认应为 0,iOS 默认竖屏为 1。自然方向不同的设备需根据实际显示方向配置。

点击补光灯没有亮

先确认当前为后置摄像头,并检查 onCameraError。前置或不带闪光灯的后置镜头无法通过软件开启实体灯。setTorchEnable(true) 表示打开,false 表示关闭,与暂停/继续录像参数无关。

已停止录像却没有文件

请等待 recoderVideoCallback,不要紧接着调用 closeCamera() 或退出页面。导出失败查看 onCameraError;取消授权等待或直接关闭不属于成功录像,不应等待成功文件。

拍照回调取不到路径

确认使用的是正确参数结构:nvue 读取 event.detail.pic,uvue 读取直接参数中的 pic。不要读取未定义的 path 字段。

验证范围

本次示例按 HBuilderX 5.26 编写。当前 sample 是 uni-app x VDOM 项目,已注册的 uvue 示例通过 Android 静态语法检查及热更新编译,生成代码中包含该示例路由。nvue 脚本通过 JavaScript 语法检查,但这不代替传统 uni-app 工程中的原生联编。iOS、nvue 及 Vapor 仍需在对应宿主中真机验收,不能用单独的 Swift/Kotlin 类型检查代替 UTS 联编。

发布前建议覆盖:首次授权和拒绝授权、前置预设、补光灯硬件缺失、拍照保存、录像暂停/继续、录制中切换、结束后等待导出,以及系统返回时的资源释放。

隐私、权限声明

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

<uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.RECORD_AUDIO" /> <!-- 录像需要麦克风权限 --> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

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

无

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

无