更新记录
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 的“已请求”状态只表示已调用方法,不是原生操作成功确认。
录像生命周期
- 等待
onCameraLoad,再调用startRecord();麦克风权限被拒绝时通过onCameraError返回,不自动降级为静音录像。 - 可调用
pauseResumeRecordering(true/false)暂停或继续,也可指定镜头切换。请避免快速连续提交相互冲突的操作。 - 调用
stopRecorder()后等待recoderVideoCallback。完整 demo 在等待导出时禁用相机操作,避免重复停止或提前关闭。 - 回调返回路径后再保存、上传或退出页面。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 联编。
发布前建议覆盖:首次授权和拒绝授权、前置预设、补光灯硬件缺失、拍照保存、录像暂停/继续、录制中切换、结束后等待导出,以及系统返回时的资源释放。

收藏人数:
购买源码授权版(
试用
使用 HBuilderX 导入示例项目
赞赏(0)
下载 13923
赞赏 78
下载 12764424
赞赏 1959
赞赏
京公网安备:11010802035340号