react native 实现扫描条形码功能(react-native-camera)

宣原
2023-12-01

目录:

  1. 思路
  2. 安装中间件
  3. 确认 iOSAndroid 配置信息
  4. 封装扫码组件
  5. 另一个组件获取扫码数据

思路

  • 安装中间件 react-native-camera
  • 检查 iOSAndroid 是否配置成功;
  • 封装扫码组件,实现页面布局、扫码动画、获取扫描信息等;
  • 另一个组件添加扫码入口,获取扫码数据;

具体步骤

1. 安装中间件 react-native-camera参考官网

版本:

"react": "16.8.3",
"react-native": "0.59.9",
"react-native-camera": "2.10.2"

安装方式:

npm install react-native-camera --save
react-native link react-native-camera

2.可能 link 失败,检查 iOSAndroid 是否配置成功

  1. iOS 环境:
- 【检查】是否存在 `RNCamera.xcodeproj`

用 XCode 打开 iOS 项目/Libraries/RNCamera.xcodeproj;
若不存在:右键Libraries->add Files to xxx项目名
-> 选择RN项目中node_modules -> react-native-camera ->  确定

- 【检查】是否有相机使用权限

在 `info.plist` 中添加相机使用权限 key:
"Privacy - Camera Usage Description",value: "需要您的同意才能使用相机"


  1. Android 环境:
- 【检查】`android/app/src/main/java/com/xxx/MainApplication.java`

    +  import org.reactnative.camera.RNCameraPackage;
    
    protected List<ReactPackage> getPackages() {
      return Arrays.<ReactPackage>asList(
          new MainReactPackage(),
          +  new RNCameraPackage()
      );
    }


- 【检查】android/settings.gradle

    + include ':react-native-camera'
    + project(':react-native-camera').projectDir = new File(rootProject.projectDir,     '../node_modules/react-native-camera/android')


- 【检查】android/app/build.gradle
    android {
      ...
      defaultConfig {
        ...
        + missingDimensionStrategy 'react-native-camera', 'general' 
      }
    }
    
    ...
    
    dependencies {
       + implementation project(':react-native-camera')
        implementation fileTree(dir: "libs", include: ["*.jar"])
        implementation "com.android.support:appcompat-v7:${rootProject.ext.supportLibVersion}"
        implementation "com.facebook.react:react-native:+"  // From node_modules
    }


- 【检查】android/build.gradle

    allprojects {
        repositories {
            ...
            maven { url "https://jitpack.io" }
            maven { url "https://maven.google.com" }
        }
    }

- 【检查】android/app/src/main/AndroidManifest.xml 是否有相机使用相关权限

    <uses-permission android:name="android.permission.RECORD_AUDIO"/>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    
- 配置文件 android/build.gradle 版本信息如下
    // Top-level build file where you can add configuration options common to all sub-projects/modules.
    
    buildscript {
        ext {
            buildToolsVersion = "28.0.3"
            minSdkVersion = 16
            compileSdkVersion = 28
            targetSdkVersion = 28
            supportLibVersion = "28.0.0"
        }
        repositories {
            google()
            jcenter()
            maven {
                url 'https://maven.google.com/'
                name 'Google'
            }
        }
        dependencies {
            classpath("com.android.tools.build:gradle:3.4.0")
    
            // NOTE: Do not place your application dependencies here; they belong
            // in the individual module build.gradle files
        }
    }
    
    allprojects {
        repositories {
            mavenLocal()
            google()
            jcenter()
            maven {
                // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
                url "$rootDir/../node_modules/react-native/android"
            }
            maven { url "https://jitpack.io" }
            maven { url "https://maven.google.com" }
        }
    }



  1. 以上配置完毕,如果有报错,可以选择关闭开发工具,重新打开,本人就是一样的操作,昨天出现各种错误,今天从头再一样到配置,就可以了,嗨,生活

3、封装扫码组件,实现页面布局、扫码动画、获取扫描信息

【封装】扫码组件 BarCodePage;
注意:扫码成功后跳转到 TestPage 页面;

import React, { Component } from 'react';
import {
    View,
    StyleSheet,
    Text,
    Animated,
    Easing,
    InteractionManager,
    TouchableOpacity,
    Image,
    SafeAreaView,
    Dimensions
} from 'react-native';
import { RNCamera } from 'react-native-camera';

const { width, height } = Dimensions.get('window');

const Height = () => {
    return height
};

const Width = () => {
    return width
};

class BarCodePage extends Component {
    constructor(props) {
        super(props);
        this.state = { 
            transCode:'', // 条码
            typeCode: '', // 条码类型
            showCode: true,
            animateCode: new Animated.Value((Width() - 200) / 2,(Height() - 340) / 2), // 二维坐标
        }
    }

