更新记录

1.0.5(2024-05-10)

1.0.5版本更新内容 1.设置预览比例和图片输出比例一致(修复部分手机预览比例和拍照结果比例不一致问题) 2.自定义文件路径通知相册更新方法,文件需要可读路径 3.新增预览大小与输出图片大小一致

1.0.4(2024-04-10)

1.0.4版本更新内容 1.处理云打包失败 2.cameraX版本使用到1.1.0,版本过高对并编译版本有限制 3.目标版本 targetSdkVersion=33 4.编译版本 compileSdkVersion=33

1.0.3(2024-04-07)

1.0.3版本更新内容 1.cameraX版本升级到1.3.2 2.拍照,录像完善错误提示 3.提高项目编译版本 targetSdkVersion=33 4.相机预览组件在页面退出时销毁 5.暴露组件手动销毁方法

查看更多

平台兼容性

Android Android CPU类型 iOS
适用版本区间:5.0 - 14.0 armeabi-v7a:支持,arm64-v8a:支持,x86:支持 ×

原生插件通用使用流程:

  1. 购买插件,选择该插件绑定的项目。
  2. 在HBuilderX里找到项目,在manifest的app原生插件配置中勾选模块,如需要填写参数则参考插件作者的文档添加。
  3. 根据插件作者的提供的文档开发代码,在代码中引用插件,调用插件功能。
  4. 打包自定义基座,选择插件,得到自定义基座,然后运行时选择自定义基座,进行log输出测试。
  5. 开发完毕后正式云打包

付费原生插件目前不支持离线打包。
Android 离线打包原生插件另见文档 https://nativesupport.dcloud.net.cn/NativePlugin/offline_package/android
iOS 离线打包原生插件另见文档 https://nativesupport.dcloud.net.cn/NativePlugin/offline_package/ios

注意事项:使用HBuilderX2.7.14以下版本,如果同一插件且同一appid下购买并绑定了多个包名,提交云打包界面提示包名绑定不一致时,需要在HBuilderX项目中manifest.json->“App原生插件配置”->”云端插件“列表中删除该插件重新选择


UniComponent - 完全界面自定义相机预览,拍照,录像,各种原生操作按钮,集成设置分辨率,视频质量

插件说明

1.0.0
1.完全界面自定义相机预览,拍照,录像,各种原生操作按钮,集成设置分辨率,视频质量
2.自定义视频质量480P/720P/1080P/2160p,图片比例-4:3/16:9

1.0.1
1.增加图片旋转,镜像处理方法
2.适配图片可能出现的旋转和前置摄像头的可能镜像情况
3.完全自定义边缘识别,图片随意拖动剪切,可单独/配合使用

1.0.2版本更新内容
1.录制视频切出去时关闭录制,功能参照系统相机录像功能
2.切出去:退出页面、切回桌面

1.0.3版本更新内容
1.cameraX版本升级到1.3.2
2.拍照,录像完善错误提示
3.提高项目编译版本 targetSdkVersion=33
4.相机预览组件在页面退出时销毁
5.暴露组件手动销毁方法

1.0.4版本更新内容
1.处理云打包失败
2.cameraX版本使用到1.1.0,版本过高对并编译版本有限制 
3.目标版本 targetSdkVersion=33
4.编译版本 compileSdkVersion=33

1.0.5版本更新内容
1.设置预览比例和图片输出比例一致(修复部分手机预览比例和拍照结果比例不一致问题)
2.自定义文件路径通知相册更新方法,文件需要可读路径
3.新增预览大小与输出图片大小一致
4.权限新增 android.permission.MANAGE_EXTERNAL_STORAGE ,兼容高版本手机文件权限

插件支持

目前UniComponent插件只支持.nvue文件

插件引入

1.下载或购买云插件
2.项目manifest.json -> App原生插件配置 -> 云端插件[选择云端插件]
3.使用云插件后,项目引入组件即可使用

插件使用demo

