• React Native调用摄像头画面及拍照和保存图片到相册全流程


    今天主要做了一个demo,功能很简单,就是调用手机摄像头画面,并且可以通过按钮控制拍照以及将图片保存到手机相册的功能,接下来我将从创建项目开始一步一步完成这个demo,各位只需要复制粘贴即可

    创建React Native项目

    npx react-native init yx_rnDemo --version 0.70.6 // 这里我使用的RN版本为0.70.6,建议各位和我一样,因为RN贼恶心了,好多插件都会因为版本问题各种报错
    
    • 1

    安装依赖

    package.json所需依赖包

    	// react-native-vision-camera版本号就写我这个,不然也容易有问题,今天因为这个费了不少时间
        "@react-native-camera-roll/camera-roll": "^7.4.2", // 照片保存到相册所需的插件
        "react-native-vision-camera": "2.15.4" // 调用摄像头画面和拍照所需插件
    
    • 1
    • 2
    • 3

    安装命令如下

    yarn add @react-native-camera-roll/camera-roll
    yarn add react-native-vision-camera@2.15.4
    
    • 1
    • 2

    安卓环境配置

    找到android/app/src/mian/AndroidManifest.xml这个文件,在manifest这个标签内添加如下请求权限的代码

    <manifest>
    	...
    	<uses-permission android:name="android.permission.INTERNET" />
    	<uses-permission android:name="android.permission.CAMERA" />  // 相机权限
    	<uses-permission android:name="android.permission.RECORD_AUDIO" /> // 麦克风权限(单纯的拍照其实不用给)
    
    	<application
    		android:requestLegacyExternalStorage="true"  // 添加这个(用于确保你的应用在 Android 10 中仍然能够访问外部存储,但如果你的应用目标是 Android 11 或更高版本,你应该考虑调整应用以符合 Scoped Storage 的要求。)
    		...
    		>
    
    	</application>
    	...
    </manifest>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    苹果ios环境配置

    找到ios/项目名/Info.plist这个文件,在plist标签内新增如下代码

    <pilst>
    	...(其他代码)
    	<key>NSCameraUsageDescription</key>
    	<string>$(PRODUCT_NAME) needs access to your Camera.</string>
    
    	<key>NSMicrophoneUsageDescription</key>
    	<string>$(PRODUCT_NAME) needs access to your Microphone.</string>
    	...(其他代码)
    </plist>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    接下来就是在单文件里面直接写代码了

    找到根目录下的App.js(主入口文件),将一下代码直接粘贴进去即可

    import { useCameraDevices, Camera } from 'react-native-vision-camera'
    import * as React from 'react'
    import { useRef, useEffect, useState } from 'react'
    import { PermissionsAndroid, Text, View, Button, Alert, Platform } from 'react-native'
    import { CameraRoll } from "@react-native-camera-roll/camera-roll"
    
    export default function CameraDemo (props) {
      const cameraRef = useRef(null) // 创建一个 ref 来引用相机组件
      const [hasCameraPermission, setHasCameraPermission] = useState(false) // 状态用于跟踪摄像头权限
      const [currentDevice, setCurrentDevice] = useState(null) // 跟踪当前摄像头设备
    
      useEffect(async () => {
        // 在组件加载时请求相机权限
        async function requestCameraPermission () {
          try {
            // 请求相机权限
            const granted = await PermissionsAndroid.request(
              PermissionsAndroid.PERMISSIONS.CAMERA,
              {
                title: 'Camera Permission',
                message: 'App needs access to your camera.',
                buttonNeutral: 'Ask Me Later',
                buttonNegative: 'Cancel',
                buttonPositive: 'OK',
              },
            )
            if (granted === PermissionsAndroid.RESULTS.GRANTED) {
              console.log('Camera permission granted')
              setHasCameraPermission(true) // 如果权限被授予,设置相机权限状态为 true
            } else {
              console.log('Camera permission denied')
              setHasCameraPermission(false) // 如果权限被拒绝,设置相机权限状态为 false
            }
          } catch (err) {
            console.warn(err)
          }
        }
    
        async function requestStoragePermission () {
          try {
            const granted = await PermissionsAndroid.requestMultiple([
              PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE,
              PermissionsAndroid.PERMISSIONS.READ_EXTERNAL_STORAGE,
            ])
            if (
              granted['android.permission.WRITE_EXTERNAL_STORAGE'] === PermissionsAndroid.RESULTS.GRANTED &&
              granted['android.permission.READ_EXTERNAL_STORAGE'] === PermissionsAndroid.RESULTS.GRANTED
            ) {
              console.log('Storage permissions granted')
              // 在此处执行您需要的操作,比如保存照片到相册
            } else {
              console.log('Storage permissions denied')
              // 处理权限被拒绝的情况
            }
          } catch (err) {
            console.warn(err)
          }
        }
    
        await requestCameraPermission() // 调用函数以请求相机权限
        await requestStoragePermission() // 请求图库权限
      }, [])
    
      const devices = useCameraDevices()
    
      // 设置默认摄像头(默认后置,如果想设置的哪个后面进来还是哪个的话可以自行再做处理)
      useEffect(() => {
        if (devices.back) {
          setCurrentDevice(devices.back)
        }
      }, [devices])
    
      // 切换摄像头
      const toggleCamera = () => {
        setCurrentDevice(currentDevice === devices.back ? devices.front : devices.back)
      }
    
      const saveToCameraRoll = async (photo) => {
          const path = Platform.OS === 'android' ? 'file://' + photo.path : photo.path
          // 使用 CameraRoll 保存图片到相册
          CameraRoll.saveToCameraRoll(path, 'photo')
            .then(() => {
              Alert.alert('Success', '图片到相册保存成功')
            })
            .catch((error) => {
              Alert.alert('Error', '图片保存到相册失败')
            })
      }
    
      const takePhoto = async () => {
        if (cameraRef.current) {
          try {
            const photo = await cameraRef.current.takePhoto()
            console.log('Photo taken:', photo)
            photo.id = new Date().getTime().toString() // 添加一个唯一的 id 属性
            saveToCameraRoll(photo)  // 将路径传递过去,为了将照片存入相册(默认不是存到相册里面)
          } catch (error) {
            console.error('Error taking photo:', error)
          }
        }
      }
    
      return (
        <View style={{ flex: 1 }}>
          {hasCameraPermission && currentDevice && (
            <View>
              <Camera
                ref={cameraRef} // 绑定ref
                style={{ width: 200, height: 300 }}
                device={currentDevice} // 绑定设备
                isActive={true}
                photo={true} // 打开相机功能
                frameProcessorFps={'auto'}
              />
              <Button title="拍照" onPress={takePhoto} />
              <Button title="切换摄像头" onPress={toggleCamera} />
            </View>
          )}
          {!hasCameraPermission && <Text>Camera permission not granted.</Text>}
        </View>
      )
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
  • 相关阅读:
    加入数(insdata)
    比尔·盖茨晒48年前简历:“没你们的好看”
    【Oracle系列4】Oracle 数据库的层次结构,常见的GUI连接用具
    kafka 调优
    挂脖式运动蓝牙耳机推荐,目前适合运动佩戴的五款耳机推荐
    2022年100道最新软件测试面试题,常见面试题及答案汇总
    一、多线程的基本概念
    【karle 笔记】QQ机器人jdk17版本下载和安装
    MATLAB算法实战应用案例精讲-【智能优化算法】黏菌算法(SMA)
    泡沫褪去,DeFi还剩下什么
  • 原文地址:https://blog.csdn.net/weixin_68658847/article/details/136277439