본문 바로가기

react-native

[RN] react-native-qrcode-scanner 활용 및 오류 수정

react-native-qrcode-scanner를 활용하면서 android에선 정상적으로 실행되었지만 IOS에서 문제가 생겨 IOS 중점으로 글을 남겨봄.

 

1. react-natvie-qrcode-scanner, react-native-permissions 설치

npm install react-native-qrcode-scanner
npm install react-native-permissions

 

2. package.json에 내용 추가

"scripts": {
    ...
    , "postinstall": "react-native setup-ios-permissions && pod-install"
},
"dependencies": {
    ...
},
"reactNativePermissionsIOS": [
    "Camera",
    "PhotoLibrary"
]

 

3. info.plist 권한 추가

<key>NSCameraUsageDescription</key>
<string>QR 스캔을 위한 카메라 권한이 필요합니다.</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>사진 라이브러리 접근 권한이 필요합니다.</string>
<key>NSMicrophoneUsageDescription</key>
<string>Your message to user when the microsphone is accessed for the first time</string>

    => android는 AndroidManifest.xml에 아래 권한을 추가했다.

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

 

4. Podfile 권한 추가

use_frameworks! 
... 
	#아래 구문 추가
	permissions_path = '../node_modules/react-native-permissions/ios'
	pod 'Permission-Camera', :path => "#{permissions_path}/Camera.podspec"
...
pod 'react-native-webview', :path => '../node_modules/react-native-webview'

 

5. npm install

npm install
cd ios
pod install

    package.json에 postinstall를 넣어서 pos install은 제외해도 되는 듯

 

6. QrScanner.js

import React, {Component, Fragment, useEffect, useState, useRef} from 'react';
import {
  StyleSheet,
  View,
  Text,
  Linking,
  TouchableOpacity,
  Dimensions,
  ImageBackground,
  Image,
  BackHandler
} from 'react-native';
const deviceWidth = Dimensions.get('screen').width;
const deviceHeight = Dimensions.get('screen').height;
import QRCodeScanner from 'react-native-qrcode-scanner';
import { RNCamera } from 'react-native-camera';

class ScanScreen extends Component {
    constructor(props) {
        super(props);
        this.state = {
            scan: false,
            ScanResult: false,
            result: null
        };
    }
    goHome = () => {
        this.setState({
            result: null,
            scan: false,
            ScanResult: false
        })
        this.props.navigation.navigate('Home')
    }
    onSuccess = (e) => {
        const check = e.data.substring(0, 4);
        console.log('scanned data' + check);
        this.setState({
            result: e,
            scan: false,
            ScanResult: true
        })
        if (check === 'http') {
            Linking.openURL(e.data).catch(err => console.error('An error occured', err));
        } else {
            this.setState({
                result: e,
                scan: false,
                ScanResult: true
            })
        }
    }
    activeQR = () => {
        this.setState({ scan: true })
    }
    scanAgain = () => {
        this.setState({ scan: true, ScanResult: false })
    }
    render() {
        const { scan, ScanResult, result } = this.state
        return (
            <View style={styles.scrollViewStyle}>
                <Fragment>
                    <View style={styles.header}>
                        <TouchableOpacity onPress={this.goHome}>
                            <Image source={require('/assets/back.png')} style={{height: 36, width: 36}}></Image>
                        </TouchableOpacity>
                        <Text style={styles.textTitle}>Scan QR Code</Text>
                    </View>
                    {!scan && !ScanResult &&
                        <View style={styles.cardView} >
                            <Image source={require('/assets/camera.png')} style={{height: 36, width: 36}}></Image>
                            <Text numberOfLines={8} style={styles.descText}>Please move your camera {"\n"} over the QR Code</Text>
                            <Image source={require('/assets/qr-code.png')} style={{margin: 20}}></Image>
                            <TouchableOpacity onPress={this.activeQR} style={styles.buttonScan}>
                                <View style={styles.buttonWrapper}>
                                <Image source={require('/assets/camera.png')} style={{height: 36, width: 36}}></Image>
                                <Text style={{...styles.buttonTextStyle, color: '#2196f3'}}>Scan QR Code</Text>
                                </View>
                            </TouchableOpacity>
                        </View>
                    }
                    {ScanResult &&
                        <Fragment>
                            <Text style={styles.textTitle1}>Result</Text>
                            <View style={ScanResult ? styles.scanCardView : styles.cardView}>
                                <Text>Type : {result.type}</Text>
                                <Text>Result : {result.data}</Text>
                                <Text numberOfLines={1}>RawData: {result.rawData}</Text>
                                <TouchableOpacity onPress={this.scanAgain} style={styles.buttonScan}>
                                    <View style={styles.buttonWrapper}>
                                        <Image source={require('/assets/camera.png')} style={{height: 36, width: 36}}></Image>
                                        <Text style={{...styles.buttonTextStyle, color: '#2196f3'}}>Click to scan again</Text>
                                    </View>
                                </TouchableOpacity>
                            </View>
                        </Fragment>
                    }
                    {scan &&
                        <QRCodeScanner
                            reactivate={true}
                            showMarker={true}
                            ref={(node) => { this.scanner = node }}
                            onRead={this.onSuccess}
                            topContent={
                                <Text style={styles.centerText}>
                                   Please move your camera {"\n"} over the QR Code
                                </Text>
                            }
                            bottomContent={
                                <View>
                                    <ImageBackground source={require('/assets/bottom-panel.png')} style={styles.bottomContent}>
                                        <TouchableOpacity style={styles.buttonScan2}
                                            onPress={() => this.scanner.reactivate()}
                                            onLongPress={() => this.setState({ scan: false })}>
                                            <Image source={require('/assets/camera2.png')}></Image>
                                        </TouchableOpacity>
                                    </ImageBackground>
                                </View>
                            }
                        />
                    }
                </Fragment>
            </View>
        );
    }
}
export default ScanScreen;
const styles = {
    scrollViewStyle: {
        flex: 1,
        justifyContent: 'flex-start',
        backgroundColor: '#2196f3'
    },
    header: {
        display: 'flex',
        flexDirection: 'row',
        alignItems: 'center',
        height: '10%',
        paddingLeft: 15,
        paddingTop: 10,
        width: deviceWidth,
    },
    textTitle: {
        fontWeight: 'bold',
        fontSize: 18,
        textAlign: 'center',
        padding: 16,
        color: 'white'
    },
    textTitle1: {
        fontWeight: 'bold',
        fontSize: 18,
        textAlign: 'center',
        padding: 16,
        color: 'white'
    },
    cardView: {
        width: deviceWidth - 32,
        height: deviceHeight - 350,
        alignSelf: 'center',
        justifyContent: 'flex-start',
        alignItems: 'center',
        borderRadius: 10,
        padding: 25,
        marginLeft: 5,
        marginRight: 5,
        marginTop: '10%',
        backgroundColor: 'white'
    },
    scanCardView: {
        width: deviceWidth - 32,
        height: deviceHeight / 2,
        alignSelf: 'center',
        justifyContent: 'center',
        alignItems: 'center',
        borderRadius: 10,
        padding: 25,
        marginLeft: 5,
        marginRight: 5,
        marginTop: 10,
        backgroundColor: 'white'
    },
    buttonWrapper: {
        display: 'flex',
        flexDirection: 'row',
        alignItems: 'center'
    },
    buttonScan: {
        borderWidth: 2,
        borderRadius: 10,
        borderColor: '#258ce3',
        paddingTop: 5,
        paddingRight: 25,
        paddingBottom: 5,
        paddingLeft: 25,
        marginTop: 20
    },
    buttonScan2: {
        marginLeft: deviceWidth / 2 - 50,
        width: 100,
        height: 100,
    },
    descText: {
        padding: 16,
        textAlign: 'center',
        fontSize: 16
    },
    highlight: {
        fontWeight: '700',
    },
    centerText: {
        flex: 1,
        textAlign: 'center',
        fontSize: 18,
        padding: 32,
        color: 'white',
    },
    textBold: {
        fontWeight: '500',
        color: '#000',
    },
    bottomContent: {
       width: deviceWidth,
       height: 120,
    },
    buttonTouchable: {
        fontSize: 21,
        backgroundColor: 'white',
        marginTop: 32,
        width: deviceWidth - 62,
        justifyContent: 'center',
        alignItems: 'center',
        height: 44
    },
    buttonTextStyle: {
        color: 'black',
        fontWeight: 'bold',
    }
}