    componentDidMount() {
        InteractionManager.runAfterInteractions(() => {
            this.startAnimation()
        })
        console.log('进入-------', this.state.showCode)
    }

    // 动画开始
    startAnimation() {
        this.state.animateCode.setValue(0)
        Animated.timing(this.state.animateCode, {
            toValue: 1,             // 运动终止位置,比值
            duration: 2500,         // 动画时长
            easing: Easing.linear,  // 线性的渐变函数
            delay: 0.3,             // 在一段时间之后开始动画(单位是毫秒),默认为0
        }).start(() => this.startAnimation())
    }

    barcodeReceived(e) {
        let that = this
        if(this.state.showCode){
            console.log(e);
            that.setState({
                transCode: e.data,
                typeCode: e.type,
                showCode: false
            })
            if(e.data) {
                let barCodeData = {
                    typeName: 'testScan', // TestPage获取此值
                    typeValue: e.data
                }
                that.props.navigation.navigate('TestPage', { barCodeData })
            }
        }
    }

    // 关闭扫一扫
    closeScanPage() {
        this.props.navigation.navigate('TestPage')
    }

    render() { 
        return ( 
            <View style={styles.container}>
                <SafeAreaView style={styles.container}>
                    <RNCamera
                        onBarCodeRead={this.barcodeReceived.bind(this)}
                        onCameraReady={() => {
                            console.log('ready')
                        }}
                        permissionDialogTitle={'提示信息'}
                        permissionDialogMessage={'APP需要使用相机,请打开相机权限允许APP使用'}
                        style={styles.scan_camera}
                    >
                        <View style={styles.scan_cont_box}>
                            <View style={styles.scan_cont_circle}>
                                <Animated.View style={{
                                    alignItems: 'center',
                                    transform: [{
                                        // translateX: x轴移动
                                        // translateY: y轴移动
                                        translateY: this.state.animateCode.interpolate({
                                            inputRange: [0,1],
                                            outputRange: [0,200]
                                        })
                                    }]
                                }}>
                                    <Text style={styles.scan_circle_init}></Text>
                                </Animated.View>
                            </View>
                        </View>
                        <TouchableOpacity
                            activeOpacity={.8}
                            style={styles.scan_top_box}
                            onPress={() => this.closeScanPage()}
                            >
                            <Image source={require('关闭图标,不需要可删除.png')}/>
                        </TouchableOpacity>
                        <View style={styles.scan_info_box}>
                            <Text style={styles.scan_info}>将条形码放入框内,即可自动扫描</Text>
                        </View>
                    </RNCamera>
                </SafeAreaView>
            </View>
        )
    }
}

const styles = StyleSheet.create({
    container: {
        flex: 1
    },
    scan_top_box: {
        position: "absolute",
        left: 20,
        top: 20,
        width: 24,
        height: 24
    },
    scan_camera: {
        flex: 1,
        height: Height()
    },
    scan_cont_box: {
        flex: 1,
        justifyContent: 'center',
        alignItems: 'center',
        backgroundColor: 'rgba(0,0,0,0.3)',
    },
    scan_cont_circle: {
        width: 260,
        height: 260,
        borderWidth: 1,
        borderColor: '#919191',
        backgroundColor: 'rgba(255,255,255,0.1)'
    },
    scan_circle_init: {
        width:250,
        height:1,
        backgroundColor:'#00ff00'
    },
    scan_info_box: {
        height: 100,
        backgroundColor: 'rgba(0,0,0,0.3)',
        alignItems: 'center',
        width: Width()
    },
    scan_info: {
        color: '#fff'
    },
    info: {
        width: Width(),
        height: 80,
        backgroundColor: '#fff',
        paddingLeft: 10,
        paddingBottom:5,
        justifyContent: 'space-around',
    },
})
 
export default BarCodePage;


4、TestPage 页面增加入口,以及获取扫描的信息,结束✌️

`TestPage`主要代码如下:


constructor(props) {
    super(props);
    this.state = {
        inputValue: ''
    }
}

componentWillReceiveProps(nextProps) {
    // 监听扫码页面获取的值
    let { barCodeData } = nextProps.navigation.state.params
    let that = this
    if(barCodeData && barCodeData.typeValue && barCodeData.typeName == 'testScan') {
        that.setState({
            inputValue: barCodeData.typeValue
        })
    }
}

handleScanCheck() {
    this.props.navigation.navigate('BarCodePage')
}

render() {
    let { inputValue } = this.state
    return(
        <Text>展示条形码数据:</Text>
        <TextInput defaultValue={inputValue} />
        <TouchableOpacity
            activeOpacity={.8}
            onPress={() => this.handleScanCheck()}
            >
            <Image source={require('扫一扫图标,点击进入扫码页面.png')} />
        </TouchableOpacity>
    )
}


写给自己的随笔,有问题欢迎指出
 类似资料: