更新记录
2.1.8(2026-10-15)
- 修复 Android 内嵌相机设置固定
9:16且使用fit时,照片为 9:16、预览仍完整显示 4:3 的问题;按真实照片裁剪区域调整可见预览,保留客户原属性与拍照调用。普通 uni-app nvue 和 uni-app x 标准组件共用修复,需重新制作匹配的 Android 自定义基座或执行原生联编。 - 修复 iOS 前后摄切换时预览镜像配置晚于画面切换,出现短暂二次翻转的问题;切换期间遮挡过渡画面,在预览配置完成后恢复显示。
- 修复 iOS 前摄预览与输出镜像不同时,
bottomLeft等预设水印锚点换边的问题;预设锚点固定在可见预览对应位置,保留custom输出坐标映射及拖动定位。 - 更新示例诊断版本,补充固定水印、独立镜像开关和拍照失败收尾说明。iOS 原生修复需重新制作匹配源码的自定义基座或重新打包 App;本版 Android 预览修复也需更新对应原生基座。
2.1.7(2026-10-15)
- 修复 iOS 按预览区域拍照时,将原始输出坐标与方向归正后的照片直接比较,导致
PHOTO_PREVIEW_SOURCE_ASPECT_UNVERIFIED的问题;使用真实照片 EXIF 同步转换裁剪区域,覆盖横竖方向及镜像。 - 保留无效几何和真实源比例失配的失败保护,并补充原始输出尺寸、照片尺寸与方向诊断;默认 output、固定 9:16、录像及原有照片回调保持。
- 明确页面必须处理 capture 阶段的拍照失败并结束等待,避免忽略 9081004 后再次提示超时。iOS 原生修复需重新制作匹配源码的自定义基座或重新打包 App;本项不需要重打 Android 基座。
2.1.6(2026-10-14)
- 修复普通 uni-app 沿用 nvue 兼容组件时,页面设置
photo-crop-mode="preview"、拍照结果却仍为output的参数丢失问题;补齐 Android / iOS 组件属性、会话配置及单拍裁剪模式转发,Android 同步补齐 nvue 属性别名。 - 缺省仍使用
output;单拍显式传入photoCropMode只影响本次照片,省略时继承组件配置。保留既有拍照回调、权限、录像、变焦和水印调用。 - 正式随包提供
compat/uniapp-nvue下的修复入口和升级说明。沿用旧 nvue 的项目升级后需替换已有 Android / iOSindex.vue;uni-app x VDOM/Vapor 继续使用标准.uvue组件。 - 更新 nvue 原生兼容入口后,需重新制作并安装匹配的 Android / iOS 自定义基座或重新打包 App;仅热更新页面不能更新该原生组件。
平台兼容性
uni-app(4.84)
| Vue2 | Vue3 | Chrome | Safari | app-vue | app-nvue | Android | iOS | 鸿蒙 |
|---|---|---|---|---|---|---|---|---|
| √ | √ | × | × | √ | √ | 6.0 | √ | √ |
| 微信小程序 | 支付宝小程序 | 抖音小程序 | 百度小程序 | 快手小程序 | 京东小程序 | 鸿蒙元服务 | QQ小程序 | 飞书小程序 | 小红书小程序 | 快应用-华为 | 快应用-联盟 |
|---|---|---|---|---|---|---|---|---|---|---|---|
| × | × | × | × | × | × | × | × | × | × | × | × |
uni-app x(4.84)
| Chrome | Safari | Android | iOS | 鸿蒙 | 微信小程序 |
|---|---|---|---|---|---|
| × | × | 6.0 | √ | √ | × |
其他
| 多语言 | 暗黑模式 | 宽屏模式 | 蒸汽模式 |
|---|---|---|---|
| × | × | × | √ |
lizhao-camera-pro
lizhao-camera-pro 是面向 uni-app / uni-app x App 的原生自定义相机插件,提供全屏拍摄与 uni-app x 页面内预览,覆盖拍照、录像、水印、统一上传和媒体删除。
适合工单留档、现场巡检、工程记录和业务附件采集。首次接入先完成一次拍照,再按需要添加水印、录像或自定义界面。
需要使用 W / 超广角?查看 广角使用指南,按设备回调选择镜头或倍率,并了解示例接入、常见问题和日志采集方法。
文档在项目中的位置:uni_modules/lizhao-camera-pro/wide-angle-guide.md。导入插件后,可在 HBuilderX 项目管理器中按此路径打开。
这个插件能解决什么问题
- 在 uni-app x 表单、工单、巡检页或自定义弹层中嵌入任意尺寸的原生相机预览,兼容 VDOM 与 Vapor。
- 使用插件提供的全屏界面快速完成拍照或录像,不必先搭建相机页面。
- 拍照、快速拍照、录像、暂停恢复,并在设备支持时于录像中切换前后镜头。
- 将多个录像片段合并为一个最终视频,业务侧只接收一个结果文件。
- 把时间、录像时长、项目、人员等业务字段及本地图片或 PNG/JPEG Base64 图片烧录到照片或视频。
- 给业务自行选择的本地图片添加水印;在 Android / iOS 的 uni-app x 自定义相机页面中拖动水印位置。
- 将媒体保存到缓存、应用文件目录、系统相册或项目已获授权的自定义位置。
- 对比请求配置和设备真实生效配置,明确处理镜头、画质、帧率等能力差异。
- 只删除插件能够确认归属的媒体,降低误删项目文件的风险。
下载与导入
- 在插件市场选择“使用 HBuilderX 导入插件”,导入自己的 uni-app 或 uni-app x 项目。
- 确认项目中存在完整的
uni_modules/lizhao-camera-pro目录,不要修改插件目录名,也不要只复制内部源码目录。 - 根 API 只从插件根目录导入;uni-app x 标准组件使用 easycom 标签,无需导入平台内部文件。
完整示例位于插件的 uni_modules/lizhao-camera-pro/example/ 目录下,按项目类型选择对应子目录:
- uni-app:
uni_modules/lizhao-camera-pro/example/uniapp/,示例首页见index.vue,全屏拍摄见fullscreen.vue,图片水印见image-watermark.vue。 - uni-app x:
uni_modules/lizhao-camera-pro/example/uniappx/,示例首页与根 API 调用见index.uvue,页面内预览见camera.uvue,图片水印见image-watermark.uvue。
示例首页按「内置界面 / 经典界面 / 自定义界面」分成三个 tab。内置界面展示完整产品相机,经典界面展示简洁拍摄工具栏;自定义界面在 uni-app x 中进入组件示例,并提供图片水印入口。普通 uni-app 的自定义 tab 展示图片水印能力与 uni-app x 组件示例位置。常用配置直接显示,更多参数与运行记录可按需展开,切换 tab 保留已填写的配置和拍摄结果。
导入后,在 HBuilderX 项目管理器中展开上述目录查看源码。本文的示例路径均相对于项目根目录;需要运行时,按下文“完整示例”说明复制页面并配置页面路由。
uni-app 导入
// 普通 uni-app 页面只从插件根目录导入需要的 API。
import {
openCamera,
getCameraCapabilities,
deleteCameraMedia,
addImageWatermark
} from '@/uni_modules/lizhao-camera-pro'
uni-app 使用根 API;新增 addImageWatermark 支持 Android / iOS。页面内嵌原生预览只在 uni-app x 标准组件中提供。
uni-app x 导入
// <script setup lang="uts"> 中使用同一个插件根目录。
import {
openCamera,
getCameraCapabilities,
deleteCameraMedia,
addImageWatermark
} from '@/uni_modules/lizhao-camera-pro'
标准组件可直接在 .uvue 模板中使用 <lizhao-camera-pro />;VDOM 与 Vapor 使用相同标签和公开 API。强类型实例写法见 uni_modules/lizhao-camera-pro/example/uniappx/camera.uvue。
参数表中的类型名称用于说明对象包含哪些字段。需要声明变量或回调参数时,导入方式见下方对应 API 的示例;普通 uni-app 的 JavaScript 页面只需导入 API,无需写 import type 或类型注解。
Android 最低支持 Android 6.0(API 23)。云打包前,请在项目 manifest.json 的以下位置设置 minSdkVersion 为数字 23;如果已有值更高,请保留较高值。
| 项目类型 | manifest.json 配置位置 |
最低值 |
|---|---|---|
| uni-app | app-plus.distribute.android.minSdkVersion |
23 |
| uni-app x(HBuilderX 4.71 及以上) | app-android.distribute.minSdkVersion |
23 |
修改该配置后,请重新云打包自定义基座或正式 App。设置 targetSdkVersion 或升级 HBuilderX 不能代替这项配置,请勿使用 tools:overrideLibrary 跳过最低系统版本检查。
插件包含原生代码;首次导入或更新原生能力后,请重新制作并安装对应平台的自定义基座或正式包。
快速开始:完成第一次拍照
先用默认全屏界面完成一次拍照,确认权限、原生包和结果回调都已接通:
import { openCamera } from '@/uni_modules/lizhao-camera-pro'
openCamera({
mode: 'photo',
success(result) {
// uploadFilePath 可直接传给 uni.uploadFile.filePath。
console.log('拍照成功', result.uploadFilePath)
},
fail(error) {
console.log('拍照失败', error.errCode, error.stage)
}
})
能够打开相机、完成拍摄,并在 success 中取得非空 uploadFilePath,就说明最小接入已经完成。path、uri 等兼容字段继续用于预览、删除和相册资产识别。
先选择接入方式
| 你的需求 | 推荐方式 | 适合的界面 | 建议起点 |
|---|---|---|---|
| 直接交付完整的水印拍摄界面 | openCamera({ uiPreset: 'product' }) |
产品化全屏界面,内置模板、倒计时和常用控制 | 查看全屏 API |
| 保留简洁拍摄界面 | openCamera() |
经典全屏界面 | 从快速开始扩展 |
| 在自己的页面中显示相机并自定义按钮 | uni-app x <lizhao-camera-pro> |
VDOM / Vapor 的表单、工单、巡检、自定义弹层 | 从模块一开始 |
| 打开前判断镜头、分辨率或录像能力 | getCameraCapabilities() |
按设备能力动态显示设置 | 查看模块七 |
| 删除插件返回的照片或视频 | deleteCameraMedia() 或组件 deleteMedia() |
撤销拍摄、附件清理 | 查看模块九 |
如果希望打开即用,选择产品模式;如果只需要简洁工具栏,使用默认经典模式;如果需要自己的布局、连续操作和完整事件,请在 uni-app x 中使用标准组件。
统一上传照片或视频
照片和视频成功结果都保证返回非空 uploadFilePath。把它直接传给 uni.uploadFile 的 filePath 即可,不要再优先取 watermarkedUri,也不要自行判断应取 path 还是 uri。
import { openCamera } from '@/uni_modules/lizhao-camera-pro'
openCamera({
mode: 'mixed',
success(result) {
// 示例地址仅为占位,请替换为自己的上传接口。
uni.uploadFile({
url: 'https://example.com/upload',
filePath: result.uploadFilePath,
name: 'file',
formData: {
mediaType: result.mediaType,
watermarkApplied: String(result.watermarkApplied)
},
success(uploadResult) {
console.log('上传完成', uploadResult.statusCode, uploadResult.data)
},
fail(error) {
console.log('上传失败', error.errMsg)
}
})
},
fail(error) {
console.log('拍摄失败', error.errCode, error.stage)
},
complete(result) {
console.log('拍摄流程结束', result)
}
})
uploadFilePath 始终指向本次照片或视频的最终成片:watermarkApplied=true 时是已经实际烧录水印的成片;未实际烧录水印时是最终无水印成片。即使 keepOriginal=true 同时保留了原片,上传字段仍指向最终交付项,原片继续从 originalPath / originalUri 读取。
Android 的 cache / files 目标分别使用应用专属外部缓存/文件目录中的 lizhao-camera-pro 子目录,兼容普通 uni-app 的预览和上传。这里仍属于当前应用的存储空间,卸载应用时清除;cache 文件还可能被系统清理,需要长期保留时使用 files 或及时上传。目录不可用时走失败回调。uploadFilePath 是本地文件地址,服务器访问地址需要由上传接口返回。
Android 10+ 相册以及返回 content:// 的已授权文档树输出,uri 保留原来的标识,uploadFilePath 提供应用专属外部缓存中的成片副本。Android 9 及以下相册仍使用可读文件路径。普通 uni-app 与 uni-app x 都应使用 uploadFilePath 上传,并在成功回调后及时处理,避免缓存被系统清理。
iOS 的 cache / files 成片使用当前应用运行期文档目录中的插件专属子目录,兼容普通 uni-app 页面读取;路径由运行环境解析,不需要配置 App ID。缓存和相册上传副本不参与系统备份,长期保留请选择 files 或及时上传。此路径修复包含 iOS 原生代码,更新后需要重新制作并安装 iOS 自定义基座或重新打包 IPA;Android 不需要因此重打基座。
iOS 保存到 Photos 时,uri 仍是 ph:// 相册资产标识;插件会另外为 uploadFilePath 提供可上传的临时副本。该副本由插件管理,最长保留 24 小时,应在成功回调后及时上传,不能保存到数据库后长期复用。
旧字段的用途如下:
| 字段 | 建议用途 |
|---|---|
uploadFilePath |
照片和视频统一上传入口,直接传给 uni.uploadFile.filePath。 |
path |
当前平台可访问的本地地址,适合预览、删除及兼容旧代码;不再作为跨平台上传字段。 |
uri |
媒体库、相册或文件 URI,适合资产识别和删除;iOS ph:// 不能直接当作上传文件路径。 |
originalPath / originalUri |
keepOriginal=true 且产生双输出时的无水印原片。 |
watermarkedPath / watermarkedUri |
实际生成的水印输出;没有独立水印输出时允许为空,不应作为统一上传字段。 |
先改这几个常用参数
以下路径均以 openCamera(options) 的 options 为起点。界面参数放在顶层或 productOptions,拍摄与保存参数放在 config,不要混用层级。
| 想调整什么 | 配置位置 | 常用取值与说明 |
|---|---|---|
| 只拍照或同时支持录像 | mode |
photo 只拍照;mixed 可切换拍照与录像 |
| 选择拍摄界面 | uiPreset |
product 为内置产品界面;省略为 classic |
| 前后镜头 | cameraPosition |
back / front;ultraWide 需设备开放该镜头 |
| 横竖拍方向 | config.orientation |
默认 auto,按拍照或开始录像时的持机方向确定 |
| 成片保存位置 | config.outputOptions.target |
cache / files / album / custom,详见模块五 |
| 水印文字和图片 | config.watermarkOptions |
启用 enabled,配置 items 和成片写入开关,详见模块四 |
| 产品界面初始模板 | productOptions.initialTemplateId |
从内置模板表选择 ID;保留内置模板时不传 templates |
| 快门倒计时 | productOptions.countdownSeconds |
0 / 3 / 5 / 10 秒;0 为关闭 |
| 构图网格 | grid / gridColor |
off / 3x3 / 4x4 / phi;颜色默认 #80FFFFFF,只显示在预览中 |
| 拍摄振动 | vibrateOnCapture / vibrateDurationMs |
默认关闭;请求时长范围 0~5000 毫秒,关闭反馈请设置 vibrateOnCapture: false |
| 硬件快门 | hardwareShutterEnabled |
默认关闭;iOS 需要 17.2 及以上,其他平台以系统是否转交按键为准 |
| 地点文字 | productOptions.location |
项目提供 title,可补 subtitle,不会自动定位 |
| 附近地点搜索 | productOptions.locationService |
Android 可选高德服务,默认不启用 |
示例代码怎么使用
本文根 API 示例可用于 uni-app 与 uni-app x。标准组件示例只用于 uni-app x,并使用 <script setup lang="uts"> 与 CameraComponentBridge 强类型 ref。
组件方法应在 ready 后由按钮触发;本文省略重复界面的片段会注明所需事件。业务上传请选用方法成功回调或媒体事件中的一个入口,避免同一张照片上传两次。
按业务模块使用
模块一:在 uni-app x 页面嵌入原生相机
适合需要保留业务表单、提示文字和自定义按钮的页面。组件收到 ready 后,原生相机会话才真正可以拍摄。
<template>
<view class="camera-box">
<!-- 原生预览必须有明确尺寸;收到 ready 后再允许点击拍照。 -->
<lizhao-camera-pro
ref="camera"
class="camera"
style="width: 100%; height: 900rpx;"
mode="mixed"
camera-position="back"
:auto-start="true"
@ready="onReady"
@orientationchange="onOrientationChange"
@photo="onPhoto"
@recordfinished="onRecordFinished"
@error="onError"
/>
<text @click="takePhoto">拍照</text>
</view>
</template>
<script setup lang="uts">
import { onUnmounted, ref } from 'vue'
import type {
CameraCapabilities,
CameraChangeEvent,
CameraComponentBridge,
CameraDeleteMediaResult,
CameraErrorEvent,
CameraFail,
CameraFinalizeProgressEvent,
CameraMediaResult,
CameraOrientationChangeEvent,
CameraPhotoEvent,
CameraReadyEvent,
CameraReadyResult,
CameraRecordPauseEvent,
CameraRecordProgressEvent,
CameraRecordResumeEvent,
CameraRecordingStartResult,
CameraStateChangeEvent,
CameraRecordFinishedEvent
} from '@/uni_modules/lizhao-camera-pro'
const camera = ref<CameraComponentBridge | null>(null)
const ready = ref<boolean>(false)
function takePhoto(): void {
if (!ready.value) return
camera.value?.takePhoto({
success: (result: CameraMediaResult): void => {
// uploadFilePath 是照片和视频统一的非空上传入口。
console.log('照片已生成', result.uploadFilePath)
}
})
}
function onReady(event: CameraReadyEvent): void {
ready.value = true
console.log('相机已就绪', event.appliedConfig)
}
function onOrientationChange(event: CameraOrientationChangeEvent): void {
console.log('设备方向', event.orientation, event.rotation, event.reliable)
}
function onPhoto(event: CameraPhotoEvent): void {
console.log('照片事件', event.result.uploadFilePath)
}
function onRecordFinished(event: CameraRecordFinishedEvent): void {
console.log('最终视频', event.result.uploadFilePath)
}
function onError(event: CameraErrorEvent): void {
console.log('相机错误', event.error.errCode, event.error.stage)
}
onUnmounted((): void => { camera.value?.destroyCamera() })
</script>
完整的 47 属性、18 方法和 16 事件示例见 uni_modules/lizhao-camera-pro/example/uniappx/camera.uvue,其中新增 watermarkDraggable 和 watermarkchange。VDOM 与 Vapor 使用完全相同的代码,不要按渲染模式复制第二套插件。
按需打开、临时关闭和重新打开预览
相机只在用户点击按钮后使用时,将组件设为 :auto-start="false",保留 ref="camera"。下面两个方法分别绑定页面的“打开预览”和“关闭预览”按钮:
function openPreview(): void {
camera.value?.open({
// open 的配置使用 position;组件属性使用 camera-position。
config: { position: 'back' },
success: (result: CameraReadyResult): void => {
console.log('预览已打开', result.state, result.capabilities)
},
fail: (error: CameraFail): void => {
console.log('预览打开失败', error.errCode, error.stage)
}
})
}
function closePreview(): void { camera.value?.close() }
如果正在录像且要保留视频,请先调用 stopRecording(),等待 recordfinished 后再关闭预览;close() 不能代替停止录像和保存。页面卸载时仍按模块一调用 destroyCamera()。
让预览水印跟随设备方向
orientationchange 返回真实持机方向,不受页面锁定竖屏影响。页面预览层可以直接使用 rotation 旋转水印;插件写入照片或视频的水印仍会按最终成片方向自动归正,不要把该角度重复写入烧录配置。
// 将模块一中的同名事件处理函数替换为下面的写法。
const previewWatermarkRotation = ref<number>(0)
const previewWatermarkStyle = ref<string>('transform:rotate(0deg);')
function onOrientationChange(event: CameraOrientationChangeEvent): void {
// 只旋转页面叠加层,不把此角度再次写进成片水印配置。
previewWatermarkRotation.value = event.rotation
previewWatermarkStyle.value = 'transform:rotate(' + event.rotation.toString() + 'deg);'
}
如果首次事件的 reliable 为 false,表示传感器还没有给出有效读数,插件先使用当前显示方向提供可用初值;传感器恢复后会再次发送可靠事件。事件只在方向或可靠性变化时触发。
模块二:拍照、录像并取得最终媒体结果
拍照完成后可以直接从 takePhoto.success 或 photo 事件取得照片。录像分为“已经开始”和“最终文件已生成”两个阶段,不要把它们混在一起。下例沿用模块一的 ref="camera",并绑定 @recordfinished="onRecordFinished"。
function takePhoto(): void {
camera.value?.takePhoto({
success: (result: CameraMediaResult): void => {
console.log('照片', result.uploadFilePath)
},
fail: (error: CameraFail): void => {
console.log('拍照失败', error.errCode, error.stage)
}
})
}
function startRecording(): void {
camera.value?.startRecording({
success: (started: CameraRecordingStartResult): void => {
// 这里只表示原生录像已经开始,还没有最终视频文件。
console.log('录像已开始', started.recordingId)
},
fail: (error: CameraFail): void => {
console.log('录像启动失败', error.errCode, error.stage)
}
})
}
function stopRecording(): void {
// 这里只发出停止请求;合并、加水印和保存完成后才触发 recordfinished。
camera.value?.stopRecording()
}
function onRecordFinished(event: CameraRecordFinishedEvent): void {
// 最终视频只能从 recordfinished.result 读取。
console.log('最终视频', event.result.uploadFilePath)
}
使用全屏 openCamera() 时,用户完成拍照或录像后的最终媒体统一从 openCamera.success 返回。
固定 9:16 照片与按预览区域裁剪(2.1.4)
2.1.6 随包提供修复后的普通 nvue 兼容入口及升级说明。沿用旧 nvue 的项目升级插件后,还需将 compat/uniapp-nvue/utssdk 下的两个 index.vue 替换到项目同名 utssdk 位置,再重新制作匹配基座;保留原 photo-crop-mode="preview" 调用即可。此步骤修复页面设置 preview、实际结果却为 output 的字段丢失。uni-app x VDOM/Vapor 继续使用标准 .uvue 组件。
photoCropMode 默认 output,沿用原输出设置。需要固定竖版照片时,在组件属性或 openCamera.config 中设置 aspectRatio: '9:16';插件会在照片方向归正后裁成宽高比 9:16,不拉伸画面。录像仍由独立的视频配置决定;Android 内嵌 fit 预览的联动见下方 2.1.8 说明。
Android 2.1.8:内嵌组件设置 aspectRatio="9:16"、scale-type="fit"、photo-crop-mode="output"(或省略裁剪模式)时,预览会按固定照片裁剪区域等比显示,不再完整显示 4:3 原始预览流。普通 uni-app nvue 和 uni-app x 标准组件共用该原生实现;保留原组件调用即可,升级后需重新制作匹配的 Android 自定义基座或执行原生联编。该调整不改变 preview 模式、fill / centerCrop、其他照片比例及录像设置。固定 9:16 与长屏比例不同时,仍可能保留上下黑边。
Android 2.1.5 修复旧比例的重复裁剪:在 output 模式下,未填写 photoResolution 时,4:3 / 16:9 随照片横竖方向输出,1:1 输出方图。例如原照片为 3024×4032 时,4:3 保留这一尺寸。旧比例同时填写 photoResolution 时,仍优先使用指定尺寸并沿用原方向适配规则;最终尺寸请读取照片结果,不用预览宽高估算。固定竖版请选 9:16,希望取景范围随预览变化请选 preview。
需要成片范围跟随取景框时,设置 photoCropMode: 'preview'。插件在快门时冻结原生预览实际可见区域,再映射到照片像素进行裁剪;此模式优先于 aspectRatio。长屏取景框可能输出 9:20 等比例,最终宽高以照片结果中的 width / height 和 appliedConfig.photoResolution 为准。
// 固定竖版 9:16,适合统一上传尺寸的表单。
openCamera({ mode: 'photo', uiPreset: 'classic', config: {
aspectRatio: '9:16', photoCropMode: 'output'
} })
<!-- uni-app x:按钮区域放在组件外,组件的实际布局就是取景区域。 -->
<lizhao-camera-pro ref="camera" style="width: 100%; height: 600px;"
mode="photo" scale-type="centerCrop" photo-crop-mode="preview" />
单次 takePhoto({ photoCropMode: 'preview' }) 可覆盖本次拍照;不传则继承会话配置,不改变下一张的默认值。takePhoto() 不接受 aspectRatio 或 fallbackPolicy,这两项应设置在组件属性或会话配置中。
监听 error 事件时,event.error.stage == 'capture' 表示本次拍照失败,应解除页面忙碌状态并取消本次等待计时器;不能直接忽略所有 9081004。拍照失败不会触发 photo 成功事件。
| 功能 | Android | iOS | HarmonyOS |
|---|---|---|---|
| 固定 9:16 照片 | 支持 | 支持 | 支持 |
| 按原生预览区域裁剪照片 | 支持;需有效传感器映射 | 支持;需有效预览/照片坐标映射 | 暂不支持,拍照返回 9081003 |
HarmonyOS 当前 CameraKit 接口不能提供可验证的预览到照片取景映射,因此不会用预览框宽高猜测裁剪区域,也不会将 preview 静默降级为完整照片;可使用 output 和固定 9:16。
fill / centerCrop填满取景框时会裁掉边缘;fit保留预览画面,可能留黑边,黑边不会写入照片。固定 9:16 无法铺满所有手机的不同屏幕比例。- 页面自行绘制的 Logo、二维码和文字位置仍由页面布局控制;写死的
top/bottom不会随原生取景画幅自动重排。 - 页面
cover-view、水印遮罩或黑色菜单不会自动缩小原生取景框。自定义布局应把不属于取景区的按钮放在相机组件外;本选项不截取页面截图。 - 新裁剪模式先裁剪再缩小,不放大图片。指定
photoResolution时,nearest在目标宽高中保留裁剪比例,strict要求精确尺寸可达,否则失败;宽高应按最终照片方向填写。 - 方向、切镜、缩放或布局尚未稳定时,按预览拍照可能返回可重试错误,请等待预览就绪再拍。水印在裁剪后绘制,
keepOriginal保留相同取景的未加水印成片。 - 更新涉及原生代码,Android/iOS 需重新制作匹配的自定义基座或正式包。当前主包的内嵌组件仍用于 uni-app x;沿用旧 nvue 组件的项目请按随包兼容入口说明替换原生组件文件,不能只给旧页面新增参数。
快速拍照与限时录像调用
captureMode 是单次 takePhoto() 的参数:quality 优先画质,fast 请求优先拍摄速度。它不是组件属性,也不是连拍开关;是否更快取决于设备和后续水印、保存操作。
下面的方法沿用模块一的 ref="camera"、photo / recordfinished / error 事件,分别绑定两个按钮;另外绑定 @recordprogress="onRecordProgress" 显示录制进度。
function takeFastPhoto(): void {
// 相机 ready 后才允许点击拍照。
camera.value?.takePhoto({ captureMode: 'fast' })
}
function recordShortVideo(): void {
// 不要在上一次录像处理完成前再次开始。
camera.value?.startRecording({
maxDurationMs: 15000, // 最多录制 15 秒;0 表示由业务手动停止。
recordAudio: true, // 需要麦克风声音;静音录像设为 false。
success: (started: CameraRecordingStartResult): void => {
console.log('录像已开始', started.recordingId)
console.log('实际音频配置', started.appliedConfig.recordAudio)
},
fail: (error: CameraFail): void => {
console.log('录像启动失败', error.errCode, error.stage)
}
})
}
function onRecordProgress(event: CameraRecordProgressEvent): void {
// durationMs 不计暂停时间;segmentCount 用于观察暂停、恢复或切镜形成的片段。
console.log('已录毫秒数 / 上限', event.durationMs, event.maxDurationMs)
console.log('片段数量', event.segmentCount)
}
达到最大时长会自动结束录制并进入最终处理,业务仍从 recordfinished.result 接收视频,不要在进度达到上限时重复停止或直接上传。
recordAudio=false 用于不需要现场声音的录像;它与拍照、录像提示音开关无关。echoCancellation 请求减少回声,noiseSuppression 请求减少背景噪声,autoGainControl 请求自动调整收音音量。这三项不能保证设备一定启用,应结合对应的 *Supported 能力和 started.appliedConfig 判断;不能确认时按 fallbackPolicy 降级或失败。
模块三:暂停、恢复录像并在录像中切换镜头
适合巡检中途暂停讲解、前后摄交替记录等场景。每个操作都应由独立按钮触发,并等待对应事件后再开放下一步按钮。给相机组件绑定 @recordpause="onRecordPause"、@recordresume="onRecordResume" 和 @camerachange="onCameraChange"。
// 每个方法分别绑定一个按钮,并等待对应事件后再开放下一步操作。
function pauseRecording(): void { camera.value?.pauseRecording() }
function resumeRecording(): void { camera.value?.resumeRecording() }
function switchToFront(): void { camera.value?.switchCamera('front') }
function stopRecording(): void { camera.value?.stopRecording() }
function onRecordPause(_event: CameraRecordPauseEvent): void {
console.log('录像已暂停,可以恢复或停止')
}
function onRecordResume(_event: CameraRecordResumeEvent): void {
console.log('录像已恢复')
}
function onCameraChange(event: CameraChangeEvent): void {
console.log('镜头已切换', event.position)
}
暂停时间不计入逻辑录像时长。切镜时插件会结束当前临时片段、切换输入并继续下一片段,停止后再合并为一个最终视频。使用前先查看 pauseResumeSupported 和 switchCameraWhileRecordingSupported;设备不支持时应隐藏对应按钮。
模块四:添加时间、业务字段和图片水印
水印可以显示时间、录像时长、项目、工单、人员等业务字段,也可以使用应用可读取的本地图片或动态生成的 PNG/JPEG Base64。
Android、iOS 在录像模式下同时开启水印预览和视频写入时,会完整展示视频画面,让边缘水印也能在录制前和录制中看到。预览容器与视频比例不同时,画面外可能留出空白;该区域不会写入成片。竖拍、横拍按开始录像时的方向输出,水印以视频画面为定位范围。
function takeWatermarkedPhoto(): void {
// 业务字段由项目提供,插件不会主动读取定位或人员信息。
camera.value?.takePhoto({
watermarkOptions: {
enabled: true, // 水印总开关;仅设置 items 不会自动启用。
fields: {
project: '项目 A',
operator: '张三',
orderNo: 'GD-001'
},
// 时间占位符写 {timestamp},格式在这里配置,不写 {timestampFormat}。
timestampFormat: 'yyyy-MM-dd HH:mm:ss',
items: [{
id: 'business',
type: 'text',
// 字符串中的 \n 是换行;不要写成 /n、<br> 或双重转义的 \\n。
text: '项目:{project}\n工单:{orderNo}\n人员:{operator}\n时间:{timestamp}\n录像时长:{recordingDuration}',
lineSpacing: 8,
anchor: 'bottomLeft',
color: '#FFFFFFFF',
backgroundColor: '#66000000',
padding: 10
}],
previewVisible: true,
burnIntoPhoto: true,
burnIntoVideo: true
},
success: (result: CameraMediaResult): void => {
console.log('水印照片', result.uploadFilePath)
},
fail: (error: CameraFail): void => {
console.log('水印拍照失败', error.errCode, error.stage)
}
})
}
previewVisible 只控制屏幕预览;是否写入成片由 burnIntoPhoto 和 burnIntoVideo 决定。enabled 必须为 true。图片水印的 imagePath 可传应用能够读取的本地路径,或 PNG/JPEG Base64 字符串。
文字换行使用 \n,lineSpacing 控制行间距。业务占位符与 fields 的键名必须一致,例如 {cusname} 对应 fields.cusname,{address} 对应 fields.address;户主、经纬度、方向和地址需要由项目提供,插件不会自动采集。{timestamp} 是内置拍摄时间,timestampFormat 是它的格式配置;只有自己在 fields 中定义了 timestampFormat 时,{timestampFormat} 才是有效的业务占位符。
修改后续拍摄使用的水印
applyWatermark(options) 用于更新当前相机会话的水印,例如切换工单或修改拍摄人员。它不会重写已经生成的照片、视频。下面方法绑定页面按钮,在 ready 后、未拍摄或处理成片时调用:
Android / iOS 标准组件也可以直接更新绑定的 watermarkOptions。单独修改水印内容、字段、位置或显示开关会刷新水印并保留当前相机预览;保持组件的 key、sessionId 和挂载状态不变。若同时切换镜头或修改相机采集配置,仍会重新配置相机。
anchor 是水印项的动态定位属性,可以直接在下一次配置中切换到 topLeft、topRight、bottomLeft、bottomRight 或 center;需要任意位置时使用 custom 并传入归一化 x/y。customOrigin 决定 custom 坐标对应整个水印外框的 center、topLeft、topRight、bottomLeft 或 bottomRight,默认是 center。内容尺寸变化时,选定的基准点仍保持不变;固定贴边优先使用预设锚点。iOS 中预设锚点不会随前摄预览镜像换边,例如 bottomLeft 始终位于可见预览的左下角。
function updateWatermark(): void {
camera.value?.applyWatermark({
enabled: true, // 传 false 可以关闭后续水印。
fields: { orderNo: 'GD-002' },
items: [{
id: 'order', type: 'text', anchor: 'bottomLeft',
text: '工单:{orderNo}\n拍摄时间:{timestamp}'
}],
previewVisible: true,
burnIntoPhoto: true,
burnIntoVideo: true
})
}
如果业务需要让 custom 的坐标直接表示左上角,可显式指定基准点;右上、左下和右下同理:
const item = {
id: 'badge', type: 'text', anchor: 'custom', customOrigin: 'topLeft',
x: 0.04, y: 0.08, text: '固定左上角'
}
更新时传入希望保留的完整水印配置,不要假设只传一个字段会自动合并旧的 items。配置失败从组件 error 接收,实际写入情况仍查看媒体结果的 watermarkApplied。
给相册已有图片加水印
Android / iOS 可从插件根目录调用 addImageWatermark(),普通 uni-app 和 uni-app x 均可使用。业务自行选图和设计界面;此方法不打开相机、不展示 product 编辑器,也不需要相机权限。下面是普通 uni-app 页面脚本中的调用:
import { addImageWatermark } from '@/uni_modules/lizhao-camera-pro'
function chooseAndWatermarkPhoto() {
uni.chooseImage({
count: 1,
sourceType: ['album'],
success: (selection) => {
// 选择器成功回调中传入仍然可读的本地图片地址。
addImageWatermark({
imagePath: selection.tempFilePaths[0],
watermarkOptions: {
enabled: true,
items: [{
id: 'order', type: 'text', anchor: 'bottomLeft',
text: '工单:GD-002\n{timestamp}', fontSize: 32,
color: '#FFFFFFFF', backgroundColor: '#80000000'
}]
},
outputOptions: { target: 'cache', conflictPolicy: 'rename' },
photoQuality: 0.92,
success: (result) => {
// 预览和上传使用可读的本地副本;它不是服务器 URL。
uni.previewImage({ urls: [result.uploadFilePath] })
console.log('新图片', result.uploadFilePath, result.width, result.height)
},
fail: (error) => console.log('图片处理失败', error.errCode, error.nativeMessage),
complete: () => console.log('本次图片处理结束')
})
}
})
}
完整页面分别位于 uni_modules/lizhao-camera-pro/example/uniapp/image-watermark.vue 和 uni_modules/lizhao-camera-pro/example/uniappx/image-watermark.uvue 的“给相册照片加水印”区域。uni-app x 使用同一 API 和 CameraImageWatermarkResult / CameraFail 强类型回调。
输入图片只读,每次输出新 JPEG;不会覆盖原图。超大图片按比例缩至最长边不超过 4096、总像素不超过 1200 万,并归正 EXIF 方向,实际尺寸以结果为准。{timestamp} 使用本次处理开始时间,不读取原图拍摄时间。水印 enabled 默认为 false,请显式开启;关闭 enabled 或 burnIntoPhoto 时仍输出归正后的新 JPEG,但不烧录水印。
如果水印配置来自本插件相机,且包含重叠或组合布局,处理网络图、其他设备照片等不同尺寸的图片时,请把相机结果中的 appliedConfig.photoResolution 作为 referenceCanvas 一起传入。插件会在外部图片中央建立同等比例的虚拟参考框,统一缩放组合中的位置、尺寸和文字;外部图片仍保留完整像素,不会被裁剪。省略 referenceCanvas 会继续按外部图片整张画布定位,保持旧调用语义。
const cameraCanvas = lastPhotoResult.appliedConfig.photoResolution
addImageWatermark({
imagePath: downloadedLocalImagePath,
referenceCanvas: cameraCanvas,
watermarkOptions: savedWatermarkOptions
})
默认 target: 'cache' 不写系统相册。需要保存相册时显式使用 target: 'album' 并处理相册权限;Android 6~9 需宿主事先取得写相册授权。iOS 若 Photos 已成功保存、后续上传副本或交付失败,错误会提示相册可能已有图片,插件不会静默删除该相册资产。cache 和相册上传临时副本应及时使用;跨启动长期保存请选择 files 或业务自己的持久化流程。
不同宽高比外部图片的组合水印
当一套水印来自相机配置,且包含两项或多项重叠、上下拼接或组合内容时,处理网络图、其他设备照片、横图、竖图或方图都应使用同一个参考画布。否则外部图片会被当作新的整图坐标系,组合水印可能出现内容挤压、块间距变化或贴边裁切。
referenceCanvas 不一定要等到拍照后才能取得:
- uni-app x 标准组件在 ready 事件中返回当前
appliedConfig.photoResolution。固定9:16和photoCropMode: 'preview'的最终尺寸需要结合原片或快门时的真实映射确定,准备阶段可能是{width:0,height:0},此时不要作为参考画布;请保存拍照成功后的实际尺寸。 - 全屏 openCamera 没有拍照前的 ready 回调。若业务已经确定相机设计画布,可以使用同一组明确的 photoResolution;若要求和设备最终实际输出完全一致,应在第一次拍照成功后保存 appliedConfig.photoResolution,后续处理外部图片时复用。
- getCameraCapabilities() 可以查询设备支持的 photoResolutions,但它是能力清单;最终生效尺寸仍以 ready 事件或拍摄结果中的 appliedConfig 为准。
标准组件在拍照前取得参考画布:
import { CameraReadyEvent, CameraSize } from '@/uni_modules/lizhao-camera-pro'
let cameraCanvas: CameraSize | null = null
function onCameraReady(event: CameraReadyEvent): void {
// 相机会话已经运行,但还没有拍照。
// 保存真实生效的输出画布,后面给外部图片加同款组合水印。
cameraCanvas = event.appliedConfig.photoResolution
}
fontSize、padding 和 lineSpacing 使用短边 1080 设计单位;x、y、width、height 是参考画布中的归一化坐标。contentHeight / 1080 只能用于把 1080 设计单位换算成参考画布尺寸,不能直接作为 y 偏移;也不要把目标图片已经测出的像素高度再除以 1080,否则会被重复缩放。
下面的例子把标题块和信息块放在同一次调用中。动态高度在参考画布中计算,目标图片的宽高不会参与排版:
import { addImageWatermark } from '@/uni_modules/lizhao-camera-pro'
// cameraCanvas 可以来自上面的 ready 事件,
// 也可以来自之前保存的 result.appliedConfig.photoResolution。
function addWatermarkToExternalImage(imagePath, cameraCanvas) {
if (!cameraCanvas ||
cameraCanvas.width <= 0 ||
cameraCanvas.height <= 0) {
console.error('缺少有效的相机参考画布')
return
}
// 1080 设计单位按参考画布短边换算,不使用外部图片的尺寸。
const shortSide = Math.min(cameraCanvas.width, cameraCanvas.height)
const designPx = (value) => value * shortSide / 1080
const widthRatio = (value) => designPx(value) / cameraCanvas.width
const heightRatio = (value) => designPx(value) / cameraCanvas.height
const title = '测试项目看看换行加长加长\n长加长加长加长加长'
const info = '时间:2026-10-13 10:06:26\n施工人:爱琳\n地点:等待定位\n经度:110.4425°E\n纬度:21.2601°N'
// 这里的高度是参考画布中的设计单位,不是当前外部图片的像素高度。
const titleContentHeight = title.split('\n').length * 44
const infoContentHeight = info.split('\n').length * 36
const titlePadding = 18
const infoPadding = 18
const gap = 24
const bottomMargin = 48
// bottomLeft 的 y 是整个水印外框的底部。
const infoBottomY = 1 - heightRatio(bottomMargin)
const infoBoxHeight = heightRatio(infoContentHeight + infoPadding * 2)
const titleBottomY = infoBottomY - infoBoxHeight - heightRatio(gap)
addImageWatermark({
imagePath,
referenceCanvas: cameraCanvas,
watermarkOptions: {
enabled: true,
burnIntoPhoto: true,
items: [
{
id: 'title',
type: 'text',
text: title,
anchor: 'custom',
customOrigin: 'bottomLeft',
x: widthRatio(48),
y: titleBottomY,
width: widthRatio(760),
height: heightRatio(titleContentHeight),
fontSize: 32,
lineSpacing: 4,
padding: titlePadding,
color: '#FFFFFFFF',
backgroundColor: '#CC2F5ED8'
},
{
id: 'info',
type: 'text',
text: info,
anchor: 'custom',
customOrigin: 'bottomLeft',
x: widthRatio(48),
y: infoBottomY,
width: widthRatio(760),
height: heightRatio(infoContentHeight),
fontSize: 26,
lineSpacing: 4,
padding: infoPadding,
color: '#FF222222',
backgroundColor: '#E6FFFFFF'
}
]
},
outputOptions: { target: 'cache' },
success: (result) => {
console.log('水印完成', result.uploadFilePath)
},
fail: (error) => {
console.error('水印失败', error.errCode, error.nativeMessage)
}
})
}
如果组合项是图片,把对应项的 type 改为 image 并填写 imagePath;它仍然必须使用同一套 widthRatio、heightRatio、x 和 y。若两张图片已经在业务侧合成为一张 PNG/JPEG,则只传一个图片水印项,不要再用另一套目标图片坐标叠加。
在自定义相机页面拖动水印
Android / iOS 的 uni-app x 标准组件可开启 watermarkDraggable,默认关闭。拖动结束、原生配置提交成功后才触发 watermarkchange;此时后续拍摄使用新位置。业务可保存事件中的完整 watermarkOptions,用于重开页面或编辑同一组水印:
<template>
<lizhao-camera-pro
style="width: 100%; height: 420px;"
:watermark-options="watermarks"
:watermark-draggable="true"
@watermarkchange="onWatermarkMoved"
/>
</template>
<script setup lang="uts">
import { CameraWatermarkOptions, CameraWatermarkChangeEvent } from '@/uni_modules/lizhao-camera-pro'
// 单项拖动无需 dragGroup;同一非空组名的多个水印整体移动。
const watermarks = ref<CameraWatermarkOptions>({
enabled: true,
items: [{ id: 'order', type: 'text', text: '工单:GD-002', anchor: 'bottomLeft' }]
})
function onWatermarkMoved(event: CameraWatermarkChangeEvent): void {
watermarks.value = event.watermarkOptions
console.log('水印位置已确认', event.changedItemIds)
}
</script>
拖动水印后,返回配置统一使用 anchor: 'custom'、customOrigin: 'center',x/y 是归一化外框中心坐标;请保存事件中的完整配置,不要再套用拖动前的角点基准。仍使用固定 anchor 时,手动填写 x/y 不会替代锚点布局。多项卡片可给相关 items 设置相同的 dragGroup,保留项间位置一起移动,不同组可分别拖动。
需要业务卡片可拖、品牌 Logo 固定时,给水印项设置 draggable。单项 draggable 省略时按允许拖动处理,只有明确设置为 false 才锁定;但全局 watermarkDraggable 默认是 false,因此要真正允许手势拖动仍须显式开启全局开关。同一非空 dragGroup 中任一项为 false,整组禁止拖动;未分组的项单独控制:
import { ref } from 'vue'
import { CameraWatermarkOptions, CameraWatermarkItem } from '@/uni_modules/lizhao-camera-pro'
const watermarks = ref<CameraWatermarkOptions>({
enabled: true,
items: [
{ id: 'title', type: 'text', text: '设备巡检', dragGroup: 'business',
draggable: true, anchor: 'custom', x: 0.25, y: 0.72 },
{ id: 'time', type: 'text', text: '{timestamp}', dragGroup: 'business',
draggable: true, anchor: 'custom', x: 0.25, y: 0.80 },
{ id: 'logo', type: 'image', imagePath: '/static/logo.png', dragGroup: 'brand',
draggable: false, anchor: 'topRight', width: 0.15 }
]
})
// 使用当前配置切换整组开关,保留内容和已确认坐标。
function setBusinessDraggable(allowed: boolean): void {
watermarks.value.items?.forEach((item: CameraWatermarkItem) => {
if (item.dragGroup == 'business') item.draggable = allowed
})
}
上述例子需导入 ref、CameraWatermarkOptions 和 CameraWatermarkItem,Logo 路径使用业务自己的本地或资源图片。锁定只限制手势,程序仍可修改位置。只切换属性中的开关会保留已确认坐标;通过 applyWatermark() 更新时,继续使用最新事件配置,或显式选择第二参数 false 自动保位。
同一页面只修改文字、fields 或样式时,Android / iOS 标准组件的属性更新会保留已提交的拖动位置。applyWatermark(options) 继续按传入的完整配置更新,包括位置;保存 watermarkchange 返回的配置后再改内容,即可沿用拖动位置,传回初始配置则恢复初始位置。不要在编辑内容时意外清空或重置自己保存的 draggedOptions。
如需组件在方法调用时自动保位,可显式调用 camera.value?.applyWatermark(options, false):保持该项 id、type、dragGroup 和原位置声明不变时保留已提交位置;明确修改 anchor、customOrigin、x/y 时使用新位置。第二参数省略或传 true 均按传入位置更新。每次仍需传入完整水印配置,删除重加或切换会话不继承旧位置;根 API 和内置相机的更新方式不变。
仅在可交互的空闲预览中拖动可见水印;拍照、录像、成片处理或位置提交期间不开始新的拖动。失败、取消、方向或布局变化会取消未提交移动,错误从原有 error 事件返回。空白处点击对焦及双指缩放沿用原配置;业务遮罩或按钮覆盖取景区时,会影响原生区域接收手势。完整开关与事件示例在 uni_modules/lizhao-camera-pro/example/uniappx/camera.uvue。
普通 uni-app 项目仍通过 openCamera 使用全屏相机;本次没有新增普通 uni-app 的内嵌组件。HarmonyOS 本次不提供通用原生水印拖动;原有内置 product 交互按各平台说明使用。
添加图片水印
type 支持 text 和 image,两种水印可以放在同一个 items 数组中。下面的方法接收通过 uni.chooseImage 选择或下载后获得的本地图片路径,再拍摄一张同时带文字和图片水印的照片。
// localImagePath 传入选图结果 tempFilePaths[0]。
// 网络图片须先下载成功,再传入本地路径,不能直接传 https 地址。
function takeImageWatermarkedPhoto(localImagePath: string): void {
if (localImagePath.length == 0) return
camera.value?.takePhoto({
watermarkOptions: {
enabled: true, // 必须启用,items 中的水印才会生效。
items: [
{
id: 'time', // 每个水印项使用不同的 id。
type: 'text',
text: '拍摄时间:{timestamp}',
anchor: 'bottomLeft'
},
{
id: 'logo',
type: 'image', // 图片水印使用 imagePath,不使用 text。
imagePath: localImagePath, // 应用可读取的本地图片路径。
anchor: 'topRight', // 图片放右上角,与左下角文字错开。
width: 0.2 // 占输出画布宽度的 20%,不是 0.2 像素。
}
],
previewVisible: true, // 控制预览显示,不代替成片写入开关。
burnIntoPhoto: true, // 将水印实际写入本次照片。
burnIntoVideo: true // 同一配置用于录像时,将水印写入视频。
},
success: (result: CameraMediaResult): void => {
// 使用实际返回的水印状态与成片位置确认结果。
console.log('图片水印照片', result.watermarkApplied, result.uploadFilePath)
},
fail: (error: CameraFail): void => {
console.error('图片水印拍照失败', error.errCode, error.stage)
}
})
}
完整的“选择图片 → 调整位置、大小和透明度 → 打开全屏相机 → 查看结果”页面见 uni-app 图片水印示例(uni_modules/lizhao-camera-pro/example/uniapp/image-watermark.vue)和 uni-app x 图片水印示例(uni_modules/lizhao-camera-pro/example/uniappx/image-watermark.uvue)。两份示例实际传入户主、时间、经纬度、方向和地址的多行文字;业务值为演示数据。移除图片后仍保留多行业务文字水印,设置在下一次打开相机时生效。选择得到的临时路径应在本次使用期间保持可读;需要下次启动继续使用时,请先保存为持久文件。
示例会提示实际被跳过的水印项,请检查对应参数及图片是否可读。uni-app x 标准组件示例显示合并、添加水印和保存各阶段的进度;当前阶段达到 100% 不等于整个流程完成,应等待最终媒体结果。
完整示例的使用顺序
图片水印示例按“拍一张照片 → 填写业务内容 → 选择 Logo → 调整效果 → 查看结果”组织。先使用默认值,再修改字段;Base64、横竖拍和不可读图片等专项操作可在页面中按需展开。成片以实际照片为准,返回字段不能代替查看排版效果。
Logo 路径怎么传,为什么会被跳过?
使用本地图片时,imagePath 要传原生可以读取的图片地址。@/static/qr.png 是项目资源写法,不能直接当作原生文件路径;<image> 可以显示,也不代表水印一定能读取。不要仅把 @/static/qr.png 改成 /static/qr.png 就当作已完成转换。
| 图片来源 | 传给 imagePath 的值 |
|---|---|
| 相册选择 | uni.chooseImage 成功回调的 result.tempFilePaths[0],完整示例已演示 |
| 动态 Base64 | PNG/JPEG 的 data:image/png;base64,...、data:image/jpeg;base64,... 或纯标准 Base64 字符串,直接传入,不需要先存文件 |
| 网络下载 | uni.downloadFile 成功且 HTTP 状态正常后的 result.tempFilePath,不能直接传网络 URL |
| 项目 static 图片 | 需要转换成当前平台原生可读取的地址,并确认资源确实存在;不能直接传 @/static/... |
下面是 uni-app App 专用的静态资源转换片段,放在 plus 已可用的页面方法中;uni-app x 不使用 plus.io:
// 项目文件为 static/qr.png,_www 表示当前应用的资源目录。
const logoPath = plus.io.convertLocalFileSystemURL('_www/static/qr.png')
// 确认该地址的图片实际可被原生读取后,再作为水印使用。
// 转换只改变地址格式;部分打包资源仍位于 APK assets 中,并非普通文件。
const logoItem = {
id: 'logo',
type: 'image',
imagePath: logoPath,
anchor: 'topLeft',
width: 0.1 // 只指定宽度,保留原始比例,避免 Logo 或二维码拉伸。
}
// 将 logoItem 加入 watermarkOptions.items;仍需 enabled: true。
如果转换后仍被跳过,先用完整示例的相册选图验证。fallbackPolicy: 'nearest' 会跳过不合法或不可读取的水印,并在 appliedConfig.skippedWatermarkItemIds 返回对应 id;logo 被跳过不代表不支持 type: 'image'。请检查实际路径、文件是否存在、图片格式及其他水印参数,而不是只看转换后的字符串。
动态生成的 Base64 怎么传?
Android、iOS 和 Harmony 的图片水印沿用 type: 'image' 与 imagePath。将生成结果的字符串直接放到 imagePath,不要传整个接口响应对象:
// generatedBase64 是接口或画布已经生成的 PNG/JPEG Base64 字符串。
// 带 data:image/png;base64, / data:image/jpeg;base64, 前缀和纯字符串都支持。
const logoItem = {
id: 'logo',
type: 'image',
imagePath: generatedBase64, // 直接传入,由插件解码;无需写临时文件。
anchor: 'topRight',
width: 0.2 // 只设宽度,图片保持原始比例。
}
// 将 logoItem 放入 watermarkOptions.items,并启用 enabled、burnIntoPhoto。
蓝色标题栏、表格、换行地址和多种字号等复杂版式,可以先由项目画布或服务端合成为一张 PNG/JPEG,再作为一个图片水印传入。完整示例内置了可直接拍摄的工程信息牌,并保留原图 static/project-card-watermark.png 便于查看:
// projectCardBase64 是已经合成好的整张工程信息牌 Data URL。
// 横拍参考效果使用 0.34;竖拍想接近示例比例时可使用 0.40。
const projectCardItem = {
id: 'project-card',
type: 'image',
imagePath: projectCardBase64, // 直接传 Base64,不需要先写入临时文件。
anchor: 'bottomLeft',
width: 0.34,
opacity: 1
}
// 复杂版式只放这一项,避免再叠加独立文字造成内容重合。
如果需要核对插件实际绘制的文字,可以使用同一组业务内容再拍一张纯文字水印。下面只传 text,没有 imagePath,因此成片中的文字不是信息牌图片的一部分:
// \n 是真实换行;{timestamp} 由插件在拍摄时替换。
const projectText = '工程名称:示例设备维护工程\n'
+ '施工内容:分体空调深度清洗\n'
+ '拍摄时间:{timestamp}\n'
+ '拍摄地点:广东省广州市白云区示例街道\n'
+ ' 示例东路 97 号示例大厦\n'
+ '备注:例行维护完成\n'
+ '拍摄人:张三\n'
+ '工单号:WO-2026-001'
// 将此对象加入 watermarkOptions.items;文字内容在拍摄时替换占位符。
const projectTextItem = {
id: 'project-text',
type: 'text',
text: projectText,
anchor: 'bottomLeft',
lineSpacing: 8,
fontSize: 30, // 竖图可改为 26,给长地址留出更多宽度。
fontFamily: 'monospace', // system / sansSerif / serif / monospace。
fontWeight: 'bold', // normal / bold。
color: '#FFFFFFFF',
backgroundColor: '#B0000000',
padding: 16
}
整张信息牌适合蓝色标题栏、表格和多字号版式;纯文字适合内容需由插件在拍摄时替换、搜索或逐字段核对的场景。完整示例同时提供两者的横拍和竖拍入口。
支持标准 Base64,允许空格、换行、制表符及省略末尾 =。单张编码原文最多 12 MiB、解码后最多 8 MiB;图片实际格式必须是 PNG/JPEG,并与 Data URL 中声明的格式一致。不支持 SVG、URL-safe Base64 或直接传网络 URL。无效、损坏或超限图片按 fallbackPolicy 处理:nearest 跳过该项并返回其 id,strict 返回失败。完整示例提供可直接粘贴和拍摄的 Base64 入口。
横着拍照或录像时,成片和水印怎样跟随设备方向?
保持 config.orientation: 'auto'(默认值)即可。即使系统或页面锁定竖屏,插件也会读取真实持机方向:照片在按快门时确定方向,录像开始时冻结本次视频方向;横持设备开始录像会生成横屏视频。文字和图片按归正后的成片方向与锚点排版,无需手动给烧录水印设置 rotation。明确设置 portrait、landscapeLeft 或 landscapeRight 时继续使用指定方向。
Android 与 iOS 的内置全屏相机会随真实设备方向旋转整个原生页面和控制栏;关闭全屏相机后,iOS 会恢复进入相机前的宿主页面方向。orientation 始终表示照片和视频的输出方向,不用于强制页面旋转。内嵌 <lizhao-camera-pro> 不接管宿主页面方向,是否横竖屏切换由项目页面配置决定。
实时预览的显示方向与成片输出方向分开处理:Android 预览默认跟随当前 Display 旋转,iOS 预览默认跟随当前 UIKit 界面方向;这样页面横屏时,取景画面不会继续按竖屏纹理显示。previewRotation 仍可传 90 / 180 / 270 做明确的预览角度修正,传 0(默认)表示使用当前屏幕方向;它不会改变照片或录像的输出方向。
设备先取得一次可靠横竖方向后,接近平放再向左或向右旋转也会继续更新下一张照片或下一次录像的方向。首次打开相机即处于平放状态,或设备无法提供可靠方向读数时,插件会回退当前显示方向。录像开始后再转动设备不会旋转当前视频;暂停恢复、录像中切换镜头及后续片段都会沿用开始时冻结的方向,停止后重新开始录像才会读取新方向。录像结果可通过 recordfinished.result.width / height 判断横竖方向,并以实际成片确认画面和水印朝向。
模块五:选择保存位置、保留原片和处理同名文件
四种输出目标对应不同的使用周期:
| 输出目标 | 适合场景 | 结果特点 |
|---|---|---|
cache |
上传前预览、短期使用 | 临时文件,业务结束后可清理 |
files |
应用内长期保存 | 写入应用文件目录 |
album |
让用户在系统相册中查看 | 可能触发系统授权或确认 |
custom |
写入项目指定的应用可写位置 | 目录形式受平台限制;Harmony 仅支持可写绝对目录或可解析的 file:// 目录 |
function takeAndKeepOriginal(): void {
camera.value?.takePhoto({
outputOptions: {
target: 'files', // 要进入系统相册可改为 album。
fileName: 'work.jpg',
conflictPolicy: 'rename',
keepOriginal: true
},
watermarkOptions: {
enabled: true,
items: [{ id: 'time', type: 'text', text: '{timestamp}' }],
burnIntoPhoto: true
},
success: (result: CameraMediaResult): void => {
console.log('原片', result.originalPath, result.originalUri)
console.log('最终成片', result.uploadFilePath)
},
fail: (error: CameraFail): void => {
console.log('照片保存失败', error.errCode, error.stage)
}
})
}
保存数量遵循下面的规则:
| 本次是否实际烧录水印 | keepOriginal |
保存结果 |
|---|---|---|
| 是 | true |
无水印原片和水印成片各一份 |
| 是 | false |
只保存一份水印成片 |
| 否 | 任意值 | 只保存一份无水印成片 |
普通业务优先使用 conflictPolicy: 'rename',可以避免同名文件覆盖。组件单次拍照或录像传入的 outputOptions 会按字段覆盖会话配置,未传字段继续继承。
模块六:调整镜头、画质、闪光灯、缩放和曝光
需要暗光拍摄、固定画质、前摄或远景时,可以在组件属性、单次拍摄参数或组件方法中配置。下面的方法通常分别绑定到界面按钮或滑块,沿用模块一的 photo、recordfinished 和 error 事件接收结果。
function takeHighQualityPhoto(): void {
camera.value?.takePhoto({
photoResolution: { width: 1920, height: 1080 },
photoQuality: 0.92
})
}
function startHighQualityVideo(): void {
camera.value?.startRecording({
videoQuality: 'high',
videoFrameRate: 30
})
}
function setDarkScene(): void {
// 闪光灯用于拍照;持续补光使用 applyTorchEnabled。
camera.value?.applyFlashMode('auto')
camera.value?.applyExposureCompensation(1)
}
function zoomIn(): void {
// 使用前读取当前镜头 zoomRange,实际值由 zoomchange 返回。
camera.value?.applyZoomRatio(2)
}
function focusCenter(): void {
camera.value?.focusAt(0.5, 0.5)
}
镜头、分辨率、帧率、闪光灯、补光灯、HDR、白平衡、缩放和曝光范围都由设备决定。请求值不等于最终值,拍摄完成后应查看 appliedConfig。
标准组件:显示 W 按钮、开启双指缩放、复制测试日志
初次接入可先看 广角使用指南,其中包含能力判断表、全屏拍摄代码和组件 W 按钮使用步骤。
完整实现位于 uni-app x 标准组件示例(uni_modules/lizhao-camera-pro/example/uniappx/camera.uvue)。showWideButton 是示例页面自己的按钮开关,不是组件属性;pinchToZoom 才是组件属性。示例会从 ready / capabilitieschange 读取真实 positions 与 zoomRange,再决定切换 ultraWide 或应用当前镜头的最小倍率,不会把 0.5× 写死为所有设备通用值。
双指缩放只在当前镜头的 zoomRange 内生效,不会自动切换独立超广角。独立超广角自己的 1× 也可能已经是广角视野,不能直接与主摄的 1× 比较。系统相机有 W,并不代表系统向第三方应用开放了同一镜头。VDOM 与 Vapor 均运行这份 .uvue 示例。
预览构图、提示音、振动与硬件快门
以下配置添加到模块一的组件标签中即可。各参数说明集中在此表,后面的代码展示实际绑定方式:
| 功能 | 配置与作用 |
|---|---|
| 预览填充 | scaleType='fit' 尽量显示完整画面,比例不同时可能留边;fill / centerCrop 填满预览,可能裁掉边缘。它不等同于成片分辨率。 |
| 构图辅助 | grid='3x3' / '4x4' / 'phi' 显示九宫格、四乘四或黄金分割辅助线,off 关闭;gridColor 设置线条颜色。辅助线不作为水印写入成片。 |
| 圆角和旋转 | cornerRadius 设置预览圆角像素;previewRotation 修正屏幕预览角度,成片方向仍由 orientation 控制。 |
| 前摄镜像 | mirrorPreview 控制自拍预览,mirrorOutput 控制前摄成片;两个开关独立。 |
| 拍摄反馈 | shutterSoundEnabled / recordSoundEnabled 控制插件拍照、录像提示音;自定义声音分别使用 shutterSoundPath / recordSoundPath,传应用可读取的本地音频路径。 |
| 振动反馈 | vibrateOnCapture 启用反馈,vibrateDurationMs 为请求毫秒数;实际效果取决于平台和硬件。 |
| 硬件快门 | hardwareShutterEnabled 请求使用音量或媒体按键拍摄;支持的按键、焦点要求与平台差异见下文。 |
<!-- 合入模块一的组件,保留已有事件;此处仅展示可选属性。 -->
<lizhao-camera-pro
ref="camera"
style="width: 750rpx; height: 700rpx;"
camera-position="front"
scale-type="fit"
grid="3x3"
grid-color="#80FFFFFF"
:corner-radius="12"
:preview-rotation="0"
:mirror-preview="true"
:mirror-output="false"
:tap-to-focus="true"
:shutter-sound-enabled="true"
:record-sound-enabled="true"
:vibrate-on-capture="true"
:vibrate-duration-ms="40"
:hardware-shutter-enabled="true"
/>
布尔值和数字前的 : 必须保留,例如关闭声音要写 :record-sound-enabled="false",不要传字符串 "false"。自定义音频路径留空时使用平台默认提示音;声音设置不代表能够关闭系统自身的拍照声音。
| 平台 | 拍摄反馈与硬件快门边界 |
|---|---|
| Android | 提供拍照/录像提示音及振动。内嵌预览需窗口和相机视图获得焦点,才处理音量加减、耳机按键;拍照或混合模式下按键拍照,录像中或暂停时按键结束录像。内嵌纯录像模式请使用页面按钮开始录像。产品全屏模式复用屏幕快门与倒计时。 |
| iOS | 提供预览网格、拍照成功与录像开始振动。硬件快门使用系统公开的相机捕获事件,需要 iOS 17.2 及以上;拍照、混合模式下触发照片,录像中或暂停时结束录像,产品模式复用当前屏幕快门和倒计时。系统较旧或当前状态不能拍摄时不会占用音量键。shutterSoundPath 自定义拍照提示音尚未实现,系统快门声由 iOS 系统策略决定。 |
| Harmony | 提供拍照/录像提示音及振动;视图接收到音量加减或媒体播放/暂停按键时处理快门,纯录像模式可开始录像,录像中或暂停时结束录像。系统未把按键交给相机视图时不会触发。 |
白平衡、HDR 与持续补光
whiteBalance 可选择自动、白炽灯、荧光灯、日光或阴天,使用前检查 capabilities.whiteBalanceModes;hdr=true 请求 HDR 采集,使用前检查 hdrSupported。两者都是设备能力请求,不能保证所有镜头或输出格式相同,实际配置见 appliedConfig。例如,在组件上绑定 white-balance="daylight" 和 :hdr="true",或在全屏相机的 config 中传 whiteBalance: 'daylight', hdr: true。
flashMode 设置拍照闪光策略;需要一直照亮取景区域时使用组件属性 :torch-enabled="true",或在 ready 后调用 camera.applyTorchEnabled(true),关闭传 false。先检查 capabilities.torchSupported,失败从 error 接收;前后镜头不一定都支持补光。
模块七:查询设备能力并处理配置降级
如果页面需要根据设备能力显示按钮,建议在打开相机前查询。该查询不会占用业务相机会话。
import { getCameraCapabilities } from '@/uni_modules/lizhao-camera-pro'
getCameraCapabilities({
position: 'back', // 查询后置镜头;切换镜头后需要使用该镜头的新能力范围。
success(capabilities) {
// 用支持标志和范围决定哪些按钮可用,不预设所有设备能力相同。
console.log('可用镜头', capabilities.positions)
console.log('录像档位', capabilities.videoQualities)
console.log('可用帧率', capabilities.videoFrameRates)
console.log('暂停恢复', capabilities.pauseResumeSupported)
console.log('录像切镜', capabilities.switchCameraWhileRecordingSupported)
},
fail(error) {
console.log('能力查询失败', error.errCode, error.stage)
}
})
fallbackPolicy: 'nearest' 适合大多数业务:设备无法完全满足时,插件选择最接近的配置,并在 appliedConfig.fallbackReasons 中说明原因。strict 适合规格必须精确匹配的业务,无法满足时返回 9081010。
模块八:监听拍摄状态、处理失败并释放相机
相机、录像、切镜和最终处理都是异步流程。按钮应跟随事件状态更新,避免在上一步尚未完成时重复提交。下例需绑定 @statechange="onStateChange"、@finalizeprogress="onFinalizeProgress" 和 @error="onError"。
function onStateChange(event: CameraStateChangeEvent): void {
// 根据 opening、previewing、recording、paused、finalizing 等状态控制按钮。
console.log('相机状态', event.state)
}
function onFinalizeProgress(event: CameraFinalizeProgressEvent): void {
// 单个阶段到 100% 不等于成片完成,仍需等待 photo / recordfinished。
console.log('处理进度', event.stage, event.progress)
}
function onError(event: CameraErrorEvent): void {
console.log('相机失败', event.error.errCode, event.error.stage, event.error.retryable)
}
close() 只关闭当前预览,之后仍可调用 open();destroyCamera() 会释放当前会话和监听,但保留标准组件 Host,同一个 ref 仍可再次 open()。页面卸载时组件会在内部执行最终销毁。
录像期间进入后台怎么处理?
backgroundBehavior 决定应用进入后台时如何处理正在进行的录像,不提供持续后台录像:
| 值 | 行为 | 业务处理 |
|---|---|---|
finish(默认) |
结束录制并进入正常的合并、保存流程 | 等待 recordfinished;全屏相机等待最终回调。处理失败仍会报错。 |
cancel |
取消本次未交付的录像 | 按取消处理,错误码为 9081013,不把它当作已保存的视频。 |
uni-app x 标准组件使用 background-behavior="finish";全屏相机使用顶层 openCamera({ backgroundBehavior: 'finish', ... }),不要放进 config。该策略不等于页面卸载策略:离开页面且希望保留视频时,先完成停止与交付,再释放组件。
模块九:删除插件创建的照片或视频
删除时优先原样传回拍摄结果中的 path、uri 和 albumIdentifier。插件只删除能够确认归属的媒体。
在模块一页面的 <script setup lang="uts"> 中补充以下代码,并用下面两个同名函数替换原来的 onPhoto、onRecordFinished。模板已有的 @photo="onPhoto" 和 @recordfinished="onRecordFinished" 保持不变;ref 与相关类型沿用模块一的导入。
import { deleteCameraMedia } from '@/uni_modules/lizhao-camera-pro'
const lastMediaResult = ref<CameraMediaResult | null>(null)
const deleting = ref<boolean>(false)
function onPhoto(event: CameraPhotoEvent): void {
// 事件只保存结果,不自动删除。
lastMediaResult.value = event.result
}
function onRecordFinished(event: CameraRecordFinishedEvent): void {
lastMediaResult.value = event.result
}
function deleteLastMedia(): void {
const mediaResult = lastMediaResult.value
if (mediaResult == null || deleting.value) return
deleting.value = true
deleteCameraMedia({
path: mediaResult.path,
uri: mediaResult.uri,
albumIdentifier: mediaResult.albumIdentifier,
success: (deleted: CameraDeleteMediaResult): void => {
console.log('删除结果', deleted.deleted)
// 等待删除时可能拍出新媒体;不清除后来收到的新结果。
if (deleted.deleted && lastMediaResult.value === mediaResult) lastMediaResult.value = null
},
fail: (error: CameraFail): void => {
console.log('删除失败', error.errCode, error.stage)
},
complete: (_result: CameraDeleteMediaResult | CameraFail): void => {
deleting.value = false
}
})
}
在模板中添加删除按钮;正式业务建议由二次确认后调用 deleteLastMedia():
<button :disabled="lastMediaResult == null || deleting" @click="deleteLastMedia">删除最近媒体</button>
uni-app x 标准组件也提供参数相同的 deleteMedia(options)。系统相册中的媒体可能需要系统授权或确认,不能把“已发起删除”当成“已经删除成功”。
复制问题排查日志(Android)
遇到预览模糊、切换镜头异常或保存后页面异常时,先复现一次,再返回“相机功能体验”或内嵌相机示例,点击 复制排查日志,将整段文字连同当时的操作步骤发送给维护者。日志会保留最近的记录,返回页面后仍可读取。
自己的业务页面可添加一个按钮调用下面的方法:
import { getCameraDiagnosticLog } from '@/uni_modules/lizhao-camera-pro'
function copyCameraDiagnosticLog() {
uni.setClipboardData({
data: getCameraDiagnosticLog(),
showToast: false,
success: () => { uni.showToast({ title: '排查日志已复制,可直接发送', icon: 'none' }) },
fail: () => { uni.showToast({ title: '复制失败,请重试', icon: 'none' }) }
})
}
日志包含机型、系统、实际镜头、拍摄保存摘要、全屏回调顺序及本应用页面的前后台变化,不含照片内容、完整路径、坐标、水印文字、密钥或设备唯一标识,也不会自动上传。它不能读取腾讯地图等其他应用的内部行为。请使用包含本接口的 Android 安装包;iOS、HarmonyOS 和非 App 平台会返回暂不支持原生诊断的说明。
排查广角时,import 放在页面 <script> 顶部;相机预览就绪、复现操作后,再点击按钮读取日志。Android 日志还会记录 CameraX 候选镜头及其公开的物理成员、读取状态和实际选择的物理路由。这份候选清单不等同于 CameraManager 原始系统清单;仍不能定位时,由维护者按需提供系统镜头诊断。更新原生诊断或选镜代码后,须重新制作并安装匹配源码的 Android 自定义基座或 APK。完整步骤见 广角使用指南。
完整示例
下表给出示例相对于项目根目录的文件位置,可在 HBuilderX 项目管理器中打开。建议先使用对应环境的“相机功能体验”入口:uni-app 验证全屏根 API;uni-app x 再进入标准组件承载页验证页面内预览、连续操作与事件。
| 项目类型 | 示例用途 | 插件内文件位置 |
|---|---|---|
| uni-app | 示例首页、根 API 与页面导航 | uni_modules/lizhao-camera-pro/example/uniapp/index.vue |
| uni-app | 内置全屏拍摄、结果回调、水印和输出位置 | uni_modules/lizhao-camera-pro/example/uniapp/fullscreen.vue |
| uni-app | 选择或移除图片、调节位置、大小和透明度,以及拍摄结果提示 | uni_modules/lizhao-camera-pro/example/uniapp/image-watermark.vue |
| uni-app x | 示例首页、根 API 与页面导航 | uni_modules/lizhao-camera-pro/example/uniappx/index.uvue |
| uni-app x | 嵌入式相机、强类型组件实例、完整事件和页面卸载清理 | uni_modules/lizhao-camera-pro/example/uniappx/camera.uvue |
| uni-app x | UVUE 选图与参数调节,以及文字和图片混排 | uni_modules/lizhao-camera-pro/example/uniappx/image-watermark.uvue |
复制选用的示例到项目页面目录后,在 pages.json 中注册页面,并调整示例中的跳转路径。uni-app 只登记统一入口及需要的全屏/图片水印页;uni-app x 再登记 camera.uvue 标准组件页,不要同时注册另一个环境的示例。地点、人员等业务值均为演示数据,请替换为项目实际内容。
建议先复制本文的最小示例确认环境,再按完整示例选取需要的功能,不要一次性把全部配置加入业务页面。
常用 API 与配置
API 用途总览
| 模块 | 适用业务 | 常用方法 | 使用结果 |
|---|---|---|---|
| 内置全屏相机 | 快速拍照或录像 | openCamera() |
最终媒体由 success 返回 |
| uni-app x 标准组件会话 | 自定义页面和按钮 | open()、close()、destroyCamera() |
ready/statechange/error 反馈状态 |
| 拍照 | 照片留档 | takePhoto() |
success 或 photo 返回结果 |
| 录像 | 视频留档 | startRecording()、stopRecording() |
recordstart 确认开始,recordfinished 返回最终视频 |
| 分段录像 | 暂停恢复、录像切镜 | pauseRecording()、resumeRecording()、switchCamera() |
停止后合并为一个视频 |
| 画面控制 | 灯光、缩放、曝光、对焦 | applyFlashMode()、applyTorchEnabled()、applyZoomRatio()、applyExposureCompensation()、focusAt() |
事件与 appliedConfig 反馈真实值 |
| 水印 | 预览及成片水印 | applyWatermark() 或拍摄参数 |
watermarkApplied 反馈是否烧录 |
| 已有图片水印 | 自选相册图片、业务自建编辑页 | addImageWatermark() |
新 JPEG 的路径、宽高和跳过项;Android / iOS |
| 自定义相机水印拖动 | uni-app x 页面内调整位置 | watermarkDraggable 属性 |
watermarkchange 返回已提交的完整配置;Android / iOS |
| 能力查询 | 按设备显示设置 | getCameraCapabilities()、组件 getCapabilities() |
返回镜头和拍摄能力 |
| 媒体删除 | 撤销或清理附件 | deleteCameraMedia()、组件 deleteMedia() |
返回 CameraDeleteMediaResult |
| 问题排查 | 复制 Android 相机最近的排错记录 | getCameraDiagnosticLog() |
同步返回脱敏文本,可直接复制反馈 |
通用回调
以下标注类型的 uts 示例放在 uni-app x 页面的 <script setup lang="uts"> 中;ts 示例用于普通 uni-app 的 TypeScript 脚本。API 使用 import,类型使用 import type,均按示例从 @/uni_modules/lizhao-camera-pro 导入。
全屏相机、能力查询、媒体删除和已有图片水印的 App 入口接收下列参数类型。需要先声明参数变量时,请按项目选择;直接写 openCamera({ ... }) 等调用时,无需额外导入参数类型。
| 方法 | uni-app TypeScript:完整字段类型 | uni-app x App:调用参数类型 |
|---|---|---|
openCamera |
OpenCameraOptions |
OpenCameraBridgeOptions |
getCameraCapabilities |
GetCameraCapabilitiesOptions |
GetCameraCapabilitiesBridgeOptions |
deleteCameraMedia |
DeleteCameraMediaOptions |
DeleteCameraMediaBridgeOptions |
addImageWatermark |
AddImageWatermarkOptions |
AddImageWatermarkBridgeOptions |
两种参数写法使用相同的业务字段和回调。不要自行创建同名类型,也不要从插件的 utssdk/app-android 等内部目录导入。
openCamera()、getCameraCapabilities()、deleteCameraMedia()、addImageWatermark() 及带异步结果的 uni-app x 标准组件方法都使用回调,不返回 Promise;getCameraDiagnosticLog() 直接返回字符串。
| 参数 | 类型 | 必填 | 说明 | 默认值 | 可选参数 |
|---|---|---|---|---|---|
| success | function | 否 | 当前操作成功时触发;具体结果随方法变化 | 无 | 无 |
| fail | function | 否 | 当前操作失败或取消时触发,返回 CameraFail |
无 | 无 |
| complete | function | 否 | 成功或失败后触发一次 | 无 | 无 |
startRecording.success 和 complete 只确认录像真实开始;最终视频必须等待 recordfinished.result。openCamera.success 则直接返回用户最终完成的照片或视频。
常用拍摄配置
组件属性、openCamera() 顶层参数和 openCamera.config 并不是完全相同的三组字段:
- 组件使用
cameraPosition,并提供预览、交互、提示音和生命周期相关属性。 openCamera()顶层使用cameraPosition、mode、tapToFocus、pinchToZoom、grid、gridColor、vibrateOnCapture、vibrateDurationMs、hardwareShutterEnabled、backgroundBehavior。openCamera.config使用position,放置照片、视频、音频请求、曝光、白平衡、HDR、输出和水印配置。
下表是 CameraRequestedConfig,用于 openCamera.config,也可作为组件 open() 的本次配置覆盖;单次拍照或录像只接受对应的拍摄字段。
例如,先声明照片尺寸和拍摄配置,再打开全屏相机:
import { openCamera } from '@/uni_modules/lizhao-camera-pro'
import type { CameraRequestedConfig, CameraSize } from '@/uni_modules/lizhao-camera-pro'
const photoResolution: CameraSize = { width: 1920, height: 1080 }
const config: CameraRequestedConfig = {
orientation: 'auto',
fallbackPolicy: 'nearest',
photoResolution
}
openCamera({ mode: 'photo', uiPreset: 'classic', config })
| 参数 | 类型 | 必填 | 说明 | 默认值 | 可选参数 |
|---|---|---|---|---|---|
| position | string | 否 | 请求镜头 | back |
back / front / ultraWide |
| orientation | string | 否 | 照片与视频输出方向;auto 按拍照或录像开始时的真实持机方向确定 |
auto |
auto / portrait / landscapeLeft / landscapeRight |
| aspectRatio | string | 否 | 输出比例;9:16 为固定竖版照片 | auto |
auto / 1:1 / 4:3 / 16:9 / 9:16 |
| photoCropMode | string | 否 | 照片按输出设置或快门时预览区域裁剪;preview 优先于比例 | output |
output / preview |
| fallbackPolicy | string | 否 | 不支持请求的处理方式 | nearest |
nearest / strict |
| photoResolution | object | 否 | 请求照片宽高;零值表示由平台选择 | {width:0,height:0} |
{ width, height } |
| photoQuality | number | 否 | JPEG 压缩质量 | 0.92 |
0~1 |
| photoFormat | string | 否 | 照片格式 | jpg |
jpg / jpeg |
| videoQuality | string | 否 | 录像档位 | high |
low / medium / high / uhd |
| videoWidth | number | 否 | 请求视频宽度;零表示由平台选择 | 0 |
非负整数 |
| videoHeight | number | 否 | 请求视频高度;零表示由平台选择 | 0 |
非负整数 |
| videoBitrate | number | 否 | 请求视频码率,单位 bit/s;例如 8000000 约为 8 Mbps,零表示由平台选择 |
0 |
非负整数 |
| videoFrameRate | number | 否 | 请求视频帧率,单位帧/秒;零表示由平台选择 | 0 |
非负整数 |
| outputFormat | string | 否 | 视频容器,不是照片格式 | Android/Harmony 为 mp4,iOS 为 mov |
mp4 / mov |
| recordAudio | boolean | 否 | 是否录制麦克风声音 | true |
true / false |
| echoCancellation | boolean | 否 | 请求系统回声消除,以实际配置为准 | true |
true / false |
| noiseSuppression | boolean | 否 | 请求系统降噪,以实际配置为准 | true |
true / false |
| autoGainControl | boolean | 否 | 请求系统自动增益,以实际配置为准 | true |
true / false |
| maxDurationMs | number | 否 | 最大录像时长;零表示手动停止 | 0 |
非负整数 |
| flashMode | string | 否 | 拍照闪光策略 | off |
off / on / auto / torch |
| zoomRatio | number | 否 | 请求缩放倍率 | 1 |
以能力范围为准 |
| exposureCompensation | number | 否 | 请求曝光补偿 | 0 |
以能力范围为准 |
| whiteBalance | string | 否 | 请求白平衡 | auto |
auto / incandescent / fluorescent / daylight / cloudy |
| hdr | boolean | 否 | 是否请求 HDR 采集,以设备能力和实际配置为准 | false |
true / false |
| outputOptions | object | 否 | 输出位置与命名策略 | 见下表 | target / directory / albumName / fileName / conflictPolicy / keepOriginal |
| watermarkOptions | object | 否 | 结构化水印 | 关闭 | 见下表 |
Harmony 视频最终输出为 MP4;请求 MOV 时,nearest 会改用 MP4,strict 会返回能力不支持错误。Android 通常输出 MP4;iOS 可在最终处理阶段将原生 MOV 转为请求的 MP4。
输出配置 outputOptions
拍摄输出使用 CameraOutputOptions。例如,将本次照片保存到缓存目录:
import { openCamera } from '@/uni_modules/lizhao-camera-pro'
import type { CameraOutputOptions } from '@/uni_modules/lizhao-camera-pro'
const outputOptions: CameraOutputOptions = { target: 'cache', keepOriginal: false }
openCamera({ mode: 'photo', uiPreset: 'classic', config: { outputOptions } })
| 参数 | 类型 | 必填 | 说明 | 默认值 | 可选参数 |
|---|---|---|---|---|---|
| target | string | 否 | 输出目标 | cache |
cache / files / album / custom |
| directory | string | 否 | custom 的平台可写目录;Harmony 仅支持绝对目录或可解析的 file:// 目录 |
空字符串 | 无 |
| albumName | string | 否 | 系统相册名称;Harmony 无法指定时,nearest 使用系统默认分组并记录降级,strict 返回 9081010 |
空字符串 | 无 |
| fileName | string | 否 | 不含路径分隔符的文件名 | 自动生成 | 无 |
| conflictPolicy | string | 否 | 同名文件处理方式 | rename |
rename / overwrite / error |
| keepOriginal | boolean | 否 | 水印实际烧录时是否同时保留无水印原片 | false |
true / false |
overwrite 只覆盖插件能够确认归属的同名媒体;无法确认归属时会失败,不会强行覆盖任意项目文件。
水印配置 watermarkOptions
| 参数 | 类型 | 必填 | 说明 | 默认值 | 可选参数 |
|---|---|---|---|---|---|
| enabled | boolean | 否 | 是否启用水印 | false |
true / false |
| items | array | 否 | 文本或图片水印项 | [] |
CameraWatermarkItem[] |
| fields | object | 否 | 业务占位符数据 | {} |
业务自定义键值 |
| timestampFormat | string | 否 | 水印级 {timestamp} 的默认格式;单个文字项可用同名字段覆盖 |
yyyy-MM-dd HH:mm:ss |
合法时间格式 |
| opacity | number | 否 | 全局透明度 | 1 |
0~1 |
| scale | number | 否 | 全局缩放,同时作用于文字尺寸、显式宽高和边距 | 1 |
正数 |
| previewVisible | boolean | 否 | 是否在插件原生预览中显示,不影响成片烧录 | true |
true / false |
| burnIntoPhoto | boolean | 否 | 是否烧录到照片 | true |
true / false |
| burnIntoVideo | boolean | 否 | 是否烧录到视频 | true |
true / false |
items[] 的常用字段:
| 参数 | 类型 | 必填 | 说明 | 默认值 | 可选参数 |
|---|---|---|---|---|---|
| id | string | 是 | 业务侧唯一标识 | 无 | 无 |
| dragGroup | string | 否 | Android / iOS 标准组件中相同非空组名的水印一起拖动,不影响烧录样式 | 空字符串 | 业务自定义组名 |
| draggable | boolean | 否 | Android / iOS 标准组件手势开关;省略时按 true 处理,但仍受全局 watermarkDraggable 限制;同组任一项 false 则整组锁定 |
true(全局开关默认仍为 false) |
true / false |
| type | string | 是 | 水印类型 | 无 | text / image |
| text | string | 文本项是 | 文本及占位符内容 | 空字符串 | {timestamp}、{recordingDuration} 或 fields 中的键 |
| timestampFormat | string | 否 | 当前文字项中 {timestamp} 的格式;未填写时继承水印级配置 |
水印级 timestampFormat |
合法时间格式 |
| imagePath | string | 图片项是 | 可读本地/资源路径或 PNG/JPEG Base64(Data URL 或纯标准串) | 空字符串 | 编码最多 12 MiB,解码最多 8 MiB |
| anchor | string | 否 | 可动态切换的水印锚点;custom 时再读取 x/y |
bottomRight |
topLeft / topRight / bottomLeft / bottomRight / center / custom |
| customOrigin | string | 否 | custom 的坐标基准点;动态改变内容尺寸时仍以同一外框基准点定位。HarmonyOS 图片项未传时为兼容旧版按左上点,显式传入后按此字段执行 |
center(HarmonyOS 旧图片调用为 topLeft) |
center / topLeft / topRight / bottomLeft / bottomRight |
| x | number | custom 时是 |
归一化横坐标,表示 customOrigin 对应的整个水印外框基准点 |
无 | 0~1 |
| y | number | custom 时是 |
归一化纵坐标,表示 customOrigin 对应的整个水印外框基准点 |
无 | 0~1 |
| width | number | 否 | 缩放前的输出画布归一化内容宽度 | 按内容 | 0~1 |
| height | number | 否 | 缩放前的输出画布归一化内容高度 | 按内容 | 0~1 |
| fontSize | number | 否 | 文本字号,按输出画面短边 1080 换算 | 32 |
正数 |
| fontFamily | string | 否 | 逻辑字体族;三端映射到对应系统字体,不需要字体文件 | system |
system / sansSerif / serif / monospace |
| fontWeight | string | 否 | 文本字重 | normal |
normal / bold |
| color | string | 否 | 文本颜色 | 平台默认 | #RRGGBB / #AARRGGBB |
| backgroundColor | string | 否 | 文本背景色 | 平台默认 | #RRGGBB / #AARRGGBB |
| opacity | number | 否 | 单项透明度 | 1 |
0~1 |
| rotation | number | 否 | 顺时针旋转角度 | 0 |
任意数值 |
| padding | number | 否 | 文字内容内边距,按输出画面短边 1080 换算 | 8 |
非负数 |
| lineSpacing | number | 否 | 多行文本行距,按输出画面短边 1080 换算 | 4 |
非负数 |
水印布局换算规则
文字水印的 fontSize、padding 和 lineSpacing 使用输出画面短边 1080 设计单位,不是手机的 dp / sp / vp,也不是最终照片的绝对像素。插件会按输出画面短边自动换算,因此同一配置在 1080p、3K、4K 成片中的相对大小一致。
如果页面需要自绘一层水印预览,应使用相机预览 Surface 旋转后的完整画面框换算,不要在拍照后改用原始照片宽度再次缩小字号。frameWidth / frameHeight 是旋转后画面框的宽高,frameX / frameY 是该画面框相对组件视口左上角的偏移:fit 出现黑边时偏移为正,fill / centerCrop 发生居中裁切时偏移可以为负。
// 这是自绘预览的换算片段;frameWidth / frameHeight 需先取得旋转后的完整画面尺寸。
const previewShortSide = Math.min(frameWidth, frameHeight)
const unitScale = previewShortSide / 1080 * (watermarkOptions.scale || 1)
const fontPx = (item.fontSize ?? 32) * unitScale
const paddingPx = (item.padding ?? 8) * unitScale
const lineSpacingPx = (item.lineSpacing ?? 4) * unitScale
// 以下内容框公式只用于显式传入且 width > 0 的情况。
const contentWidth = item.width * frameWidth * (watermarkOptions.scale || 1)
const outerWidth = contentWidth + paddingPx * 2
const customOrigin = item.customOrigin || 'center'
const left = customOrigin === 'topRight' || customOrigin === 'bottomRight'
? frameX + item.x * frameWidth - outerWidth
: customOrigin === 'center' ? frameX + item.x * frameWidth - outerWidth / 2
: frameX + item.x * frameWidth
// 高度和纵坐标遵循同一规则;height 为 0 或省略时改为测量实际内容高度。
const contentHeight = item.height * frameHeight * (watermarkOptions.scale || 1)
const outerHeight = contentHeight + paddingPx * 2
const top = customOrigin === 'bottomLeft' || customOrigin === 'bottomRight'
? frameY + item.y * frameHeight - outerHeight
: customOrigin === 'center' ? frameY + item.y * frameHeight - outerHeight / 2
: frameY + item.y * frameHeight
未传 width 或传 0 时,应使用同一字体、字重和 fontPx 测量最长显式文本行,作为内容宽度;不能直接把 undefined 代入公式。width / height 是缩放前的归一化内容框尺寸,0 或省略表示按内容计算;顶层 scale 会同时缩放内容框、字号、padding 和行距,文字 padding 位于内容框外。对于 custom,x / y 会按 customOrigin 把整个水印外框的指定基准点放到对应归一化坐标;未传时默认是 center。HarmonyOS 图片项没有传 customOrigin 时为兼容旧版仍以左上点定位,显式传入后与其他平台使用相同五种基准点;如需跨平台稳定贴边,优先使用 topLeft / topRight / bottomLeft / bottomRight / center 等预设锚点。
预设锚点在实时预览中按屏幕实际可见的 viewport 计算。fill / centerCrop 预览为了铺满组件会把完整画面框裁出屏幕,bottomLeft 等预设仍以可见框的边缘和边距定位,因此不会因为完整画面框的负偏移而把卡片左侧推到屏幕外;照片和录像烧录继续按完整输出画布定位。custom 的 x / y 默认按中心点计算;需要固定左上角或其他角点时设置 customOrigin,内容或外框尺寸变化时无需重新估算该基准点。
文本只按显式 \n 换行,并保留开头、结尾和连续换行产生的空行;width 不会自动折行。单行超过内容框时会被裁切,请在业务层按需要插入换行符。previewVisible:false 只隐藏插件原生预览水印,不会关闭成片烧录;照片和视频分别由 burnIntoPhoto、burnIntoVideo 控制。
普通水印字段由业务侧写入 fields,再在 text 中使用同名占位符;这一过程不申请定位权限。Android 全屏位置搜索是独立的可选配置,见 locationService。
<lizhao-camera-pro /> 属性
| 参数 | 类型 | 必填 | 说明 | 默认值 | 可选参数 |
|---|---|---|---|---|---|
| sessionId | string | 否 | 页面内稳定且唯一的会话标识 | 自动生成 | 无 |
| cameraPosition | string | 否 | 初始镜头 | back |
back / front / ultraWide |
| mode | string | 否 | 拍摄模式 | mixed |
photo / video / mixed |
| autoStart | boolean | 否 | 挂载后是否自动打开 | true |
true / false |
| scaleType | string | 否 | 预览填充方式 | fill |
fit / fill / centerCrop |
| aspectRatio | string | 否 | 输出比例;9:16 为固定竖版照片 | auto |
auto / 1:1 / 4:3 / 16:9 / 9:16 |
| photoCropMode | string | 否 | 照片按输出设置或快门时预览区域裁剪;preview 优先于比例 | output |
output / preview |
| cornerRadius | number | 否 | 原生预览圆角 | 0 |
非负数 |
| previewRotation | number | 否 | 预览旋转修正 | 0 |
0 / 90 / 180 / 270 |
| flashMode | string | 否 | 闪光策略 | off |
off / on / auto / torch |
| torchEnabled | boolean | 否 | 是否开启补光灯 | false |
true / false |
| zoomRatio | number | 否 | 请求缩放倍率;实际值由 zoomchange.appliedRatio 返回 |
1 |
以当前镜头 zoomRange 为准 |
| exposureCompensation | number | 否 | 请求曝光补偿 | 0 |
以能力范围为准 |
| tapToFocus | boolean | 否 | 是否启用点击对焦 | true |
true / false |
| pinchToZoom | boolean | 否 | 是否启用取景区域双指缩放 | true |
true / false;在当前镜头范围内缩放 |
| grid | string | 否 | 预览网格 | off |
off / 3x3 / 4x4 / phi |
| gridColor | string | 否 | 网格颜色 | #80FFFFFF |
颜色字符串 |
| mirrorPreview | boolean | 否 | 前摄预览是否镜像 | true |
true / false |
| mirrorOutput | boolean | 否 | 前摄输出是否镜像 | false |
true / false |
| orientation | string | 否 | 输出方向 | auto |
auto / portrait / landscapeLeft / landscapeRight |
| photoResolution | object | 否 | 请求照片宽高;零值表示由平台选择 | {width:0,height:0} |
{ width, height } |
| photoQuality | number | 否 | JPEG 压缩质量 | 0.92 |
0~1 |
| photoFormat | string | 否 | 照片格式 | jpg |
jpg / jpeg |
| videoQuality | string | 否 | 录像档位 | high |
low / medium / high / uhd |
| videoWidth | number | 否 | 请求视频宽度;零表示由平台选择 | 0 |
非负整数 |
| videoHeight | number | 否 | 请求视频高度;零表示由平台选择 | 0 |
非负整数 |
| videoBitrate | number | 否 | 请求视频码率;零表示由平台选择 | 0 |
非负整数 |
| videoFrameRate | number | 否 | 请求视频帧率;零表示由平台选择 | 0 |
非负整数 |
| outputFormat | string | 否 | 视频容器 | Android/Harmony 为 mp4,iOS 为 mov |
mp4 / mov |
| recordAudio | boolean | 否 | 是否录制麦克风声音 | true |
true / false |
| echoCancellation | boolean | 否 | 请求系统回声消除 | true |
true / false |
| noiseSuppression | boolean | 否 | 请求系统降噪 | true |
true / false |
| autoGainControl | boolean | 否 | 请求系统自动增益 | true |
true / false |
| maxDurationMs | number | 否 | 最大录像时长;零表示手动停止 | 0 |
非负整数 |
| whiteBalance | string | 否 | 请求白平衡 | auto |
auto / incandescent / fluorescent / daylight / cloudy |
| hdr | boolean | 否 | 是否请求 HDR 采集 | false |
true / false |
| shutterSoundEnabled | boolean | 否 | 是否播放拍照提示音 | true |
true / false |
| shutterSoundPath | string | 否 | 自定义拍照提示音本地路径 | 空字符串 | 无 |
| recordSoundEnabled | boolean | 否 | 是否播放录像开始/停止提示音 | true |
true / false |
| recordSoundPath | string | 否 | 自定义录像提示音本地路径 | 空字符串 | 无 |
| vibrateOnCapture | boolean | 否 | 拍摄时是否振动 | false |
true / false |
| vibrateDurationMs | number | 否 | 振动时长 | 40 |
0~5000 |
| hardwareShutterEnabled | boolean | 否 | 是否启用音量键或媒体键快门 | false |
true / false |
| backgroundBehavior | string | 否 | 录像进入后台后的处理方式 | finish |
finish / cancel |
| fallbackPolicy | string | 否 | 设备不能满足配置时的处理方式 | nearest |
nearest / strict |
| outputOptions | object | 否 | 默认输出选项 | target=cache |
见输出配置 |
| watermarkOptions | object | 否 | 默认水印选项 | 关闭 | 见水印配置 |
| watermarkDraggable | boolean | 否 | Android / iOS 空闲预览中允许拖动可见水印;成功后触发 watermarkchange | false |
true / false |
双指缩放作用于当前镜头。先在 ready 或 capabilitieschange 中读取 capabilities.zoomRange;不要将最小值固定为 1 或 0.5。设备开放独立超广角时,可通过 switchCamera('ultraWide') 切换;查看 capabilities.positions 判断可用镜头,切换后以实际事件和新范围更新界面。系统相机显示 W 不代表第三方必然能够访问同一镜头,双指缩放也不会自动跨独立镜头切换。
uni-app x 标准组件示例提供自动打开、双指缩放、点击对焦、持续补光和预览旋转等配置,以及打开/关闭预览、镜头切换、曝光调整和能力查询。选择关闭自动打开时,请在预览页点击“打开预览”;测试手势时应在未被业务按钮覆盖的取景区域双指张合。
需要测试广角时,在示例的“内嵌预览设置”中开启“显示 W 广角按钮”,并在“交互与拍摄反馈”中开启“双指缩放”,然后打开内嵌相机。W 会优先切换设备开放的独立超广角;没有独立镜头但当前后置镜头支持小于 1 倍时,使用其真实最小倍率;系统没有报告可用能力时会显示提示。
点击 W 并尝试双指放大、缩小后,点击“复制测试日志”即可转发排查。日志包含机型、系统、镜头能力、请求与实际倍率、切镜结果和错误;连续缩放记录会限频,复制时附上最新实际状态。“显示 W 广角按钮”仅控制 uni-app x 示例按钮显示,不会增加设备原本没有开放的镜头能力。
组件方法
查询方法的可选 callback 会异步触发一次,收到本次查询时的真实状态或能力;uni-app x 也可直接使用同步返回值。业务若需要与其他异步状态统一处理,可以使用以下回调写法:
// 放在 <script setup lang="uts"> 的页面按钮方法中执行。
if (camera.value != null) {
camera.value!.isOpened((opened: boolean): void => {
console.log('预览是否打开', opened)
})
camera.value!.getCapabilities((capabilities: CameraCapabilities): void => {
console.log('当前镜头能力', capabilities)
if (!capabilities.ready) return
console.log('可用镜头', capabilities.positions)
console.log('当前镜头缩放范围', capabilities.zoomRange)
})
}
| 方法 | 用途 | 返回或结果 |
|---|---|---|
open(options?) |
打开或重新打开预览 | 回调返回 CameraReadyResult |
close() |
关闭当前预览 | 之后仍可再次打开 |
destroyCamera() |
释放当前相机会话与监听 | 同一组件仍可再次调用 open();页面卸载会由组件内部最终销毁 Host |
isOpened(callback?) |
查询是否已经打开 | 同步返回 boolean;可选回调异步返回同一快照 |
getCapabilities(callback?) |
获取当前能力快照 | 同步返回 CameraCapabilities;可选回调异步返回同一快照;未就绪时 ready=false |
takePhoto(options?) |
拍照 | 回调及 photo 事件返回媒体 |
startRecording(options?) |
开始一条逻辑录像 | 回调只确认真实开始 |
pauseRecording() |
暂停录像 | 等待 recordpause |
resumeRecording() |
恢复录像 | 等待 recordresume |
stopRecording() |
停止并处理录像 | 最终结果来自 recordfinished |
switchCamera(position?) |
切换镜头 | 未传位置时自动前后切换 |
applyFlashMode(mode) |
应用闪光策略 | 以能力和事件反馈为准 |
applyTorchEnabled(enabled) |
设置补光灯 | 以能力和事件反馈为准 |
applyZoomRatio(ratio) |
设置缩放倍率 | zoomchange 返回实际倍率 |
applyExposureCompensation(value) |
设置曝光补偿 | 以能力范围为准 |
applyWatermark(options, resetPosition?) |
更新后续拍摄水印 | 默认完整替换并使用传入位置;Android / iOS 标准组件第二参数传 false 可保留同项拖动位置 |
focusAt(x, y) |
按归一化坐标对焦 | focuschange 返回状态 |
deleteMedia(options) |
删除插件归属媒体 | 回调返回 CameraDeleteMediaResult |
组件方法要求页面已经挂载。destroyCamera() 只释放当前会话,后续可在同一个 ref 上再次 open();页面卸载时组件会完成最终清理。
组件方法参数
| 参数 | 类型 | 必填 | 说明 | 默认值 | 可选参数 |
|---|---|---|---|---|---|
open.options |
CameraOpenOptions | 否 | 本次打开组件相机会话的参数 | {} |
config / success / fail / complete |
takePhoto.options |
CameraTakePhotoOptions | 否 | 本次拍照覆盖项 | {} |
captureMode / photoCropMode / photoResolution / photoQuality / photoFormat / outputOptions / watermarkOptions / success / fail / complete |
takePhoto.options.photoCropMode |
string | 否 | 仅本次照片裁剪覆盖 | 继承会话 | output / preview |
takePhoto.options.captureMode |
string | 否 | 优先画质或优先拍摄速度 | quality |
quality / fast |
startRecording.options |
CameraStartRecordingOptions | 否 | 本次录像覆盖项 | {} |
videoQuality / videoWidth / videoHeight / videoBitrate / videoFrameRate / outputFormat / recordAudio / echoCancellation / noiseSuppression / autoGainControl / maxDurationMs / outputOptions / watermarkOptions / success / fail / complete |
open.success 返回已经运行的相机会话信息;takePhoto.success 返回最终照片;startRecording.success 只确认录像真实开始,最终视频仍从 recordfinished.result 取得。未传的单次字段继承当前会话配置,显式传入的 false 或 0 会保留。
组件方法的参数类型这样导入。下面与模块一的 <lizhao-camera-pro ref="camera" /> 配合使用,三个函数分别绑定各自的按钮;拍照和录像按钮在组件就绪后再开放。
import { ref } from 'vue'
import type {
CameraComponentBridge, CameraOpenOptions, CameraTakePhotoOptions,
CameraStartRecordingOptions, CameraReadyResult, CameraMediaResult,
CameraRecordingStartResult
} from '@/uni_modules/lizhao-camera-pro'
const camera = ref<CameraComponentBridge | null>(null)
function openPreview(): void {
const options: CameraOpenOptions = {
config: { fallbackPolicy: 'nearest' },
success: (result: CameraReadyResult): void => {
console.log('预览就绪', result.sessionId, result.appliedConfig)
}
}
camera.value?.open(options)
}
function takePhoto(): void {
const options: CameraTakePhotoOptions = {
photoQuality: 0.92,
success: (result: CameraMediaResult): void => {
console.log('最终照片', result.uploadFilePath)
}
}
camera.value?.takePhoto(options)
}
function startRecording(): void {
const options: CameraStartRecordingOptions = {
maxDurationMs: 10000,
success: (result: CameraRecordingStartResult): void => {
console.log('录像已开始', result.recordingId)
}
}
camera.value?.startRecording(options)
}
独立图片 API
addImageWatermark(options)
uni-app x App:需要单独声明参数时,导入 AddImageWatermarkBridgeOptions。imagePath 传图片选择器返回的可读本地路径。
import { addImageWatermark } from '@/uni_modules/lizhao-camera-pro'
import type { AddImageWatermarkBridgeOptions, CameraImageWatermarkResult } from '@/uni_modules/lizhao-camera-pro'
function addTextWatermark(imagePath: string): void {
const options: AddImageWatermarkBridgeOptions = {
imagePath,
watermarkOptions: {
enabled: true,
items: [{ id: 'note', type: 'text', text: '现场留存', anchor: 'bottomLeft' }]
},
outputOptions: { target: 'cache', conflictPolicy: 'rename' },
success: (result: CameraImageWatermarkResult): void => {
console.log('新图片', result.uploadFilePath)
}
}
addImageWatermark(options)
}
普通 uni-app TypeScript:完整参数和独立图片输出配置分别使用 AddImageWatermarkOptions、CameraImageOutputOptions;拍摄用的 keepOriginal 不适用于此方法。
import { addImageWatermark } from '@/uni_modules/lizhao-camera-pro'
import type {
AddImageWatermarkOptions, CameraImageOutputOptions,
CameraImageWatermarkResult, CameraWatermarkOptions
} from '@/uni_modules/lizhao-camera-pro'
function addTextWatermark(imagePath: string): void {
const watermarkOptions: CameraWatermarkOptions = {
enabled: true,
items: [{ id: 'note', type: 'text', text: '现场留存', anchor: 'bottomLeft' }]
}
const outputOptions: CameraImageOutputOptions = { target: 'cache', conflictPolicy: 'rename' }
const options: AddImageWatermarkOptions = {
imagePath, watermarkOptions, outputOptions,
success: (result: CameraImageWatermarkResult): void => {
console.log('新图片', result.uploadFilePath)
}
}
addImageWatermark(options)
}
| 参数 | 类型 | 必填 | 说明 | 默认值 |
|---|---|---|---|---|
| options | uni-app TS:AddImageWatermarkOptions;uni-app x App:AddImageWatermarkBridgeOptions | 是 | 图片水印参数对象,导入见上方示例 | 无 |
| imagePath | string | 是 | 业务可读的本地图片;支持文件路径、file://、运行期资源路径,Android 还支持已获读取权的 content://。不直接下载网络图片,不接受 ph:// 资产标识;先通过选择器取得本地文件 |
无 |
| watermarkOptions | CameraWatermarkOptions | 是 | 完整水印配置,文字与图片项沿用上表;要烧录需 enabled: true |
无 |
| referenceCanvas | CameraSize | 否 | watermarkOptions 坐标和尺寸对应的原相机输出画布;传入后对不同宽高比的外部图片保持组合水印等比,省略则按外部图片整图定位 |
无 |
| outputOptions | CameraImageOutputOptions | 否 | 本方法只创建新文件,字段见下表 | target: 'cache' |
| photoQuality | number | 否 | JPEG 质量,0~1;0 是有效值 | 0.92 |
| fallbackPolicy | string | 否 | nearest 跳过不支持或不可读的水印项并返回跳过清单;strict 返回失败 |
nearest |
| success | (result: CameraImageWatermarkResult) => void | 否 | 新图片输出完成且本地上传文件已检查可读 | 无 |
| fail | (error: CameraFail) => void | 否 | 使用已有错误码;无效参数、不可读图片、解码/渲染/保存失败均真实返回失败 | 无 |
| complete | function | 否 | 成功或失败后一次;即使业务 success/fail 抛出异常也独立派发 | 无 |
CameraImageOutputOptions:
| 参数 | 类型 | 说明 | 默认值 |
|---|---|---|---|
| target | string | cache / files / album / custom,与拍摄输出位置含义相同 |
cache |
| directory | string | custom 必填,应用已获写入权的目录 |
空字符串 |
| albumName | string | 系统相册名称,按平台保存规则处理 | 空字符串 |
| fileName | string | 新 JPEG 文件名 | 自动生成 |
| conflictPolicy | string | 只接受 rename / error;拒绝 overwrite,也不使用 keepOriginal |
rename |
此接口不创建相机会话,也不返回拍摄方向或镜头能力。HarmonyOS / Web / 小程序返回 9081003(平台不支持)。旧基座不包含新增原生入口,使用前必须重新打对应平台的原生包。
全屏 API
openCamera(options)
打开插件内置的原生全屏拍摄界面,不是系统相机选择器。默认继续使用经典界面;需要打开即用的完整拍摄产品时,显式选择 product。
uni-app x App:直接传对象可以自动推断;需要把参数保存为变量时,使用实际 App 入口的 OpenCameraBridgeOptions,成功和失败回调分别使用 CameraMediaResult、CameraFail。
import { openCamera } from '@/uni_modules/lizhao-camera-pro'
import type { OpenCameraBridgeOptions, CameraMediaResult, CameraFail } from '@/uni_modules/lizhao-camera-pro'
const options: OpenCameraBridgeOptions = {
mode: 'photo',
uiPreset: 'classic',
config: { fallbackPolicy: 'nearest', outputOptions: { target: 'cache' } },
success: (result: CameraMediaResult): void => { console.log('照片路径', result.uploadFilePath) },
fail: (error: CameraFail): void => { console.log('拍摄失败', error.errCode, error.errMsg) }
}
openCamera(options)
普通 uni-app TypeScript:表中的完整字段类型 OpenCameraOptions 按下面的方式导入;普通 JavaScript 页面删除 import type 和 : OpenCameraOptions 即可。
import { openCamera } from '@/uni_modules/lizhao-camera-pro'
import type { OpenCameraOptions } from '@/uni_modules/lizhao-camera-pro'
const options: OpenCameraOptions = {
mode: 'photo',
uiPreset: 'classic',
config: { fallbackPolicy: 'nearest', outputOptions: { target: 'cache' } }
}
openCamera(options)
| 参数 | 类型 | 必填 | 说明 | 默认值 | 可选参数 |
|---|---|---|---|---|---|
| options | uni-app TS:OpenCameraOptions;uni-app x App:OpenCameraBridgeOptions | 是 | 全屏相机参数对象,导入见上方示例 | 无 | 无 |
| options.uiPreset | string | 否 | 全屏界面样式 | classic |
classic / product |
| options.productOptions | ProductCameraOptions | 否 | 产品界面的模板、倒计时和项目地点 | 默认产品配置 | 仅 uiPreset='product' 时读取 |
| options.mode | string | 否 | 拍摄模式 | mixed |
photo / video / mixed |
| options.cameraPosition | string | 否 | 初始镜头 | back |
back / front / ultraWide |
| options.config | CameraRequestedConfig | 否 | 初始拍摄、输出和水印配置 | 默认配置 | 见常用拍摄配置 |
| options.tapToFocus | boolean | 否 | 是否启用点击对焦 | true |
true / false |
| options.pinchToZoom | boolean | 否 | 是否启用双指缩放 | true |
true / false |
| options.grid | string | 否 | 预览网格 | off |
off / 3x3 / 4x4 / phi |
| options.gridColor | string | 否 | 预览网格颜色;网格不会写入成片 | #80FFFFFF |
常用十六进制颜色 |
| options.vibrateOnCapture | boolean | 否 | 拍照成功或录像开始时是否振动 | false |
true / false |
| options.vibrateDurationMs | number | 否 | 请求振动时长;实际效果受设备能力影响 | 40 |
0~5000 |
| options.hardwareShutterEnabled | boolean | 否 | 是否启用硬件快门 | false |
true / false |
| options.backgroundBehavior | string | 否 | 录像进入后台后的处理方式 | finish |
finish / cancel |
| options.onOrientationChange | function | 否 | 相机运行期间设备真实持机方向变化时持续触发 | 无 | CameraOrientationChangeEvent |
| options.success | function | 否 | 用户完成照片或视频后触发 | 无 | 无 |
| options.fail | function | 否 | 权限、取消、拍摄或处理失败后触发 | 无 | 无 |
| options.complete | function | 否 | 成功或失败后触发一次 | 无 | 无 |
产品界面配置
三端产品界面顶部按设置、拍照/录像切换、倒计时、闪光灯和翻转排列,预览右侧提供倍率,底部快门保持居中;iOS、HarmonyOS 可从设置中退出相机,Android 支持系统返回。Android、iOS 底部依次提供相册、地点、快门、滤镜和水印;HarmonyOS 保持对应的共有控件位置,不显示尚未提供的相册导入和照片滤镜入口。mixed 默认进入拍照状态,录像或成片处理中会锁定模式切换;单一拍摄模式不显示模式切换入口。网格由 options.grid / options.gridColor 控制,只覆盖真实取景区域,不会重复绘制,也不会进入照片或视频。
内置模板如下;“通用参考套件”中的 28 个模板在 Android、iOS 与 HarmonyOS 共用同一套 ID、标题、排序和结构化字段。已有的“极简时间”“日期卡片”等历史模板继续保留,Android 还提供工程水印:
| 模板 ID | 名称 | 分类 |
|---|---|---|
minimal-time |
极简时间 | 通用 |
classic-time-location |
经典时间地点 | 工作 |
electronic-clock |
电子时钟 | 工作 |
date-card |
日期卡片 | 通用 |
field-note |
现场记录 | 工作 |
work-trace |
工作留痕 | 工作 |
meeting-note |
会议记录 | 工作 |
daily-moment |
今日片刻 | 生活 |
engineering-record |
工程记录(Android) | 工作 |
general-coordinates |
经纬度水印 | 通用参考套件 |
general-location |
地点水印 | 通用参考套件 |
general-calendar |
圆角日历 | 通用参考套件 |
general-mood |
心情水印 | 通用参考套件 |
general-weekday |
星期水印 | 通用参考套件 |
general-altitude |
海拔水印 | 通用参考套件 |
general-weather |
天气水印 | 通用参考套件 |
general-cute-weather |
可爱天气 | 通用参考套件 |
general-image-location |
图像地点 | 通用参考套件 |
general-simple-weather |
简单天气 | 通用参考套件 |
general-receipt |
票据水印 | 通用参考套件 |
general-round-seal |
圆形印章 | 通用参考套件 |
general-magazine |
杂志风 | 通用参考套件 |
general-news |
新闻风 | 通用参考套件 |
general-today-mood |
今日心情 | 通用参考套件 |
general-solar-term |
节气水印 | 通用参考套件 |
general-anniversary |
纪念日水印 | 通用参考套件 |
general-camera-time |
相机时间 | 通用参考套件 |
general-city-impression |
城市印象 | 通用参考套件 |
general-free-travel |
随心远行 | 通用参考套件 |
general-diary |
日记本 | 通用参考套件 |
general-love-location |
爱心地点 | 通用参考套件 |
general-text-quote |
文字水印 | 通用参考套件 |
general-contact-card |
联系名片 | 通用参考套件 |
general-meeting-clock |
会议时钟 | 通用参考套件 |
general-baby-diary |
宝宝日记 | 通用参考套件 |
general-birthday |
生日水印 | 通用参考套件 |
general-sunrise-clock |
日出时钟 | 通用参考套件 |
general-travel-card |
旅游实拍打卡 | 通用分类,Android / iOS |
三端水印抽屉统一使用紧凑分类栏和三列模板卡,按最近、工作、通用和生活分类选择,左侧可选择“无水印”,右侧箭头收起抽屉。字体样式从左上角“设置”进入;Android 设置还提供水印内容编辑,iOS 设置提供“旅游实拍打卡”的内容编辑。
Android 拍摄预览中可以拖动水印:工程卡整组移动,经纬度模板的坐标区和底部日期地点区可分别移动。松手确认后,本次打开相机期间会按模板保留位置;切换模板或编辑字段后继续使用该位置。抽屉展开时仅临时移开被遮挡的水印,收起后恢复原位;照片仍使用已确认的原位置。
iOS 内置相机的所有内置水印模板均可拖动:模板原有内容作为整张卡片移动,额外启用的地点条可单独移动;松手确认后按模板保留本次会话的位置,内容更新、拍照和录像继续使用已确认位置。
点击预览中的水印,可从底部展开全屏字段列表;也可从设置页进入水印内容。普通字段在独立页面编辑,支持取消和完成,地点进入独立选择页。字段可单独显示或隐藏,最外层点击“完成”后应用,返回取消本次草稿。编辑仅在本次打开相机期间生效。内置模板的日期、时间、月份和星期来自实际处理时间,只能控制显示,不能手动改成固定值;自定义模板的 {timestamp} 和 {recordingDuration} 同样自动更新,其余业务字段可编辑。未启用地点服务时,地点使用项目提供或手工输入的信息;天气、温度、空气质量、节气、纪念日、宝宝年龄、联系方式和日出时间等没有真实数据来源的字段不会自动生成,缺失时显示“未设置”或隐藏对应行。经纬度和海拔未设置时会明确显示“未设置”。
使用内置模板时不传 productOptions.templates;将 initialTemplateId 设置为 classic-time-location 即可直接打开该模板,演示页的“内置模板”默认使用它。显式传入模板(包括空数组)仍按原规则替换内置列表。
Android 和 iOS 的“旅游实拍打卡”使用相同的字段与布局规则,由原生绘制红色圆角主体、白色斜切标题、黄色行标和文字,无需准备水印图片。日期使用拍摄时间;从相机设置进入“水印内容”,可修改标题、拍摄人、地点,或调整“卡片圆角”(0~48,默认 18,0 为直角)。关闭圆角字段的显示开关也会使用直角;标题、日期、拍摄人和地点全部隐藏时不绘制卡片。长内容自动换行并增加高度。圆角值使用模板设计尺寸,随整体大小缩放;与相机预览的 cornerRadius 属性分别控制不同对象。系统字体的字形和测量由各平台决定。
两端均可点击这张卡片进入内容编辑,或拖动整张卡片调整位置。取消编辑不改变已确认内容,应用失败时保留草稿以便重试;字段值和位置在本次相机会话内保留。四项内容全部隐藏后,可从设置中的“水印内容”重新显示。
原图片水印示例的模块五提供 Android / iOS 共用的“旅游实拍打卡:打开相机”按钮,仍调用公开 openCamera,并沿用本页保存位置和保留原图设置。调用时使用 uiPreset: 'product'、productOptions.initialTemplateId: 'general-travel-card',不传 templates;可通过 productOptions.location.title 提供地点,通过 config.watermarkOptions.fields 的 title 和 photographer 提供初始标题和拍摄人,cardCornerRadius 可提供初始圆角值。
“经典时间地点”按参考水印相机的视觉层级显示:底部居中的大号 HH:mm,下一行显示 yyyy-MM-dd 星期 与项目提供的地点文本;地点没有配置时只保留日期星期,不生成虚假位置。该模板的两个文字项使用独立的 timestampFormat,自定义模板也可以复用这一能力。
“电子时钟”由浅色电子屏日期 yyyy.MM.dd、大号 HH:mm:ss、“记录这一刻”和地点四层组成。默认选择普通模板时只显示模板自身内容,不会再自动叠加独立地点条;经典时间地点和电子时钟直接在模板内部使用项目提供的地点。需要独立地点条时,仍可从产品相机的地点入口显式启用。
水印模板卡使用 4:3 画布展示模板实际的文字层级、字体、字重、颜色和位置,选择前即可判断大致效果;图片项会显示为安全占位框,不读取外部图片来生成缩略图。选中态会同时显示描边和文字状态,模板正在提交时会显示“应用中”。
选中包含文字的模板后,可从设置中的“水印样式”或“字体样式”进入编辑,按需调整字体、字号、字重和文字颜色。编辑只作用于当前模板的普通文字,不改变地点文字、文字内容、位置、背景或图片项;“恢复模板样式”可清除当前模板的本次编辑。
字体样式是本次 openCamera 打开期间的会话设置,关闭产品相机后不会保存。Android 在全屏样式页调整,返回取景后查看效果;iOS、HarmonyOS 使用字体样式面板预览调整。点击“完成”保留最新调整,点击“取消”恢复编辑前样式;应用失败会保留编辑内容供重试。需要固定默认字体时,请直接在 productOptions.templates[].watermarkOptions.items 中配置 fontFamily、fontSize、fontWeight 和 color。
ProductCameraOptions 可按需配置:
下面是普通 uni-app TypeScript 的类型导入和自定义模板示例。ProductCameraTemplate 是一个模板,ProductCameraLocation 是项目提供的地点文字,ProductCameraLocationService 是可选地点服务;这里保持定位服务关闭。
import { openCamera } from '@/uni_modules/lizhao-camera-pro'
import type {
ProductCameraOptions, ProductCameraTemplate,
ProductCameraLocation, ProductCameraLocationService
} from '@/uni_modules/lizhao-camera-pro'
const template: ProductCameraTemplate = {
id: 'business-note', title: '现场记录', category: 'work',
watermarkOptions: {
enabled: true,
items: [{ id: 'note', type: 'text', text: '现场记录', anchor: 'bottomLeft' }]
}
}
const location: ProductCameraLocation = { title: '项目现场', subtitle: '一号区域' }
const locationService: ProductCameraLocationService = {
provider: 'amap', enabled: false, privacyAgreed: false
}
const productOptions: ProductCameraOptions = {
templates: [template], initialTemplateId: template.id,
location, locationService, countdownSeconds: 0
}
openCamera({ mode: 'photo', uiPreset: 'product', productOptions })
uni-app x App 使用上方 OpenCameraBridgeOptions 写法,直接在 productOptions 中填写模板和地点对象即可,无需单独导入这些产品配置类型。只有项目已经配置高德服务并取得用户同意后,才启用地点服务,具体步骤见下方“高德定位和附近地点搜索”。
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
countdownSeconds |
number | 0 |
快门倒计时,只能是 0 / 3 / 5 / 10 |
templates |
ProductCameraTemplate[] | 内置模板 | 显式传入后替换内置模板;传 [] 时仅保留“无水印”和可能存在的当前水印配置 |
initialTemplateId |
string | 当前配置、最近选择或首个可用模板 | 初始选中模板;不存在时依次回退到当前水印配置、最近一次成功选择和首个可用模板,不会阻断打开相机 |
rememberLastTemplate |
boolean | true |
是否记住最近一次成功应用的模板;显式 false 会保留 |
location |
ProductCameraLocation | 不显示 | 项目传入的地点文字;可选 subtitle / x / y |
locationService |
ProductCameraLocationService | 不启用 | Android 产品界面高德定位和附近地点搜索,见下方配置 |
location.x、location.y 是 0 到 1 的归一化位置,默认分别为 0.04、0.86。只传 productOptions.location 时不申请定位权限。启用 locationService 后,也仅在打开位置页并满足同意条件时请求前台定位,不在打开相机时自动定位。
在相机内设置拍摄参数
左上角“设置”打开全屏配置页,可调整适用于当前设备的拍照、录像、镜头与画面、文件保存、提示音与振动、交互和水印选项。更改先保存在草稿中,完成后应用,失败时保留草稿供重试。录像、暂停或视频收尾时不能应用需要重新配置相机的设置。
只属于 uni-app x 标准组件的尺寸、会话标识和挂载控制仍在页面属性中设置。部分设备无法精确选择视频帧率、码率或声音处理,界面会显示设备决定或不支持;实际效果以设备返回值为准。
高德定位和附近地点搜索(Android)
位置页支持重新定位、附近地点列表、关键字搜索和自定义地点文字。搜索结果来自高德,列表展示地址和距离;手动输入会明确标识为自定义地点。定位被拒绝、系统定位关闭、网络异常或服务未配置时会显示原因,可重试或手动输入。
locationService 字段 |
类型 | 默认值 | 说明 |
|---|---|---|---|
provider |
string | 必填 | 当前为 amap |
enabled |
boolean | false |
允许在位置页使用定位与搜索 |
apiKey |
string | 宿主清单配置 | 高德 Android 平台 Key,须匹配应用包名和签名;不是 Web 服务 Key |
privacyAgreed |
boolean | false |
项目实际展示相关隐私说明且用户已同意后才传 true |
radius |
number | 1000 |
附近搜索半径,100~5000 米的整数 |
import { openCamera } from '@/uni_modules/lizhao-camera-pro'
// 在项目完成隐私说明和同意流程后调用。
// Key 从项目配置传入,不要把真实 Key 写进公开示例或可复制的测试日志。
function openWatermarkCamera(amapAndroidKey: string, hasPrivacyConsent: boolean) {
openCamera({
uiPreset: 'product', // 使用带设置、模板和地点选择的原生界面。
mode: 'mixed', // 上方图标可切换拍照与录像;录制过程中不可切换。
productOptions: {
initialTemplateId: 'engineering-record', // 不传 templates,保留内置模板。
locationService: {
provider: 'amap',
enabled: true, // 进入位置页才开始申请定位,不会打开相机就定位。
apiKey: amapAndroidKey, // 已在宿主清单配置 Key 时可省略这一行。
privacyAgreed: hasPrivacyConsent, // 传递真实同意结果,不要直接固定为 true。
radius: 1000 // 搜索附近 1 公里内的地点。
}
},
success(result) {
console.log('拍摄完成', result.path) // 最终照片或视频路径。
},
fail(error) {
console.log('拍摄未完成', error.errCode, error.errMsg)
}
})
}
启用 locationService 前,项目需在 manifest.json 中启用 Geolocation 的高德定位,完成 Android Key 配置和相应服务授权,并在实际隐私说明中说明该服务。Key 继续由项目统一配置,无需写入插件源码;未在调用参数中传入 apiKey 时,插件读取项目清单中的 Key。
插件复用项目提供的高德定位 SDK,仅补充附近地点搜索能力,不再打入第二份定位 SDK;现有 locationService 参数和调用方式不变。本功能不显示地图。iOS、HarmonyOS 暂不提供此位置搜索页。
每个自定义模板都必须提供非空且唯一的 id、非空 title、category 和对象型 watermarkOptions;首尾空格不参与 ID 唯一性判断。category 可用 work / general / life,watermarkOptions 复用完整水印配置,包括字体族、字重、图片水印、动态字段和成片烧录选项。自定义 watermarkOptions.items 不要把 __lizhao_product_location__ 用作 item.id,该标识专用于产品界面的地点项。地点对象必须提供非空 title,subtitle 可选,x / y 必须是范围内的数字。
下面的示例用一套项目模板替换内置模板,并明确初始选择:
import { openCamera } from '@/uni_modules/lizhao-camera-pro'
// 自定义模板示例:传 templates 会替换内置列表,不是向内置列表追加。
openCamera({
uiPreset: 'product',
mode: 'mixed', // 同一模板用于拍照与录像。
productOptions: {
countdownSeconds: 5, // 点击快门后倒计时 5 秒。
templates: [
{
id: 'inspection-card', // 模板唯一 ID,供 initialTemplateId 引用。
title: '巡检记录', // 模板选择卡片显示的名称。
category: 'work', // 归入工作分类;也可用 general / life。
watermarkOptions: {
enabled: true,
previewVisible: true,
burnIntoPhoto: true,
burnIntoVideo: true,
fields: { project: '桥梁巡检' }, // {project} 的业务值;{timestamp} 为内置时间。
items: [
{
id: 'inspection-title',
type: 'text',
text: '{project}\n{timestamp}',
anchor: 'bottomLeft',
fontFamily: 'sansSerif',
fontWeight: 'bold',
fontSize: 18, // 按输出短边 1080 设计单位换算,不是手机 sp。
color: '#FFFFFFFF', // #AARRGGBB:不透明白字。
backgroundColor: '#99050608',
padding: 8
}
]
}
}
],
initialTemplateId: 'inspection-card', // 与上面的模板 ID 一致。
rememberLastTemplate: false, // 每次按本次配置选择,不记住最近模板。
location: { title: 'A 区泵房', subtitle: '项目提供' } // 独立地点文字,不会自动定位。
},
success(result) {
// 拍照或录像完成后的最终媒体;watermarkApplied 表示是否实际写入水印。
console.log('拍摄完成', result.uploadFilePath, result.watermarkApplied)
},
fail(error) {
console.log('拍摄失败', error.errCode, error.stage)
},
complete(result) {
console.log('产品相机已结束', result)
}
})
Android、iOS 照片模式均提供原图、黑白、暖色、冷色和鲜明滤镜,可调整强度,照片预览与成片使用相同效果;水印保持自己的颜色。点击“完成”保留,返回恢复打开滤镜前的效果。录像模式使用原图,切回照片后恢复本次选择。
Android 相册入口通过系统选择图片,按图片比例展示当前水印和照片滤镜。点击“保存到相册”另存新图片,不修改选中的原图;取消选图或返回图片预览可继续拍摄。导入图片的日期水印使用本次导入处理时间。图片导入另存不触发相机拍照回调;openCamera 的原有拍照、录像结果回调保持原语义。
Android 设置中的照片尺寸来自当前镜头支持的尺寸,作用于下一次拍摄;“保留原图”在处理后的照片之外保留未加水印、未加滤镜的原图,拍照结果通过 originalPath / originalUri 返回。水印字体可以进入当前模板的字体样式配置。闪光灯按关闭、自动、开启循环,补光灯在设置面板中独立控制,最终显示以设备实际返回的 appliedConfig 为准。
现有项目无需改调用:省略 uiPreset,或显式传入 uiPreset: 'classic',都会继续打开原来的经典全屏界面。嵌入式 <lizhao-camera-pro> 不受产品模式影响。
getCameraCapabilities(options)
uni-app x App:从根目录导入 GetCameraCapabilitiesBridgeOptions,用 CameraCapabilities 接收结果;范围是 CameraNumberRange,照片尺寸列表是 CameraSize[]。
import { getCameraCapabilities } from '@/uni_modules/lizhao-camera-pro'
import type {
GetCameraCapabilitiesBridgeOptions, CameraCapabilities, CameraNumberRange, CameraSize
} from '@/uni_modules/lizhao-camera-pro'
const options: GetCameraCapabilitiesBridgeOptions = {
position: 'back',
success: (result: CameraCapabilities): void => {
const zoomRange: CameraNumberRange = result.zoomRange
const sizes: CameraSize[] = result.photoResolutions
console.log('缩放范围', zoomRange.min, zoomRange.max, '照片尺寸', sizes)
}
}
getCameraCapabilities(options)
普通 uni-app TypeScript 的完整参数类型导入:
import { getCameraCapabilities } from '@/uni_modules/lizhao-camera-pro'
import type { GetCameraCapabilitiesOptions } from '@/uni_modules/lizhao-camera-pro'
const options: GetCameraCapabilitiesOptions = {
position: 'back',
success: (result): void => { console.log('可用镜头', result.positions) }
}
getCameraCapabilities(options)
| 参数 | 类型 | 必填 | 说明 | 默认值 | 可选参数 |
|---|---|---|---|---|---|
| options | uni-app TS:GetCameraCapabilitiesOptions;uni-app x App:GetCameraCapabilitiesBridgeOptions | 是 | 查询参数对象,导入见上方示例 | 无 | 无 |
| options.position | string | 否 | 需要查询的镜头 | back |
back / front / ultraWide |
| options.success | function | 否 | 返回 CameraCapabilities |
无 | 无 |
| options.fail | function | 否 | 查询失败时触发 | 无 | 无 |
| options.complete | function | 否 | 查询结束时触发 | 无 | 无 |
position: 'back' 返回默认后摄自己的 zoomRange,不会合并独立超广角的倍率范围。min: 1 表示该镜头最小为 1×,不能据此判断整台设备没有超广角;可选择的超广角看 positions 是否包含 ultraWide,可再用 position: 'ultraWide' 查询,并核对返回的 position。超广角的 1× 也可能比主摄的 1× 视野更宽。没有 ultraWide 时,若当前后摄的 0 < zoomRange.min < 1,也可使用其真实最小倍率。完整判断与代码见 广角使用指南。
Android 根 API 的能力查询独立于预览,成功结果中的 ready: false 不表示查询失败,也不反映其他预览会话的就绪状态。查询结果通过 success / fail 判断;组件预览就绪应查看其 ready 事件和当前能力快照。
Android 优先使用独立超广角;没有独立候选时,也会检查系统公开的逻辑后摄物理成员,并依据有效的传感器尺寸与焦距识别更宽视场。选择物理成员后,预览、照片和录像统一路由到该镜头;变焦控制仍属于逻辑父相机,返回其真实范围,不人为改成 0.5×。设备未开放物理镜头或缺少可比较的视场信息时,不会猜测镜头 ID;输出尺寸等组合能否使用,还需以实际绑定结果和 nearest / strict 规则为准。
deleteCameraMedia(options)
uni-app x App:导入 DeleteCameraMediaBridgeOptions,从本次拍摄结果取回原路径;删除成功结果为 CameraDeleteMediaResult。请在用户点击删除并确认后调用。
import { deleteCameraMedia } from '@/uni_modules/lizhao-camera-pro'
import type {
DeleteCameraMediaBridgeOptions, CameraMediaResult, CameraDeleteMediaResult
} from '@/uni_modules/lizhao-camera-pro'
function deleteCapturedMedia(media: CameraMediaResult): void {
const options: DeleteCameraMediaBridgeOptions = {
path: media.path, uri: media.uri, albumIdentifier: media.albumIdentifier,
success: (result: CameraDeleteMediaResult): void => { console.log('删除完成', result.deleted) }
}
deleteCameraMedia(options)
}
普通 uni-app TypeScript 的完整参数类型导入:
import { deleteCameraMedia } from '@/uni_modules/lizhao-camera-pro'
import type { DeleteCameraMediaOptions, CameraMediaResult } from '@/uni_modules/lizhao-camera-pro'
function deleteCapturedMedia(media: CameraMediaResult): void {
const options: DeleteCameraMediaOptions = {
path: media.path, uri: media.uri, albumIdentifier: media.albumIdentifier
}
deleteCameraMedia(options)
}
| 参数 | 类型 | 必填 | 说明 | 默认值 | 可选参数 |
|---|---|---|---|---|---|
| options | uni-app TS:DeleteCameraMediaOptions;uni-app x App:DeleteCameraMediaBridgeOptions | 是 | 删除参数对象,导入见上方示例 | 无 | path / uri / albumIdentifier / success / fail / complete |
| options.path | string | 否 | 插件返回的文件路径 | 空字符串 | 无 |
| options.uri | string | 否 | 插件返回的媒体 URI | 空字符串 | 无 |
| options.albumIdentifier | string | 否 | 插件返回的相册资产标识 | 空字符串 | 无 |
| options.success | function | 否 | 删除成功时触发 | 无 | 无 |
| options.fail | function | 否 | 删除失败时触发 | 无 | 无 |
| options.complete | function | 否 | 删除结束时触发 | 无 | 无 |
path、uri、albumIdentifier 至少应提供一个,推荐直接传回拍摄结果中的原值。
主要返回值
CameraImageWatermarkResult
| 字段 | 类型 | 说明 |
|---|---|---|
| path / uri | string | 新图片公开路径或相册标识;用于识别结果与后续删除 |
| uploadFilePath | string | 已验证可读的非空本地文件地址,可交给 uni.uploadFile 的 filePath 或本地图片预览;不是服务器地址 |
| width / height | number | 方向归正及受限缩放后的实际像素尺寸 |
| fileName / sizeBytes / mimeType | string / number / string | 输出文件名、JPEG 字节数、固定 image/jpeg |
| savedToAlbum / albumIdentifier | boolean / string | 是否写入系统相册及相册标识;未保存相册时标识为空 |
| watermarkApplied | boolean | 是否实际烧录水印;检查跳过项以判断是否完整应用 |
| skippedWatermarkItemIds | string[] | 被跳过的水印项 ID |
| skippedWatermarkFieldKeys | string[] | 未能替换的业务字段键 |
| createdAt | number | 本次图片处理开始时间,毫秒时间戳 |
只删除本次输出时,将结果的 path / uri / albumIdentifier 传给现有 deleteCameraMedia()。输入原图不属于本次输出,不能用其地址代替结果;插件的媒体归属检查保持不变。
CameraMediaResult
| 字段 | 类型 | 说明 |
|---|---|---|
| mediaType | string | photo 或 video |
| path | string | 可访问的本地文件地址;iOS 返回标准 file:// URL,只有 URI 时为空字符串 |
| uri | string | 文件、媒体库或相册 URI;只有 path 时可为空字符串 |
| uploadFilePath | string | 照片/视频最终成片的统一上传地址,成功结果保证非空;可直接传给 uni.uploadFile.filePath。iOS Photos 返回最长保留 24 小时的插件临时副本,应及时上传且不可长期持久化 |
| originalPath / originalUri | string | keepOriginal=true 且产生双输出时的无水印媒体;iOS 的 path 字段为标准 file:// URL |
| watermarkedPath / watermarkedUri | string | 实际烧录水印后的媒体;iOS 的 path 字段为标准 file:// URL |
| width / height | number | 最终可读媒体尺寸 |
| durationMs | number | 视频逻辑时长;照片为零 |
| sizeBytes | number | 最终媒体字节数 |
| mimeType | string | 真实 MIME 类型 |
| fileName | string | 最终文件名 |
| savedToAlbum | boolean | 是否保存到系统相册 |
| albumIdentifier | string | 系统相册资产标识;不适用时为空字符串 |
| cameraPosition | string | 最终使用的镜头 |
| watermarkApplied | boolean | 是否实际烧录水印 |
| requestedConfig | CameraRequestedConfig | 本次请求配置 |
| appliedConfig | CameraAppliedConfig | 设备和平台真实生效配置 |
| createdAt | number | 创建时间戳,单位毫秒 |
CameraAppliedConfig 常用字段
返回值由插件提供,放在真实成功回调中读取即可。例如,CameraRequestedConfig 是请求配置,CameraAppliedConfig 是本次拍摄真正生效的配置:
import { openCamera } from '@/uni_modules/lizhao-camera-pro'
import type {
CameraMediaResult, CameraRequestedConfig, CameraAppliedConfig, CameraSize
} from '@/uni_modules/lizhao-camera-pro'
openCamera({
mode: 'photo', uiPreset: 'classic',
success: (result: CameraMediaResult): void => {
const requested: CameraRequestedConfig = result.requestedConfig
const applied: CameraAppliedConfig = result.appliedConfig
const size: CameraSize = applied.photoResolution
console.log('请求方向', requested.orientation, '实际照片尺寸', size.width, size.height)
}
})
| 字段 | 类型 | 说明 |
|---|---|---|
| position | string | 实际使用的镜头 |
| orientation / aspectRatio / fallbackPolicy | string | 本次输出方向、宽高比和能力处理策略 |
| photoCropMode | string | 2.1.4 新增,本次照片的实际裁剪模式;旧版本结果可缺省 |
| photoResolution | CameraSize | 最终照片输出尺寸 |
| photoQuality / photoFormat | number / string | 照片压缩质量和格式 |
| captureSourceResolution | CameraSize | 原生拍照采集源尺寸;通过 result.appliedConfig.captureSourceResolution 读取 |
| videoWidth / videoHeight | number | 实际视频宽高 |
| videoQuality | string | 实际录像档位 |
| videoBitrate / videoFrameRate | number | 实际码率和帧率 |
| outputFormat | string | 实际视频容器 |
| recordAudio | boolean | 是否实际录制声音 |
| echoCancellation / noiseSuppression / autoGainControl | boolean | 能确认已应用的音频处理;不直接沿用请求值判断 |
| maxDurationMs | number | 最大录像时长,单位毫秒;0 表示手动停止 |
| flashMode / zoomRatio / exposureCompensation | 对应类型 | 实际应用的画面控制值 |
| whiteBalance / hdr | 对应类型 | 实际白平衡和 HDR 请求结果 |
| outputTarget | string | 实际输出目标 |
| watermarkEnabled | boolean | 水印是否实际启用 |
| fallbackReasons | string[] | 请求配置未被精确满足的原因 |
| skippedWatermarkItemIds | string[] | 被跳过的无效或不可读取水印项 |
| skippedWatermarkFieldKeys | string[] | 被跳过的缺失占位符键 |
CameraCapabilities 常用字段
| 字段 | 类型 | 说明 |
|---|---|---|
| ready | boolean | 是否已具备当前镜头完整能力;组件未就绪时可为 false |
| buildTag | string | 当前原生构建标识,反馈问题时可随诊断信息提供 |
| position | string | 这份能力对应的当前镜头 |
| positions | string[] | 设备可用镜头 |
| zoomRange | CameraNumberRange | 缩放最小值、最大值和步长 |
| exposureCompensationRange | CameraNumberRange | 曝光补偿范围 |
| flashSupported / torchSupported / focusSupported | boolean | 闪光灯、补光灯和对焦能力 |
| hdrSupported | boolean | 当前镜头是否报告 HDR 能力 |
| whiteBalanceModes | string[] | 可用白平衡模式 |
| photoResolutions / videoResolutions | CameraSize[] | 可用照片和视频尺寸 |
| videoQualities / videoFrameRates / videoFormats | array | 可用录像档位、帧率和容器 |
| pauseResumeSupported | boolean | 是否支持录像暂停恢复 |
| switchCameraWhileRecordingSupported | boolean | 是否支持录像中切镜并合并 |
| recordAudioSupported | boolean | 是否支持麦克风录像 |
| echoCancellationSupported | boolean | 是否能确认系统回声消除生效 |
| noiseSuppressionSupported | boolean | 是否能确认系统降噪生效 |
| autoGainControlSupported | boolean | 是否能确认系统自动增益生效 |
CameraSize 的 width / height 单位为像素。CameraNumberRange 的 min / max 表示最小值与最大值,step 表示步长;例如曝光范围 { min: -2, max: 2, step: 1 } 可选择 -2、-1、0、1、2。构建滑块时先判断范围是否可调,不能把无效或为零的步长拿来做除法。
曝光值和步长使用同一单位:Android 使用整数补偿档位(支持时步长为 1),iOS 使用 EV;设置值应落在当前 exposureCompensationRange 范围和步长上。切换镜头后重新读取能力,不要固定使用某个机型的范围。
打开预览和开始录像的结果
| 结果类型 | 返回字段 | 使用时机 |
|---|---|---|
CameraReadyResult |
sessionId / generation / state / requestedConfig / appliedConfig / capabilities |
组件 open.success 返回,表示会话已就绪;不是照片结果。 |
CameraRecordingStartResult |
sessionId / generation / recordingId / appliedConfig |
组件 startRecording.success 返回,用 recordingId 对应后续录像事件;此时没有最终视频文件。 |
CameraDeleteMediaResult
| 字段 | 类型 | 说明 |
|---|---|---|
| deleted | boolean | 是否删除成功 |
| path | string | 被删除的路径;不适用时为空字符串 |
| uri | string | 被删除的 URI;不适用时为空字符串 |
| albumIdentifier | string | 被删除的相册资产标识;不适用时为空字符串 |
事件
以下 16 个事件只由 uni-app x 标准组件触发,其中 watermarkchange 为 Android / iOS 新增。openCamera() 不触发这些组件事件,但可通过 onOrientationChange 接收同一方向负载;最终媒体仍通过 success / fail / complete 返回。
| 事件 | 返回类型 | 说明 |
|---|---|---|
| ready | CameraReadyEvent | 原生相机会话已运行,返回请求配置、实际配置和当前能力 |
| statechange | CameraStateChangeEvent | opening、previewing、capturing、recording、paused、switching、finalizing 等状态变化 |
| orientationchange | CameraOrientationChangeEvent | 真实持机方向变化;ready 后先发送一次当前方向,按角度和可靠性去重 |
| photo | CameraPhotoEvent | 照片已经可以读取并完成交付 |
| recordstart | CameraRecordStartEvent | 第一段录像收到原生真实开始回调 |
| recordprogress | CameraRecordProgressEvent | 约每 250ms 返回逻辑录像时长,不含暂停时间 |
| recordpause | CameraRecordPauseEvent | 当前片段已结束并进入暂停 |
| recordresume | CameraRecordResumeEvent | 新片段已真实开始 |
| recordfinished | CameraRecordFinishedEvent | 合并、水印、保存和结果检查完成后的最终视频 |
| finalizeprogress | CameraFinalizeProgressEvent | merge / watermark / save / complete 阶段及 0~100 进度 |
| camerachange | CameraChangeEvent | 镜头切换已完成;录像中在新片段真实开始后触发 |
| focuschange | CameraFocusChangeEvent | 对焦状态和归一化坐标 |
| zoomchange | CameraZoomChangeEvent | 请求倍率与实际倍率 |
| capabilitieschange | CameraCapabilitiesChangeEvent | 镜头或配置变化后的真实能力 |
| error | CameraErrorEvent | 统一 CameraFail;可根据 stage 与 retryable 判断是否重试 |
| watermarkchange | CameraWatermarkChangeEvent | 拖动位置已提交,返回完整水印配置;不会逐帧发送 |
标准组件为兼容事件消费方式,同时提供顶层字段和 detail;uni-app x 强类型示例直接读取顶层字段,也可用 event.detail ?? event 解包。
事件处理函数也要导入参数类型。ready / photo / recordfinished / error / orientationchange 的完整写法见模块一,录像进度、暂停、恢复和状态处理见对应业务模块;下面补充录像开始、对焦、缩放和能力更新:
<template>
<lizhao-camera-pro
style="width: 100%; height: 900rpx;"
:auto-start="true"
@recordstart="onRecordStart"
@focuschange="onFocusChange"
@zoomchange="onZoomChange"
@capabilitieschange="onCapabilitiesChange"
/>
</template>
<script setup lang="uts">
import type {
CameraRecordStartEvent, CameraFocusChangeEvent,
CameraZoomChangeEvent, CameraCapabilitiesChangeEvent
} from '@/uni_modules/lizhao-camera-pro'
function onRecordStart(event: CameraRecordStartEvent): void {
console.log('录像开始', event.recordingId)
}
function onFocusChange(event: CameraFocusChangeEvent): void {
console.log('对焦状态', event.state, event.x, event.y)
}
function onZoomChange(event: CameraZoomChangeEvent): void {
console.log('实际缩放倍率', event.appliedRatio)
}
function onCapabilitiesChange(event: CameraCapabilitiesChangeEvent): void {
console.log('当前能力', event.capabilities.positions)
}
</script>
事件数据怎么读取
所有组件事件都带 sessionId(相机会话标识)、generation(本次会话代次)和 timestamp(毫秒时间戳)。重新打开相机后,应以新事件为准,避免用旧会话的异步结果更新当前页面。下面字段位于事件顶层,并在 detail 中保留同一份兼容载荷:
| 事件 | 除公共字段外的完整字段 | 说明 |
|---|---|---|
ready |
state / requestedConfig / appliedConfig / capabilities |
用真实配置和能力初始化界面。 |
statechange |
previousState / state / reason |
上一个状态、当前状态和变化原因。 |
orientationchange |
orientation / rotation / isLandscape / reliable |
见下方方向事件表。 |
photo |
result |
CameraMediaResult,与本次拍照成功回调对应同一份媒体。 |
recordstart |
recordingId / appliedConfig |
本次逻辑录像已经开始。 |
recordprogress |
recordingId / durationMs / maxDurationMs / segmentCount |
累计录制毫秒数、上限和片段数;不是最终处理进度。 |
recordpause / recordresume |
recordingId / durationMs |
当前录像标识和累计录制时长。 |
recordfinished |
recordingId / result |
最终视频及其所属录像。 |
finalizeprogress |
recordingId / stage / progress |
当前处理阶段和阶段内百分比;切换阶段后进度可能重新从较小值开始。 |
camerachange |
previousPosition / position / requestedConfig / appliedConfig |
切换前后镜头与本次配置;不能只看请求镜头判断切换成功。 |
focuschange |
state / x / y |
started / focused / failed / cancelled,坐标范围为 0~1。 |
zoomchange |
requestedRatio / appliedRatio |
显示倍率使用实际值 appliedRatio。 |
capabilitieschange |
capabilities |
更新缩放、曝光和镜头选项。 |
error |
error |
内层对象才是 CameraFail,例如 payload.error.errCode。 |
watermarkchange |
source / changedItemIds / watermarkOptions |
source 固定为 drag,ID 数组标识本次移动项,配置可保存并用于后续拍摄。 |
会话状态包括 idle(空闲)、opening(打开中)、previewing(预览中)、capturing(拍照中)、recording(录像中)、paused(已暂停)、switching(切镜中)、finalizing(处理成片中)、closing(关闭中)、released(已释放)和 error(错误)。页面按钮应根据状态开放;特别是 finalizing 时不要把进度更新当作可开始下一次拍摄的信号。
CameraOrientationChangeEvent
| 字段 | 类型 | 说明 |
|---|---|---|
| sessionId | string | 当前相机会话标识 |
| generation | number | 当前相机会话代次 |
| timestamp | number | 事件时间戳,单位毫秒 |
| orientation | string | portrait、portraitUpsideDown、landscapeLeft 或 landscapeRight |
| rotation | number | 页面顺时针旋转建议角度:竖屏 0、左横屏 90、倒竖屏 180、右横屏 270 |
| isLandscape | boolean | 当前方向是否为横屏 |
| reliable | boolean | 是否已取得当前传感器可靠读数;false 表示暂用显示方向兜底 |
支持平台
| 平台 | 是否支持 | 说明 |
|---|---|---|
| App Android | 支持 | uni-app 支持拍摄、能力查询、删除及已有图片水印 API;uni-app x 还支持 VDOM / Vapor 标准组件与水印拖动。Android 需 6.0 及以上。 |
| App iOS | 支持 | uni-app 支持拍摄、能力查询、删除及已有图片水印 API;uni-app x 还支持 VDOM / Vapor 标准组件与水印拖动。 |
| App Harmony | 支持已有能力 | uni-app 可使用拍摄、能力查询、删除三个根 API;uni-app x 标准组件需 HBuilderX 5.26 及以上。视频输出使用 MP4;本次不支持独立图片水印 API 和通用水印拖动。 |
| Web / H5 | 不支持 | 返回明确的平台不支持错误,不伪造拍摄结果。 |
| 各类小程序 | 不支持 | 不使用小程序相机组件做静默降级。 |
同一套 App 业务可以先调用 getCameraCapabilities(),再根据 positions、pauseResumeSupported、switchCameraWhileRecordingSupported、recordAudioSupported 等字段决定显示哪些按钮。镜头、暂停恢复和录像切镜等能力始终以当前设备查询结果为准。
错误码
| 错误码 | 含义 | 说明 |
|---|---|---|
| 9081001 | 参数无效 | 类型、枚举、范围或 JSON 不合法 |
| 9081002 | 权限被拒绝 | 相机或按需麦克风权限不可用 |
| 9081003 | 相机不可用 | 平台、设备或目标镜头不可用 |
| 9081004 | 状态不允许 | 当前会话正在拍摄、切换、处理或已经释放 |
| 9081005 | 打开失败 | 原生会话、输入、输出或宿主创建失败 |
| 9081006 | 拍照失败 | 拍照、解码、方向处理或结果检查失败 |
| 9081007 | 录像失败 | 原生片段开始、写入或结束失败 |
| 9081008 | 媒体处理失败 | 合并、水印、方向统一、转码或结果协议失败 |
| 9081009 | 媒体写入失败 | 文件或系统相册保存事务失败 |
| 9081010 | 能力不支持 | strict 下请求无法精确满足 |
| 9081011 | 删除失败 | 目标不存在、不是插件归属媒体或系统删除失败 |
| 9081012 | 自定义位置不可访问 | custom 位置不受当前平台支持、不可写或未授权 |
| 9081013 | 用户取消 | 用户关闭、生命周期取消或交付被撤销 |
| 9081014 | 操作超时 | 原生步骤超过允许时间 |
| 9081015 | 存储不足 | 可用空间或安全像素预算不足 |
CameraFail 还包含 errSubject、errMsg、stage、retryable、sessionId、generation 和精简的 nativeMessage,可用于区分权限、打开、拍照、录像、合并、水印、保存或删除阶段。
常见问题
第一次接入应该先测试什么?
先运行“快速开始”中的 openCamera({ mode: 'photo' }),确认能够打开、拍照并从 success 获得非空 uploadFilePath。成功后再接入录像、水印和自定义目录;uni-app x 项目再继续接入标准组件。
为什么相机打不开或没有预览?
先确认当前安装包包含插件原生代码,再检查相机权限,并查看 fail 或标准组件 error 中的 errCode、stage。标准组件应等到 ready 后再允许拍摄。
为什么录像没有声音?
确认 recordAudio=true、麦克风权限已经授予,并检查 capabilities.recordAudioSupported。回声消除、降噪和自动增益只是请求项,是否真实生效还要看 appliedConfig 和能力字段;Harmony 当前不能独立确认这三项生效,对应能力字段返回 false。
startRecording.success 已执行,为什么还没有视频文件?
该回调只表示录像已经真实开始。调用 stopRecording() 后仍要等待合并、水印和保存,最终文件从 recordfinished.result 获取。
暂停、恢复或切镜为什么提示状态不允许?
这些操作属于异步状态机。应等待 recordpause、recordresume、camerachange 等事件后再开放下一步按钮,不能在同一段代码中连续立即调用。
为什么请求的分辨率或帧率没有完全生效?
nearest 会自动选择设备最接近的能力。比较 requestedConfig 和 appliedConfig,并查看 fallbackReasons;业务必须完全匹配时使用 strict。
keepOriginal 为什么有时生成一份、有时生成两份媒体?
只有水印确实烧录且 keepOriginal=true 时才保存无水印原片和水印成片两份;关闭水印或没有实际烧录时只保存一份。
水印为什么只在预览出现,成片中没有?
检查 enabled、burnIntoPhoto、burnIntoVideo。图片路径不可读或占位符缺失时,还应查看 appliedConfig.skippedWatermarkItemIds 和 skippedWatermarkFieldKeys。
保存到相册为什么会申请权限或出现确认界面?
写入或删除系统相册属于平台受保护操作,插件会在实际需要时遵循系统授权与确认流程;保存到 cache 或 files 不等同于写入系统相册。
iOS 请求 MP4 为什么需要等待处理?
iOS 原生录像片段可能先生成 MOV,请求 MP4 时会在停止后进入转换、合并、水印和保存流程。监听 finalizeprogress,最终文件以 recordfinished 或 openCamera.success 为准。
Harmony 请求 MOV 为什么得到 MP4 或失败?
Harmony 视频输出使用 MP4。使用 nearest 时会降级为 MP4,并把原因写入 fallbackReasons;使用 strict 时返回 9081010。
前置预览正常,保存的照片为什么方向或镜像不同?
mirrorPreview 和 mirrorOutput 是两个独立配置:前者只控制前摄屏幕预览,后者控制最终输出。输出方向还应查看 orientation 和 appliedConfig。iOS 预设水印锚点固定在可见预览的对应位置;custom 使用输出坐标,在预览与输出镜像不同时会转换显示位置。拖动后请保存 watermarkchange 返回的完整配置。
页面离开时应该调用 close() 还是 destroyCamera()?
只是临时隐藏并准备再次打开时使用 close();页面卸载或不再使用该实例时调用 destroyCamera()。
custom 目录为什么无法保存或覆盖?
directory 必须是当前平台支持的应用可写目录,fileName 不能带路径分隔符。Harmony 只接受可写绝对目录或可解析的 file:// 目录,不支持任意 content:// 或 datashare:// URI。普通场景优先使用 rename;overwrite 只覆盖插件能够确认归属的同名媒体。
删除媒体为什么返回 9081011?
常见原因是目标不存在、没有原样传回插件返回的标识、目标不是插件能够确认归属的媒体,或系统拒绝删除相册资产。
注意事项
- 首次打开会申请相机权限;只有需要录音时才按需申请麦克风权限;保存或删除系统相册媒体时遵循平台实际授权与确认流程。
- Harmony 保存照片或视频可使用系统保存弹窗;删除或覆盖相册媒体另需写相册权限,应用须具备系统要求的相册管理授权。未取得授权时返回删除失败,已保存的媒体会保留。
nearest会选择设备可用的最接近配置,并在appliedConfig.fallbackReasons中说明原因;strict无法精确满足时返回9081010。- Android 和 Harmony 通常输出 MP4;iOS 原生录像片段通常先写为 MOV,请求 MP4 时在最终处理阶段转换。最终容器和 MIME 以结果为准。
- Harmony 最终视频统一为 8 位 SDR MP4,包括
keepOriginal产生的无水印副本;hdr=true只是请求设备进行 HDR 采集,不表示最终文件为 HDR10。MOV 请求仍按nearest / strict处理。 - Harmony 的手动白平衡需要 API 20,录像原生镜像需要 API 15;低版本以及超广角、补光、录像切镜等能力均按设备查询结果和
nearest / strict规则降级或失败。 - Harmony 当前不能独立确认回声消除、降噪和自动增益开关,相关能力字段返回
false;不要仅凭请求参数判断已生效。 custom.directory必须是当前平台支持的应用可写位置。Harmony 仅支持可写绝对目录或可解析的file://目录,不支持任意content://或datashare://URI。插件不会自行扩大目录权限,也不会覆盖无法确认归属的项目文件。overwrite只覆盖插件能够确认归属的同名媒体。系统相册保存或删除可能出现授权/确认,失败回调不代表相册中一定没有产生任何媒体,应以系统结果和插件返回标识为准。- 暂停、恢复、切镜和最终处理均为异步状态机。按钮应依据
statechange、recordstart、recordpause、recordresume、camerachange和finalizeprogress控制,避免重复提交。 - 更新 iOS 原生实现后,请重新制作匹配源码的自定义基座或重新打包 App,再验证切镜、拍照和水印效果。
- 页面卸载时调用
destroyCamera();只是暂时关闭并准备复用时调用close()。 - 示例中的
custom路径必须替换为项目真实获得的可写位置。
作者系列 UTS 插件
以下为已在 DCloud 插件市场上架的作者系列 UTS 插件,可按业务场景组合使用。未列出的插件表示当前未确认公开市场页,后续上架后再补充。
| 插件 | 能力方向 | 插件市场 |
|---|---|---|
lizhao-nfc-pro |
NFC 标签读写、NDEF、IsoDep 与诊断 | 查看插件 |
lizhao-float-window |
悬浮窗、画中画、权限与诊断 | 查看插件 |
lizhao-device-id |
设备标识、隐私策略与诊断 | 查看插件 |
lizhao-scan-pro |
原生扫码、连续扫码、相册识别 | 查看插件 |
lizhao-choose-file |
原生文件选择、上传、进度与取消 | 查看插件 |
lizhao-bg-audio |
背景音频播放、队列、倍速与事件 | 查看插件 |
lizhao-smart-tts |
系统 TTS、云端合成、听书方案 | 查看插件 |
lizhao-share-plus |
系统分享、远程文件下载后分享 | 查看插件 |
lizhao-sqlite-pro |
原生 SQLite、迁移、备份与诊断 | 查看插件 |
lizhao-icon-pro |
SVG 图标组件、多主题与缓存 | 查看插件 |
lizhao-cast-screen |
DLNA 投屏、AirPlay 路由入口 | 查看插件 |
lizhao-call-kit |
电话、短信、通讯录原生能力 | 查看插件 |
lizhao-app-keepalive |
应用保活、唤醒、自愈与报告 | 查看插件 |
lizhao-doc-corrector |
文档扫描、矫正、增强与识别 | 查看插件 |
lizhao-emu-detect |
模拟器环境检测、风险评分与证据 | 查看插件 |
lizhao-gallery-pro |
相册媒体分页、筛选、缩略图与导出 | 查看插件 |
lizhao-video-thumb |
视频封面、批量取帧与 Base64 返回 | 查看插件 |
lizhao-ble |
BLE 扫描、连接、读写、通知与自动重连 | 查看插件 |
lizhao-sse-pro |
SSE、Line、JSONL 与 Raw 流式请求 | 查看插件 |
lizhao-pdf-pro |
PDF 阅读、签批、真实写回与页面处理 | 查看插件 |
lizhao-serial-port |
路径串口、USB 串口、多会话收发与诊断 | 查看插件 |
lizhao-wechat-kit |
微信登录、分享、支付、小程序与客服 | 查看插件 |
lizhao-video-editor |
视频裁剪、压缩、取帧与 FFmpeg/FFprobe | 查看插件 |
lizhao-vpn-pro |
企业 VPN、IKEv2、安全接入与脱敏诊断 | 查看插件 |
lizhao-camera-pro |
原生相机、拍照录像、水印与媒体保存 | 查看插件 |
lizhao-tcp-pro |
TCP 客户端、服务端、多连接与诊断 | 查看插件 |
lizhao-notify-pro |
本地通知、点击动作、进度与定时提醒 | 查看插件 |

收藏人数:
购买源码授权版(
试用
赞赏(0)
下载 6486
赞赏 5
下载 12687259
赞赏 1956
赞赏
京公网安备:11010802035340号