반응형

📷 바코드, QR 코드 인식하기

특정 바코드를 인식하여 문자열을 가져와야하는 기능을 만들어야 했다.

몇가지 카메라 관련 라이브러리가 있었지만, deprecated된 라이브러리는 제외하고 비교적 최근까지 버전업이 이루어지고 있는 라이브러리 중 react-native-camera-kit을 채택했다.

📦 라이브러리 설치 및 적용하기

⚙️ 설치하기

  • 라이브러리 설치
    npm install react-native-camera-kit --save
  • pod 패키지 설치
    cd ios && pod install

✍️ 권한 설정

카메라 사용을 위해 권한을 설정한다.

🤖 Android

프로젝트/android/app/src/main/AndroidManifest.xml 파일을 열어준다.

아래 내용을 상단에 추가한다.

<!-- camera 접근 제어 -->
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<!-- 진동 접근 제어 -->
<uses-permission android:name="android.permission.VIBRATE"/>

🍎 IOS

프로젝트/ios/프로젝트명/info.list 파일을 열어준다.

아래 내용을 하단에 추가한다.

<key>NSCameraUsageDescription</key>
<string>For taking photos</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>For saving photos</string>

⚠️ 설치간 이슈 에러 정리

라이브러리 설치 후 프로젝트 실행시 안드로이드가 정상적으로 열리지 않는 현상이 있을 수 있습니다.
프로젝트/android/build.gradle 파일을 열어줍니다.

buildscript {
    ext {
        ...
        // 기존 버전 주석
        // minSdkVersion = 21
        // kotlinVersion = "1.8.0"
        minSdkVersion = 23
        kotlin_version = "1.8.0"
    }
    dependencies {
            ...
            classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version")
    }
}
  • 기존 minSdkVersion의 21을 23으로 올려주었습니다.
  • 기존 kotlinVersion이라는 텍스트를 카멜케이스 kotlin_version으로 변경하고 dependencies에도 적용하였습니다.

이후 프로젝트 경로로 돌아와서 아래 명령어로 gradle 초기화를 진행하고 안드로이드 구동시 정상 동작을 확인했습니다.
$ ./gradlew clean

🧐 적용예제

전역 state사용을 위해 recoil의 atom을 사용한 예제입니다.

App.tsx

function App(): React.JSX.Element {

  async function requestCameraPermission() {
    try {
      const granted = await PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.CAMERA, {
        title: '카메라 권한 요청',
        message: '앱에서 카메라를 사용하기 위해 권한이 필요합니다.',
        buttonNeutral: '나중에 묻기',
        buttonNegative: '취소',
        buttonPositive: '허용',
      });
      if (granted === PermissionsAndroid.RESULTS.GRANTED) {
        console.log('카메라 권한을 얻었습니다.');
      } else {
        console.log('카메라 권한을 거부했습니다.');
      }
    } catch (err) {
      console.warn(err);
    }
  }

  useEffect(() => {
    (async function () {
      await requestCameraPermission();
    })();
  }, []);

  return (
    ...
  );
}

ScanHooks.ts

export const ScanHooks = () => {
  const [scanText, setScanText] = useRecoilState(scanedTextAtom);

  const changeScanText = (text: string) => setScanText(text);
  const initScanText = () => setScanText('');

  return {scanText, changeScanText, initScanText};
};

const scanedTextAtom = atom({
  key: 'scanedTextAtom',
  default: '',
});

Barcode.tsx

import {useEffect, useRef} from 'react';
import {Dimensions, StyleSheet, Vibration, View} from 'react-native';
import {useNavigation} from '@react-navigation/native';
import {Camera, CameraType} from 'react-native-camera-kit';
import {ScanHooks} from '@hooks/common/ScanHooks.ts';

const Barcode = () => {
  const {changeScanText, initScanText} = ScanHooks();

  const ref = useRef(null);
  const navigation = useNavigation();

  useEffect(() => {
    initScanText();
  }, []);

  const onBarCodeRead = (event: any) => {
    changeScanText(event.nativeEvent.codeStringValue); // 바코드 텍스트 저장
    Vibration.vibrate(100); // 바코드 인식 알림을 위한 진동처리
    navigation.goBack(); // 이전페이지로 이동
  };

  return (
    <View style={styles.container}>
      <Camera
        style={styles.scanner}
        ref={ref}
        cameraType={CameraType.Back} // front/back(default)
        scanBarcode
        showFrame={false}
        laserColor="rgba(255, 0, 0, 0)"
        frameColor="rgba(255, 0, 0, 0)"
        surfaceColor="rgba(255, 0, 0, 0)"
        onReadCode={onBarCodeRead}
      />
    </View>
  );
};

export default Barcode;

const styles = StyleSheet.create({
  container: {
    flex: 1,
    width: Dimensions.get('window').width,
    height: Dimensions.get('window').height,
  },
  scanner: {flex: 1},
});
반응형