更新记录

1.1.0(2025-09-03)

添加 hideUvcCamera 用来控制UVC摄像隐藏和显示,因为有的usb摄像头UVC设备如果使用openUvcCamera和closedUvcCamera 来重复打开和关闭,这样每次都创建新的多次后有的摄像设备会导致程序崩溃。可以通过UVC设备只打开一次,然后使用hideUvcCamera 来控制隐藏和显示

1.0.8(2025-08-27)

参数由 deviceId 统一改为传入 productId 打开摄像头,因为deviceId是系统自动获取的设备关机重启后可能会发生改变,导致重启可能会不匹配

1.0.7(2025-08-07)

设备的getVendorId有存在相同的情况,改为使用 getDeviceId 来打开,参数由 vendorId 统一改为传入 deviceId

查看更多

平台兼容性

uni-app(4.36)

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

uni-app x(4.36)

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

安卓UVCAndroid视频设备拍照,usb摄像外接设备预览和拍照,返回路径和base64

需要打包自定调试包测试才能使用

安卓10的设备,如果有碰到返回 “没有授予访问设备的权限” ,打调试包的时候在 manifest.json 把 targetSdkVersion 设置为27 后重新打包自定调试包

完整页面使用方法:

vue2的需要自己去设置一下调用方法,案例写的是vue3的方式

<template>
    <view>

        <button @click="UTSgetUvcCamera">获取当前UVC设备列表</button>
        <button @click="UTSopenUvcCameraX(14785)">打开UVC视频设备</button>
        <button @click="UTSgetUvcCameraImg(14785)">UVC设备拍照</button>
        <button @click="UTSclosedUvcCamera(14785)">关闭UVC设备</button>
        <button @click="UTShideUvcCamera(14785,false)">隐藏UVC设备</button>
        <button @click="UTShideUvcCamera(14785,true)">显示UVC设备</button>

        <image :src="img" mode="aspectFill"></image>

        <view class="sssAD"></view>

    </view>
</template>

