I'm trying to implement a feature in my app where I the user can select a picture from their camera roll and the app will decode a QR code in the image is detected.
I'm currently using react-native-camera-roll-picker: and react-native-qrcode-local-image:
The problem is the local QR code image library wants me to pass a local path and isn't compatible with the native uri provided by react-native-camera-roll-picker. I would use another library for decoding the image QR code but this one appears to be the only one that works on iOS and Android and scans from existing images rather than from the actual camera.
I've also tried implementing react-native-fetch-blob in order to temporarily save the camera roll image locally, but that's been giving me trouble as well:
This is my current attempt in a function that I call in the "callback" prop for react-native-camera-roll-picker (with previous attempts commented out):
_pickedImage(array,currentImg) {
console.log(currentImg)
var path = RNFS.DocumentDirectoryPath + '/pickedqr';
let rnfbURI = RNFetchBlob.wrap(RNFetchBlob.fs.asset(currentImg.uri))
const Blob = RNFetchBlob.polyfill.Blob
Blob.build(rnfbURI, {type:'image/jpg'}).then((b) => {
tmpBlob = b;
RNFetchBlob.fs.readFile(tmpBlob, 'base64').then((data) => {
console.log("Base64", data)
QRDecoder.decode(`data:image/gif;base64,${data}`, (error, result)=>{
console.log("Code", result)
console.log("Error", error)
});
});
})
/*fullPath = currentImg.uri.replace("assets-library://", "cdvfile://localhost/assets-library/")
QRDecoder.decode(fullPath, (error, result)=>{
console.log("Code", result)
console.log("Error", error)
});*/
/*let blb = Blob.build( rnfbURI, { type: 'image/jpg'})
console.log(blb)*/
/*RNFetchBlob.fs.readFile(rnfbURI, 'base64').then((data) => {
console.log("Base64", data)
QRDecoder.decode(`data:image/gif;base64,${data}`, (error, result)=>{
console.log("Code", result)
console.log("Error", error)
});
})*/
}
I'm at a total loss at the moment so any methods or insight would be much appreciated.
I'm trying to implement a feature in my app where I the user can select a picture from their camera roll and the app will decode a QR code in the image is detected.
I'm currently using react-native-camera-roll-picker: https://github.com/jeanpan/react-native-camera-roll-picker and react-native-qrcode-local-image: https://github.com/remobile/react-native-qrcode-local-image
The problem is the local QR code image library wants me to pass a local path and isn't compatible with the native uri provided by react-native-camera-roll-picker. I would use another library for decoding the image QR code but this one appears to be the only one that works on iOS and Android and scans from existing images rather than from the actual camera.
I've also tried implementing react-native-fetch-blob in order to temporarily save the camera roll image locally, but that's been giving me trouble as well: https://github.com/wkh237/react-native-fetch-blob
This is my current attempt in a function that I call in the "callback" prop for react-native-camera-roll-picker (with previous attempts commented out):
_pickedImage(array,currentImg) {
console.log(currentImg)
var path = RNFS.DocumentDirectoryPath + '/pickedqr';
let rnfbURI = RNFetchBlob.wrap(RNFetchBlob.fs.asset(currentImg.uri))
const Blob = RNFetchBlob.polyfill.Blob
Blob.build(rnfbURI, {type:'image/jpg'}).then((b) => {
tmpBlob = b;
RNFetchBlob.fs.readFile(tmpBlob, 'base64').then((data) => {
console.log("Base64", data)
QRDecoder.decode(`data:image/gif;base64,${data}`, (error, result)=>{
console.log("Code", result)
console.log("Error", error)
});
});
})
/*fullPath = currentImg.uri.replace("assets-library://", "cdvfile://localhost/assets-library/")
QRDecoder.decode(fullPath, (error, result)=>{
console.log("Code", result)
console.log("Error", error)
});*/
/*let blb = Blob.build( rnfbURI, { type: 'image/jpg'})
console.log(blb)*/
/*RNFetchBlob.fs.readFile(rnfbURI, 'base64').then((data) => {
console.log("Base64", data)
QRDecoder.decode(`data:image/gif;base64,${data}`, (error, result)=>{
console.log("Code", result)
console.log("Error", error)
});
})*/
}
I'm at a total loss at the moment so any methods or insight would be much appreciated.
Share Improve this question edited Dec 26, 2018 at 11:40 p u 1,4551 gold badge20 silver badges30 bronze badges asked Mar 11, 2017 at 13:57 ArminArmin 1,2813 gold badges18 silver badges31 bronze badges 5 |5 Answers
Reset to default 1you can use react-native-qrcode-scanner
to scan QR from images or directly through the camera.
INSTALLATION:
install dependency by using this command:
yarn add react-native-camera react-native-qr-scanner
link those libraries by using:
react-native link react-native-camera && react-native-qr-scanner
you need to add the permission to your AndroidManifest.xml of your project. This should be found in your android/app/src/main/AndroidManifest.xml
Add the following:
<uses-permission android:name="android.permission.CAMERA" />
<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" />
<uses-permission android:name="android.permission.VIBRATE"/>
With iOS 10 and higher, you need to add the "Privacy - Camera Usage Description" key to the info.plist of your project. This should be found in your_project/ios/your_project/Info.plist
. Add the following code:
<key>NSCameraUsageDescription</key>
<string/>
<key>NSPhotoLibraryUsageDescription</key>
<string/>
<key>NSMicrophoneUsageDescription</key>
<string/>
<key>NSPhotoLibraryAddUsageDescription</key>
<string/>
Usage:
import React, {Component} from 'react';
import {Platform, StyleSheet, Text, View, TouchableOpacity} from 'react-native';
import {QRreader} from 'react-native-qr-scanner';
import ImagePicker from 'react-native-image-picker';
export default class Scanner extends Component {
constructor(props) {
super(props);
this.state = {
reader: {
message: null,
data: null
}
};
}
render() {
return (
<View style={styles.container}>
<TouchableOpacity onPress={()=>{
this.openPhoto();
}}>
<Text style={{marginTop: 20}}>打开相册识别二维码</Text>
</TouchableOpacity>
<View>
{!this.state.reader? <Text>{!this.state.reader.message?'':`${this.state.reader.message}`}</Text>: <Text>{!this.state.reader.message?'':`${this.state.reader.message}:${this.state.reader.data}`}</Text>}
</View>
</View>
);
}
openPhoto(){
console.log('ImagePicker');
ImagePicker.launchImageLibrary({}, (response) => {
console.log('Response = ', response);
if (response.didCancel) {
console.log('User cancelled image picker');
}
else if (response.error) {
console.log('ImagePicker Error: ', response.error);
}
else if (response.customButton) {
console.log('User tapped custom button: ', response.customButton);
}
else {
if(response.uri){
var path = response.path;
if(!path){
path = response.uri;
}
QRreader(path).then((data)=>{
this.setState({reader: {
message: '识别成功',
data: data
}});
// 十秒后自动清空
setTimeout(() => {
this.setState({reader: {
message: null,
data: null
}})
}, 10000);
}).catch((err)=>{
this.setState({reader: {
message: '识别失败',
data: null
}});
});
}
}
});
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff'
}
});
you can read more about this library here: https://www.npmjs.com/package/react-native-qr-scanner
You can use react-native-camera
to solve this issue easily.
Here's the simple code snippet for that.
handleCodeDetected = (data) => {
// do whatever you want to do with data
}
...
...
<RNCamera
type={RNCamera.Constants.Type.back}
barCodeTypes={[RNCamera.Constants.BarCodeType.qr]}
onBarCodeRead={this.handleCodeDetected}
style={styles.preview}
/>
This answer solved it for me. Created native method to covert uri in path, here is my code:
@ReactMethod
public void getRealPathFromURI(String contentUriString, Promise promise) {
Uri contentUri = Uri.parse(contentUriString);
Cursor cursor = null;
try {
String wholeID = DocumentsContract.getDocumentId(contentUri);
String id = wholeID.split(":")[1];
String[] column = { MediaStore.Images.Media.DATA };
String sel = MediaStore.Images.Media._ID + "=?";
cursor = reactContext.getContentResolver().
query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
column, sel, new String[]{ id }, null);
int columnIndex = cursor.getColumnIndex(column[0]);
String filePath = "";
if (cursor.moveToFirst()) {
filePath = cursor.getString(columnIndex);
}
promise.resolve(filePath);
} catch (Throwable e) {
promise.reject(e);
} finally {
if (cursor != null) {
cursor.close();
}
}
}
And js:
DocumentPicker.pick({ type }).then((document: DocumentPickerResponse) => {
MyNativeModule.getRealPathFromURI(document.uri).then((path) => {
QRCodeLocalImage.decode(path, (err, res) => {
callback(err, { qrData: res });
});
});
});
You can just use react-native-rn-zxing:
npm i react-native-rn-zxing
then link it :
react-native link react-native-rn-zxing
Usage :
import RnZxing from 'react-native-rn-zxing';
...
// Pass the callback as a parameter
RnZxing.showQrReader(this.onBarcodeScanned);
...
// Define the callback function to handle data after scan
onBarcodeScanned = (data) => {
this.setState({data: data});
};
You can use rn-qr-generator
It can detect QR code in image
RNQRGenerator.detect({
uri: PATH_TO_IMAGE, // local path of the image. Can be skipped if base64 is passed.
base64: imageBase64String, // If uri is passed this option will be skipped.
})
.then(response => {
const { values } = response; // Array of detected QR code values. Empty if nothing found.
})
RCTQRCodeLocalImage.m
#23 with this solutionhttp://stackoverflow.com/questions/7221167/how-to-check-if-an-alasset-still-exists-using-a-url
. – Sagar Khatri Commented Mar 20, 2017 at 6:53