<!-- 拍照预览,边缘识别,图片剪切 -->
<template>
    <view>
        <view style="overflow-y: scroll;">
            <text style="font-size:30rpx;word-wrap:break-word;">
                完全界面自定义相机预览,拍照,录像,各种原生操作按钮,集成设置分辨率,视频质量
            </text>
            <text style="font-size:30rpx;word-wrap:break-word;">
                增加图片旋转,镜像处理方法,适配图片可能出现的旋转和前置摄像头的可能镜像情况
            </text>
            <text style="font-size:30rpx;word-wrap:break-word;">
                自定义视频质量480P/720P/1080P/2160p,图片比例-4:3/16:9
            </text>
            <text style="font-size:30rpx;word-wrap:break-word;">
                完全自定义边缘识别,图片随意剪切,可单独使用,可配合使用
            </text>

            <!-- 拍摄预览组件 -->
            <CustomPreview ref="CustomPreview" style="width:100%;height:200px;background-color: antiquewhite;">
            </CustomPreview>

            <button @click="unbindCamera()">销毁预览(v1.0.3)</button>
            <button @click="switchCamera()">切换摄像头</button>
            <button @click="takePhoto()">拍照</button>
            <button @click="startVideo()">开始录像</button>
            <button @click="pauseVideo()">暂停录像</button>
            <button @click="resumeVideo()">继续录像</button>
            <button @click="stopVideo()">停止录像</button>
            <button @click="switchTorch()">打开或关闭手电筒</button>
            <button @click="switchFlashMode()">打开或关闭闪光灯</button>
            <button @click="hasBackCamera()">返回是否有后置摄像头</button>
            <button @click="hasFrontCamera()">返回是否有前置摄像头</button>
            <button @click="imageRotate(filePath,90)">旋转图片</button>
            <button @click="imageMirror(filePath,true,false)">镜像图片</button>
            <button @click="notifyAlbum()">通知相册</button>

            <!-- 剪切预览组件 -->
            <CustomCrop ref="CustomCrop" style="width:100%;height:200px;background-color: antiquewhite;">
            </CustomCrop>

            <button @click="confirmCrop()">确定剪切</button>
            <button @click="cancelCrop()">取消剪切</button>

        </view>
    </view>
</template>

<script>
    export default {
        data() {
            return {
                filePath: ''
            }
        },
        onLoad() {},
        mounted() {
            /**
             * 预览组件初始化
             * @param quality     视频质量
             *                    0:LOWEST(The lowest video quality supported by the video frame producer.)
             *                    1:HIGHEST(The highest video quality supported by the video frame producer.)
             *                    4:SD(720 x 480 (480p))
             *                    5:HD(f 1280 x 720 (720p) )
             *                    6:FHD(1920 x 1080 (1080p) )
             *                    8:UHD(3840 x 2160 (2160p) )
             * @param aspectRatio 拍照比例 0=4:3 1=16:9 2=预览视图大小,即<CustomPreview></CustomPreview> 的大小
             * @param res  - 成功示例:{"code":2xx,"data":string/int/bool,"message":"success"}
             *                    --code=200: 拍照成功,data(string)=图片路径
             *                    --code=201: 视频录制中,data(int)=录制时长/s,每秒更新一次
             *                    --code=202: 视频录制结束,data(string)=视频路径
             *                    --code=203: 是否有前摄像头,data(bool)=是否有前摄像头true/false
             *                    --code=204: 是否有后摄像头,data(bool)=是否有后摄像头true/false
             *                    --code=205: 图片旋转,data(string)=图片路径
             *                    --code=206: 图片镜像处理,data(string)=图片路径
             *                    --code=207: 图片相册通知成功,data(string)=图片路径
             *                    - 失败示例: {"code":500,data:null,"message":"error"}(message:错误信息)
             */
            const quality = uni.getStorageSync("quality") || 0
            console.log("[quality]==", quality)
            this.$refs.CustomPreview.init(quality, 1, (res) => { 
                if (res.code == 500) {
                    this.showToast("[CustomPreview] 错误:" + res.message)
                    return
                }

                console.log("[CustomPreview:res]=", res);
                this.showToast("[CustomPreview:res]=" + JSON.stringify(res))
                if (res.code == 200) {
                    this.showToast("[CustomCrop] 图片路径:" + res.data)
                    this.filePath = res.data;

                    // 设置剪切
                    this.$refs.CustomCrop.initCrop(res.data);

                    // 保存图片路径,用于其他测试
                    uni.setStorageSync("filePath", res.data)
                }
                if (res.code == 201) {
                    this.showToast("[CustomPreview] 视频录制时间:" + res.data)
                }
                if (res.code == 202) {
                    this.showToast("[CustomPreview] 视频路径:" + res.data)
                }
                if (res.code == 203) {
                    this.showToast("[CustomPreview] 是否有前摄像头:" + res.data)
                }
                if (res.code == 204) {
                    this.showToast("[CustomPreview] 是否有后摄像头:" + res.data)
                }
                if (res.code == 205) {
                    this.showToast("[CustomPreview] 对图片旋转指定角度:" + res.data)
                }
                if (res.code == 206) {
                    this.showToast("[CustomPreview] 图片水平或垂直镜像:" + res.data)
                }
                if (res.code == 207) {
                    this.showToast("[CustomPreview] 图片相册通知成功:" + res.data)
                }
            })
            /**  
             * 边缘识别初始化
             * @param res - 成功示例:{"code":200,"data":string,"message":"success"}
             *                   --code=200: 图片剪切成功,data(string)=图片路径
             *                   --code=201: 图片剪切取消,data(string)=图片源路径
             *                   - 失败示例: {"code":500,data:null,"message":"error"}(message:错误信息)
             */
            this.$refs.CustomCrop.init((res) => {
                console.log("[CustomCrop:res]=", res);
                if (res.code == 200) {
                    // 拍照后传入路径用于图片边缘识别和剪切 
                    this.showToast("[CustomCrop] 图片剪切成功路径:" + res.data)
                    this.$refs.CustomCrop.initCrop(res.data);
                }
                if (res.code == 201) {
                    this.showToast("[CustomCrop] 图片剪切取消路径:" + res.data)
                }
            })
        },
        methods: {
            showToast(c) {
                uni.showToast({
                    title: c,
                    icon: 'none'
                });
            },
            // 销毁预览组件
            unbindCamera() {
                this.$refs.CustomPreview.unbindCamera();
            },
            // 切换摄像头
            switchCamera() {
                this.$refs.CustomPreview.switchCamera();
            },
            /**
             * 拍照
             *
             * @param relationPath 文件相对路径,自定义,eg: /com.abc.hello/media/image
             * @param filePrefix   文件名称前缀,自定义,eg: ori_图片_
             * @param fileSuffix   文件名称后缀,自定义,eg: .jpg
             */
            takePhoto() {
                var relationPath = "/_A/B";
                var filePrefix = "img_";
                var fileSuffix = ".jpg";
                this.$refs.CustomPreview.takePhoto(relationPath, filePrefix, fileSuffix);
            },
            /**
             * 开始录像
             *
             * @param relationPath 文件相对路径,自定义,eg: /com.abc.hello/media/video
             * @param filePrefix   文件名称前缀,自定义,eg: ori_视频_
             * @param fileSuffix   文件名称后缀,自定义,eg: .mp4
             */
            startVideo() {
                var relationPath = "/_A/B";
                var filePrefix = "video_";
                var fileSuffix = ".mp4";
                this.$refs.CustomPreview.startVideo(relationPath, filePrefix, fileSuffix);
            },
            // 暂停录像
            pauseVideo() {
                this.$refs.CustomPreview.pauseVideo();
            },
            // 继续录像
            resumeVideo() {
                this.$refs.CustomPreview.resumeVideo();
            },
            //停止录像
            stopVideo() {
                this.$refs.CustomPreview.stopVideo();
            },
            // 打开或关闭手电筒
            switchTorch() {
                this.$refs.CustomPreview.switchTorch();
            },
            // 打开或关闭闪光灯
            switchFlashMode() {
                this.$refs.CustomPreview.switchFlashMode();
            },
            // 返回是否有后置摄像头
            hasBackCamera() {
                this.$refs.CustomPreview.hasBackCamera();
            },
            // 返回是否有前置摄像头
            hasFrontCamera() {
                this.$refs.CustomPreview.hasFrontCamera();
            },

            // TODO 注意:剪切预览图片为初始图片,如果发生了旋转/镜像后图片会被替换为新的图片,结果会以最新的图片为剪切底图,以下功能请按照顺序调用
            // 对图片旋转指定角度
            imageRotate(filePath, degree) {
                this.$refs.CustomPreview.imageRotate(filePath, degree);
            },
            // 图片水平或垂直镜像
            imageMirror(filePath, horizontal, vertical) {
                this.$refs.CustomPreview.imageMirror(filePath, horizontal, vertical);
            },
            // 确定剪切
            confirmCrop() {
                this.$refs.CustomCrop.confirmCrop();
            },
            // 取消剪切
            cancelCrop() {
                this.$refs.CustomCrop.cancelCrop();
            },
            // 自定义图片路径通知相册
            notifyAlbum(filePath) {
                // 测试用文件路径,可通过其他方式获取
                const fp = filePath ? filePath : (uni.getStorageSync("filePath") || '')
                this.$refs.CustomPreview.notifyAlbum(fp);
            },
        }
    }
</script>

<style> 
</style>

更新内容

1.0.5版本更新内容
1.设置预览比例和图片输出比例一致(修复部分手机预览比例和拍照结果比例不一致问题)
2.自定义文件路径通知相册更新方法

权限

相机权限, android.permission.CAMERA
读写文件权限,
android.permission.WRITE_EXTERNAL_STORAGE;
android.permission.READ_EXTERNAL_STORAGE,
android.permission.MANAGE_EXTERNAL_STORAGE
录音权限,android.permission.RECORD_AUDIO

隐私、权限声明

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

相机权限, android.permission.CAMERA 读写文件权限, android.permission.WRITE_EXTERNAL_STORAGE; android.permission.READ_EXTERNAL_STORAGE android.permission.MANAGE_EXTERNAL_STORAGE 录音权限,android.permission.RECORD_AUDIO

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

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

使用中有什么不明白的地方,就向插件作者提问吧~ 我要提问