- 참고 사이트: https://jw910911.tistory.com/71

 

React-Native : qrcode 스캐너 이용하기

React-Native로 QR코드 인식 카메라 구현해보기 React-Native로 개발하던중 qrcode를 사용할 일이있어서, 해당 react-native-qrcode-scanner라는 라이브러리를 찾게 되었습니다.. 외국문서는 많이 있지만 한글로

jw910911.tistory.com

 

 

※ 나는 위 순서대로 진행하고 xcode에서 빌드시 아래 오류가 발생했다.

Duplicate interface definition for class 'RNPermissionHandlerCamera'

Podfile에 Permission-Camera를 추가하면 pod install 시 Permission-Camera가 설치되고 이게 RNPermission에 있는 RNPermissionHandlerCamera와 충돌이 났다.

 

react-native-permissions npm 공식 사이트에도 Podfile에 Permission-Camera를 추가하라고 되어 있지만

react-native-permissions가 버전이 바뀌면서 충돌이 생긴 것 같다. (정확한 원인은 모르겠다...)

공식 사이트엔 react-native-permissions 2.0.2버전으로 되어 있지만 나는 최신버전(3.8.4)를 받음

 

현재 내가 작업하고 있는 라이브러리 버전들

"dependencies": {
  "react": "18.2.0",
  "react-native": "^0.72.3",
  "react-native-camera": "^4.2.1",
  "react-native-permissions": "^3.8.4",
  "react-native-qrcode-scanner": "^1.5.5"
}

 

※ 해결 방법

 

1. Podfile에 넣은 pod 'Permission-Camera'.... 구문 삭제

    

2. package-lock.json에 react-native-scanner -> dependencies 내 react-native-permissions 버전 변경

"node_modules/react-native-qrcode-scanner": {
    ...
    "dependencies": {
       ...
       "react-native-permissions": "^3.8.4"
    }
    ...
}

 

3. node_modules 및 Pods, Podfile.lock 삭제 후 재설치

rn -rf node_modules
cd ios 
rn -rf Pods Podfile.lock

cd ..
npm install

 

4. /node_modules/react-native-qrcode-scanner/node_modules/react-native-permissions 삭제

    여기에 있는 RNPermissionHandlerCamera.h가 RNPermission에 있는 것과 충돌 나는 듯

 

참고 사이트: https://github.com/moaazsidat/react-native-qrcode-scanner/issues/403