<script setup>
    import {
        onShow,
        onReady,
        onReachBottom,
        onPullDownRefresh,
        onShareAppMessage
    }
    from '@dcloudio/uni-app';
    import {
        getCurrentInstance,
        ref,
        reactive,
        inject,
        computed,
        onMounted
    } from 'vue';

    import {
        getUvcCamera,
        openUvcCamera,
        getUvcCameraImg,
        closedUvcCamera,
        clickUvcCameraImage,
        hideUvcCamera
    } from "@/uni_modules/mushan-uvccamera";

    //获取当前设备的UVC列表
    /*
        返回参数 getDeviceName,getDeviceId,getProductId,getProductName,getVendorId
        保存好设备的getProductId,用于打开UVC视频和拍照,自己去测试哪个是可打开的设备
    */
    let getProductId = ref(null);
    function UTSgetUvcCamera() {
        getUvcCamera((res) => {
            let resData = JSON.parse(res)
            console.log(resData);
        })
    }

    //打开对应的UVC设备
    //简单使用案例
    //productId 通过getUvcCamera获取的列表里拿到;
    //widthView 预览显示的宽,按设备整体宽度百分比1为设备的宽。0.5为一半宽
    //heightView 预览显示的高,按设备整体高度百分比1为设备的高。0.5为一半高
    //topMargin 预览与顶部的距离,1为整个设备的高距离,0.5为一半
    //leftMargin 预览与左边的距离,1为整个设备的宽距离,0.5为一半
    //quirkFixBandwidth 是否设置UVC固定带宽模式,为了支持同时一个页面打开多个摄像设备,有的高清摄像头使用该模式会有重影,正常是不需要打开此模式

    /**
    textData 为文本数组的显示,不需要时 textData:[] 为空
    textData:[
        {
            content:'文本1',   //文本内容
            textSize:16,    //文本字体
            textColor:'#DC143C',  //文本颜色
            topMargin:50,       //与预览显示的头部距离
            leftMargin:50,      //与预览显示的左边距离
        },
    ]
    **/

    /**
    imageData 为图片数组的显示,不需要时 imageData:[] 为空 
    imageData:[
        {
            url:'static/logo.png',   //图片地址,在static的目录下的图片
            width:50,       //显示的图片宽度
            height:50,      //显示的图片高度
            topMargin:50,  //与预览显示的头部距离
            leftMargin:100,  //与预览显示的左边距离
        },
    ]
    **/
    async function UTSopenUvcCamera(productId) {
        return new Promise((resolve, reject) => {

            let parame = {
                textData:[
                    {
                        content:'文本1',
                        textSize:16,
                        textColor:'#DC143C',
                        topMargin:30,
                        leftMargin:50,
                    },
                    {
                        content:'文本2',
                        textSize:16,
                        textColor:'#DC143C',
                        topMargin:30,
                        leftMargin:100,
                    }
                ],
                imageData:[
                    {
                        url:'static/logo.png',
                        width:50,
                        height:50,
                        topMargin:50,
                        leftMargin:50,
                    },
                    {
                        url:'static/logo.png',
                        width:50,
                        height:50,
                        topMargin:100,
                        leftMargin:200,
                    }
                ],
                productId: Number(productId),
                widthView: 0.5,
                heightView: 0.5,
                topMargin: 0.5,
                leftMargin: 0,
                quirkFixBandwidth:false,
            }
            openUvcCamera(parame, res => {
                let resData = JSON.parse(res)
                console.log(resData)
                if (resData.msg == 'ok') {

                    //parame的imageData中第1张图片点击的触发
                    clickUvcCameraImage({
                        productId: productId,
                        imageNum: 0,
                    },(res) => {
                        console.log('点击了第1张图片');
                    })

                    //parame的imageData中第2张图片点击的触发
                    clickUvcCameraImage({
                        productId: productId,
                        imageNum: 1,
                    },(res) => {
                        console.log('点击了第2张图片');
                    })

                    resolve()
                }else if (resData.msg == '用户拒绝了部分权限') {
                    //这里是拒绝了授权权限的返回
                    reject()
                }
            })
        })
    }

    //根据class使用案例
    //这里是根据某个class获取到view的位置,然后获取到设备宽高大小比例等等可以把预览设定到指定页面
    //假设有某个<view class="cameraClass"></view>可以根据以下获取
    async function UTSopenUvcCameraX(productId) {
        return new Promise((resolve, reject) => {
            uni.getSystemInfo({
                success: function(res) {
                    let screenWidth = res.screenWidth
                    let screenHeight = res.screenHeight
                    const query = uni.createSelectorQuery();
                    query.select('.sssAD').boundingClientRect().exec((ret) => {

                        let vWidth = (ret[0].width / screenWidth).toFixed(2)
                        let vHeight = (ret[0].height / screenHeight).toFixed(2)
                        let vTop = (ret[0].top / screenHeight).toFixed(2)
                        let vLeft = (ret[0].left / screenWidth).toFixed(2)

                        let parame = {
                            textData:[],
                            imageData:[],
                            productId: Number(productId),
                            widthView: vWidth * 1,
                            heightView: vHeight * 1,
                            topMargin: vTop * 1,
                            leftMargin: vLeft * 1,
                            quirkFixBandwidth:false,
                        }
                        openUvcCamera(parame, res => {
                            let resData = JSON.parse(res)
                            console.log(resData);
                            if (resData.msg == 'ok') {
                                resolve()
                            } else if (resData.msg == '用户拒绝了部分权限') {
                                reject()
                            }
                        })

                    })
                }
            });

        })
    }

    //获取uvc设备拍照图片
    /*
        productId 通过getUvcCamera获取的列表里拿到;
        someQuality 拍照的图片质量 0 - 100
        isBase64 是否返回base64数据,不返回填false

        返回值 base64 和 图片路径file
    */
    let img = ref('');
    async function UTSgetUvcCameraImg(productId){
        return new Promise((resolve, reject) => {

            try{

                let parame = {
                    productId:Number(productId),
                    someQuality:40,
                    isBase64:true,
                }
                getUvcCameraImg(parame,(res)=>{
                    let resData = JSON.parse(res)
                    if(resData.msg == 'ok'){
                        console.log(resData);
                        console.log(resData.file);
                        img.value = filterBase64(resData.base64);
                    }
                })

            }catch(error){
                console.log(error)
            }

        })
    }
    function filterBase64(codeImages) {
        return codeImages.replace(/[\r\n]/g, "");
    }

    //关闭摄像头 productId 通过getUvcCamera获取的列表里拿到
    async function UTSclosedUvcCamera(productId){
        closedUvcCamera(Number(productId),(res)=>{
            let resData = JSON.parse(res);
            console.log(resData);
            if(resData.msg == 'ok'){

            }
        })
    }

    //隐藏摄像头 productId 通过getUvcCamera获取的列表里拿到,type 为 true 是打开,为 false 是关闭
    async function UTShideUvcCamera(productId,type){
        hideUvcCamera(Number(productId),type,(res) => {
            let resData = JSON.parse(res);
            console.log(resData);
            if (resData.msg === 'ok') {

            }
        });
    }

</script>

<style lang="scss" scoped>
    .sssAD{
        width: 400px;
        height: 400px;
        position: absolute;
        background-color: red;
        top: 200px;
        left: 400px;
    }
</style>

隐私、权限声明

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

<uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

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

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