I am trying to download image which is coming from api.I am using rn-fetch-blob package to download file. But the problem here is when i click on download file do get downloaded but it gives some error saying
Download manager donwload failed , the file does not downloaded to destination
Any help would be great.
This is how i implemented rn-fetch-blob in my code
const checkPermission = async (image: string) => {
if (Platform.OS === 'android') {
try {
const granted = await PermissionsAndroid.request(
PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE,
{
title: 'Storage Permission Required',
message: 'This app needs access to your storage to download Photos',
buttonPositive: 'OK',
},
);
if (granted === PermissionsAndroid.RESULTS.GRANTED) {
console.log('Storage Permission Granted.');
handleDownload(image);
} else {
Alert.alert('Storage Permission Not Granted');
}
} catch (err) {
console.warn(err);
}
}
};
const getExtention = (filename: string) => {
//To get the file extension
return /[.]/.exec(filename) ? /[^.]+$/.exec(filename) : undefined;
};
// eslint-disable-next-line #typescript-eslint/no-unused-vars
const handleDownload = async (image: string) => {
let date = new Date();
let image_url = image;
let ext = getExtention(image_url);
const {config, fs} = RNFetchBlob;
let pictureDir = fs.dirs.PictureDir;
let options = {
fileCache: true,
addAndroidDownloads: {
useDownloadManager: true,
notification: true,
path:
pictureDir +
'/wallace_' +
Math.floor(date.getTime() + date.getSeconds() / 2) +
'.' +
ext,
description: 'Image',
},
};
config(options)
.fetch('GET', image_url)
.then((res) => {
console.log(res.path());
Alert.alert('Image Downloaded Successfully.');
})
.catch((err) => {
Alert.alert('Download Failed', err.message);
});
};
return <View>
<TouchableWithoutFeedback
onPress={() => handleShare(src.portrait)}>
<Text variant="buttonText">Share Image</Text>
</TouchableWithoutFeedback>
</View>
Related
I am trying to download a pdf from the URL. I am using RNFetchBlob to download pdf from URLs. It is also getting downloaded successfully. But it doesn't open. It says invalid format. At first, I thought it might be because I was running in an emulator but I tried on a real device also it is also giving an invalid format.
Below is the code I am using:
const downloadFile = async (url, title) => {
const grantedstorage = await PermissionsAndroid.request(
PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE);
if (grantedstorage === PermissionsAndroid.RESULTS.GRANTED) {
const { dirs } = RNFetchBlob.fs;
const dirToSave = Platform.OS == 'ios' ? dirs.DocumentDir : dirs.DownloadDir
const configfb = {
fileCache: true,
addAndroidDownloads: {
useDownloadManager: true,
notification: true,
mediaScannable: true,
title: title + ".pdf",
path: dirToSave + "/" + title + ".pdf",
mime : 'application/pdf',
}
}
const configOptions = Platform.select({
ios: {
fileCache: configfb.fileCache,
title: configfb.title,
path: configfb.path,
appendExt: 'pdf',
notification: configfb.notification
},
android: configfb,
});
RNFetchBlob.config(configOptions)
.fetch('GET', url,{})
.then((res) => {
if (Platform.OS === "ios") {
RNFetchBlob.fs.writeFile(configfb.path, res.data, 'base64');
RNFetchBlob.ios.previewDocument(configfb.path);
}
if (Platform.OS == 'android') {
alert('File downloaded');
}
console.log('The file saved to ', res.path());
})
.catch((e) => {
console.log('Catch ERROR', e.message)
});
} else if (grantedstorage === PermissionsAndroid.RESULTS.DENIED) {
alert("Please allow permission to storage if you want to download file.");
}
else {
alert("Please go to app setting and allow permission to storage.");
}
}
Please help me solve this. And yes the URL is of a protected pdf if that is of any concern, please let me know.
Im strugglling with an error that im not capable of get a solution and i dont know if its happening in the front or in the back of the app.
Im trying to follow a tutorial where the guy is setting up an app that records your voice and return it as text from Google API speech to text.
this is the front part, the app is failing in the axios.post, the request is not passing and keeps loading until the error log says it cannot connect to the path.
import React, { Component } from 'react'
import {
StyleSheet, Text, View, TouchableOpacity, ActivityIndicator, Platform,
} from 'react-native'
// import { Audio, Permissions, FileSystem } from 'expo'
import * as Permissions from 'expo-permissions'
import { Audio } from 'expo-av'
import * as FileSystem from 'expo-file-system';
import axios from 'axios'
const styles = StyleSheet.create({
container: {
marginTop: 40,
backgroundColor: '#fff',
alignItems: 'center',
},
button: {
backgroundColor: '#1e88e5',
paddingVertical: 20,
width: '90%',
alignItems: 'center',
borderRadius: 5,
padding: 8,
marginTop: 20,
},
text: {
color: '#fff',
}
})
/*this.recordingSettings = JSON.parse(JSON.stringify(Audio.RECORDING_OPTIONS_PRESET_HIGH_QUALITY = */let recordingOptions = {
android: {
extension: '.m4a',
outputFormat: Audio.RECORDING_OPTION_ANDROID_OUTPUT_FORMAT_MPEG_4,
audioEncoder: Audio.RECORDING_OPTION_ANDROID_AUDIO_ENCODER_AAC,
sampleRate: 44100,
numberOfChannels: 2,
bitRate: 128000,
},
ios: {
extension: '.m4a',
outputFormat: Audio.RECORDING_OPTION_IOS_OUTPUT_FORMAT_MPEG4AAC,
audioQuality: Audio.RECORDING_OPTION_IOS_AUDIO_QUALITY_HIGH,
sampleRate: 44100,
numberOfChannels: 2,
bitRate: 128000,
linearPCMBitDepth: 16,
linearPCMIsBigEndian: false,
linearPCMIsFloat: false,
},
};
export default class SpeechToTextButton extends Component {
constructor(props) {
super(props)
this.recording = null
this.state = {
isRecording: false,
//we would like to know if data fetching is in progress
isFetching: false,
//we will write the transcript result here
transcript: '',
}
}
startRecording = async () => {
// request permissions to record audio
const { status } = await Permissions.askAsync(Permissions.AUDIO_RECORDING)
// if the user doesn't allow us to do so - return as we can't do anything further :(
if (status !== 'granted') return
// when status is granted - setting up our state
this.setState({ isRecording: true })
// basic settings before we start recording,
// you can read more about each of them in expo documentation on Audio
await Audio.setAudioModeAsync({
allowsRecordingIOS: true,
interruptionModeIOS: Audio.INTERRUPTION_MODE_IOS_DO_NOT_MIX,
playsInSilentModeIOS: true,
interruptionModeAndroid: Audio.INTERRUPTION_MODE_ANDROID_DO_NOT_MIX,
playThroughEarpieceAndroid: true,
})
const recording = new Audio.Recording()
try {
// here we pass our recording options
await recording.prepareToRecordAsync(recordingOptions)
// and finally start the record
await recording.startAsync()
console.log('funcionaaa')
} catch (error) {
console.log(error)
// we will take a closer look at stopRecording function further in this article
this.stopRecording()
console.log('no funca')
}
// if recording was successful we store the result in variable,
// so we can refer to it from other functions of our component
this.recording = recording
}
stopRecording = async () => {
// set our state to false, so the UI knows that we've stopped the recording
this.setState({ isRecording: false })
try {
// stop the recording
await this.recording.stopAndUnloadAsync()
console.log('aca tiene que parar')
} catch (error) {
console.log(error)
}
}
getTranscription = async () => {
// set isFetching to true, so the UI knows about it
this.setState({ isFetching: true })
try {
// take the uri of the recorded audio from the file system
const { uri } = await FileSystem.getInfoAsync(this.recording.getURI())
// now we create formData which will be sent to our backend
const formData = new FormData()
formData.append('file', {
uri,
// as different audio types are used for android and ios - we should handle it
type: Platform.OS === 'ios' ? 'audio/x-wav' : 'audio/m4a',
name: Platform.OS === 'ios' ? `${Date.now()}.wav` : `${Date.now()}.m4a`,
})
// post the formData to our backend
const { data } = await axios.post('http://190.19.68.120/api/speech', formData, {
headers: {
'Content-Type': 'multipart/form-data',
},
})
console.log(data)
// set transcript from the data which we received from the api
this.setState({ transcript: data.transcript })
} catch (error) {
console.log('There was an error reading file', error.request)
this.stopRecording()
// we will take a closer look at resetRecording function further down
this.resetRecording()
}
// set isFetching to false so the UI can properly react on that
this.setState({ isFetching: false })
}
deleteRecordingFile = async () => {
// deleting file
try {
const info = await FileSystem.getInfoAsync(this.recording.getURI())
await FileSystem.deleteAsync(info.uri)
} catch (error) {
console.log('There was an error deleting recorded file', error)
}
}
resetRecording = () => {
this.deleteRecordingFile()
this.recording = null
}
handleOnPressOut = () => {
// first we stop the recording
this.stopRecording()
console.log('para en el pressout')
// second we interact with our backend
this.getTranscription()
}
render() {
const {
isRecording, transcript, isFetching,
} = this.state
return (
<View style={styles.container}>
<TouchableOpacity
style={styles.button}
onPressIn={this.startRecording}
onPressOut={this.handleOnPressOut}
>
{isFetching && <ActivityIndicator color="#ffffff" />}
{!isFetching &&
<Text style={styles.text}>
{isRecording ? 'Recording...' : 'Start recording'}
</Text>
}
</TouchableOpacity>
<Text>
{transcript}
</Text>
</View>
)
}
}
Here it is the back part, where i receive the request from the front and send the audio to the google API
'use strict';
const Hapi = require('#hapi/hapi');
const fs = require('fs')
const axios = require('axios')
const speech = require('#google-cloud/speech');
const ffmpeg = require('fluent-ffmpeg');
const client = new speech.SpeechClient();
const init = async () => {
const server = Hapi.server({
port: 3005,
host: 'localhost'
});
server.route({
method: 'POST',
path: '/speech',
config: {
handler: async (request, h) => {
const data = request.payload;
console.log(data)
if (data.file) {
const name = data.file.hapi.filename;
const path = __dirname + "/uploads/" + name;
const encodedPath = __dirname + "/uploads/encoded_" + name;
const file = fs.createWriteStream(path);
file.on('error', (err) => console.error(err));
data.file.pipe(file);
return new Promise(resolve => {
data.file.on('end', async (err) => {
const ret = {
filename: data.name,
headers: data.file.hapi.headers
}
ffmpeg()
.input(path)
.outputOptions([
'-f s16le',
'-acodec pcm_s16le',
'-vn',
'-ac 1',
'-ar 41k',
'-map_metadata -1'
])
.save(encodedPath)
.on('end', async () => {
const savedFile = fs.readFileSync(encodedPath)
const audioBytes = savedFile.toString('base64');
const audio = {
content: audioBytes,
}
const sttConfig = {
enableAutomaticPunctuation: false,
encoding: "LINEAR16",
sampleRateHertz: 41000,
languageCode: "en-US",
model: "default"
}
const request = {
audio: audio,
config: sttConfig,
}
const [response] = await client.recognize(request);
const transcription = response.results
.map(result => result.alternatives[0].transcript)
.join('\n');
fs.unlinkSync(path)
fs.unlinkSync(encodedPath)
resolve(JSON.stringify({ ...ret, transcript: transcription }))
})
})
})
}
},
payload: {
output: 'stream',
parse: true,
}
}
})
await server.start();
console.log('Server running on %s', server.info.uri);
};
process.on('unhandledRejection', (err) => {
console.log(err);
});
init();
i thought i could try migrating the server to express.js but under handler, i got payload key, and i dont know what to do with that in an express server.
I trying to upload a file image to API in postman thats work fine but when a i try file image from ImagePicker didnot work.
I think doing something wrong when create formdata
Handler
ImagePicker.showImagePicker(optionsImagePicker, (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 {
// const source = { image: response.data };
let photo = { uri: response.uri}
let formdata = new FormData();
formdata.append("product[name]", 'test')
formdata.append("product[price]", 10)
formdata.append("product[category_ids][]", 2)
formdata.append("product[description]", '12dsadadsa')
formdata.append("product[images_attributes[0][file]]", {uri: photo.uri, name: 'image.jpg', type: 'image/jpeg'})
updateProfilePic(formdata)
// You can also display the image using data:
// const source = { uri: 'data:image/jpeg;base64,' + response.data };
// this.setState({
// avatarSource: source,
// });
}
});
Service
export function uploadImageProfile(data: any): Promise<any> {
const config = {
headers: {
'Content-Type': 'multipart/form-data',
},
};
return api.post('/users/profilepic', {image: data}, config).then((res) => {
console.log(res.data);
return res.data;
});
}
Your form data must be like that.
formdata.append('file',{
uri: Platform.OS === 'android' ? photo.uri : 'file://' + photo.uri,
name: 'test',
type: 'image/jpeg' // or your mime type what you want
});
Then
axios.post('/users/profilepic', formdata, config).then((res) => {
console.log(res.data);
return res.data;
});
let formdata = new FormData();
formdata.append('file',{
uri: Platform.OS === 'android' ? photo.uri : 'file://' + photo.uri,
name: 'test',
type: 'image/jpeg'
});
use method:"POST" and spread formdata.getHeaders() into header
let reqObj = {
method: "POST",
url: 'http://example.com/upload/image',
headers: {
'x-sh-auth': token,
...formdata.getHeaders()
},
maxContentLength: Infinity,
maxBodyLength: Infinity
};
axios(reqObj).then(result => {
console.log(result)
}).catch(error => {
console.log(error)
});
I changed how I send image to the server. Now send im base64 and in server convert to file with fs.
const uploadImage = {
imageBase64: 'data:' + response.type + ';base64,' + response.data,
};
updateProfilePic(uploadImage);
server side
async saveImageProfile(imageBase64, logedUserData) {
let base64Image = imageBase64.imageBase64.split(';base64,').pop();
let type = imageBase64.imageBase64.split('image/').pop().split(';')[0];
let newFileName = `${logedUserData.id}.${type}`;
if (imageFileFilter(type)) {
const file = await fs.writeFile('./files/' + newFileName, base64Image, { encoding: 'base64' }, function (err) {
console.log('File created');
});
const url = `${baseUrl}/users/files/${newFileName}`;
this.updateRefProfilePic(url, logedUserData);
}
else {
throw new BadRequestException("Tipo de arquivo não suportado");
}
}
I try to upload some image from the camera gallery on localhost and prod environnement. My code works with a valid url like : https://res.cloudinary.com/dtdiwoz7o/image/upload/v1586706052/cn-2016-sashaonyshchenko-1920x1920-1510074905_dyfldk.jpg
But when I pass the image file path, it's return an 400 error.
Here is my code with some log :
_avatarClicked = () => {
const options = {
title: 'Select Photo',
storageOptions: {
skipBackup: true,
path: 'images',
},
};
ImagePicker.showImagePicker(options, (response) => {
if (response.didCancel) {
return
}
else if (response.error) {
return
}
else {
let data = {
file: response.uri,
upload_preset: "my_preset_name",
}
axios.post("https://api.cloudinary.com/v1_1/my_cloud_name/image/upload", data)
.then(res => console.log(res))
.catch(err => console.log(err))
}
})
}
log of my repsponse.uri :
(file:///Users/clement/Library/Developer/CoreSimulator/Devices/62E85527-A2AC-46CD-B517-E6039F99E056/data/Containers/Data/Application/E218E950-3A1C-40EB-8289-3837EC89FBBB/Documents/images/46674162-E32B-4302-B28A-5EF9150206D0.jpg)
I tried to replace in data file this by this 'const source' but it doesn't work :
const source = {
uri: response.uri,
type: response.type,
name: response.fileName,
}
I saw and test this on the react-native)image-picker documentation but I've got the same 400 error...
// const source = { uri: 'data:image/jpeg;base64,' + response.data };
I also try to Base64.encode(response.url) or Base64.encodeURI(response.url)
Please, can you help me ?
And sorry for my bad english
"react-native": "~0.61.4",
"react-native-image-picker": "^2.3.1",
///////////////////////////
I found the solution :
let data = {
file: 'data:image/jpg;base64,' + response.data,
upload_preset: "my_preset_name",
}
axios.post("https://api.cloudinary.com/v1_1/my_cloud_name/image/upload/", data)
.then(res => console.log(res))
.catch(err => console.log(err))
Ok I find the solution :
let data = {
file: 'data:image/jpg;base64,' + response.data,
upload_preset: "my_preset_name",
}
axios.post("https://api.cloudinary.com/v1_1/my_cloud_name/image/upload/", data)
.then(res => console.log(res))
.catch(err => console.log(err))
I have to let user download a pdf file whene he clock on button, I find that I have to use rn-fetch-blob instead of react-native-fetch-blob. In the documentation there is this code:
const { config, fs } = RNFetchBlob
let DownloadDir = fs.dirs.DownloadDir // this is the Downloads directory.
let options = {
fileCache: true,
addAndroidDownloads : {
useDownloadManager : true, //uses the device's native download manager.
notification : true,
title : "Notification Title", // Title of download notification.
path: DownloadDir + "/me_"+ '.' + extension, // this is the path where your download file will be in
description : 'Downloading file.'
}
}
config(options)
.fetch('GET',"https://whatever_url_u _want/)
.then((res) => {
//console.log("Success");
})
.catch((err) => {console.log('error')}) // To execute when download cancelled and other errors
}
I have no idea what I can do with this ! how to use use it in TouchableOpacity onPress prop ? please someone can provide a detailed example
PS. I call an API with POST methode and I receive a link of PDF file. I think
I have to set this link like that
config(options)
.fetch('GET',this.state.data.link)
Add below permissions in AndroidManifest.xml
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.DOWNLOAD_WITHOUT_NOTIFICATION" />
To use downloadmanager, add below action in intent in AndroidManifest.xml
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<action android:name="android.intent.action.DOWNLOAD_COMPLETE"/>
</intent-filter>
import PermissionsAndroid, Alert from react native (android only)
import {PermissionsAndroid, Alert} from "react-native";
Now in component
actualDownload = () => {
const { dirs } = RNFetchBlob.fs;
RNFetchBlob.config({
fileCache: true,
addAndroidDownloads: {
useDownloadManager: true,
notification: true,
mediaScannable: true,
title: `test.pdf`,
path: `${dirs.DownloadDir}/test.pdf`,
},
})
.fetch('GET', 'http://www.africau.edu/images/default/sample.pdf', {})
.then((res) => {
console.log('The file saved to ', res.path());
})
.catch((e) => {
console.log(e)
});
}
downloadFile = () => {
try {
const granted = await PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE);
if (granted === PermissionsAndroid.RESULTS.GRANTED) {
this.actualDownload();
} else {
Alert.alert('Permission Denied!', 'You need to give storage permission to download the file');
}
} catch (err) {
console.warn(err);
}
}
render(){
<TouchableOpacity onPress={this.downloadFile}>
<Text>Download!!!</Text>
</TouchableOpacity>
}
CAUTION: You need to ask for storage permission for android 6 or higher in runtime
LATEST WORKING SOLN both ios/android
Follow mosabbir tuhin's answer and then use my function actualDownload() and permissionFunc() to make pdf work on ios also.
const permissionFunc = async () => {
if (Platform.OS == 'ios') {
actualDownload();
} else {
if (downloaded) {
try {
const granted = await PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE);
if (granted === PermissionsAndroid.RESULTS.GRANTED) {
actualDownload();
} else {
showSnackbar('You need to give storage permission to download the file');
}
} catch (err) {
console.warn(err);
}
}
else {
showSnackbar('File is already downloaded.');
}
}
}
const actualDownload = () => {
const { dirs } = RNFetchBlob.fs;
const dirToSave = Platform.OS == 'ios' ? dirs.DocumentDir : dirs.DownloadDir
const configfb = {
fileCache: true,
useDownloadManager: true,
notification: true,
mediaScannable: true,
title: pdfInfo.pdf,
path: `${dirToSave}/${pdfInfo.pdf}`,
}
const configOptions = Platform.select({
ios: {
fileCache: configfb.fileCache,
title: configfb.title,
path: configfb.path,
appendExt: 'pdf',
},
android: configfb,
});
console.log('The file saved to 23233', configfb, dirs);
RNFetchBlob.config(configOptions)
.fetch('GET', `https://aquatherm.s3.ap-south-1.amazonaws.com/pdfs/${pdfInfo.pdf}`, {})
.then((res) => {
if (Platform.OS === "ios") {
RNFetchBlob.fs.writeFile(configfb.path, res.data, 'base64');
RNFetchBlob.ios.previewDocument(configfb.path);
}
setisdownloaded(false)
if (Platform.OS == 'android') {
showSnackbar('File downloaded');
}
console.log('The file saved to ', res);
})
.catch((e) => {
setisdownloaded(true)
showSnackbar(e.message);
console.log('The file saved to ERROR', e.message)
});
}