📷 바코드, 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},
});