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에 아래 권한을 추가했다.
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
'react-native' 카테고리의 다른 글
[RN] react-native-orientation 화면 고정 (0) | 2023.08.18 |
---|---|
[RN] react-native-pin-view PIN CODE 구현 (0) | 2023.08.11 |
[RN] react-native-vector-icons 사용하기 (0) | 2023.08.11 |
[RN] react-native 생체인증 구현, biometrics와 touch-id (1) | 2023.08.09 |
[RN] react-native-keychain 구현 (0) | 2023.08.09 |