Upload video in react-native - javascript

Is there a way to upload video to a server in react native?
I've looked into the react-native-uploader plugin on github, but it doesn't give any guidance on video uploads if it's even possible with that plugin.

Just use fetch for uploading
let formData = new FormData();
formData.append("videoFile", {
name: name.mp4,
uri: video.uri,
type: 'video/mp4'
});
formData.append("id", "1234567");
try {
let response = await fetch(url, {
method: 'post',
headers: {
'Content-Type': 'multipart/form-data',
},
body: formData
});
return await response.json();
}
catch (error) {
console.log('error : ' + error);
return error;
}

Here is another answer, using rn-fetch-blob in RN 0.57.8.
postVideo = (video,url) => {
RNFetchBlob.fetch('POST',url, {
'content-type': 'multipart/form-data',
"Accept":"multipart/form-data",
'access-token': AuthToken.token, //token from server
},[
//the value of name depends on the key from server
{name: 'video', filename: 'vid.mp4', data: RNFetchBlob.wrap(video.uri) },
]).then(response => response.json())
.then(response => {
if (response.status === 'success') {
alert("Upload success");
this.props.navigation.navigate('publish');
} else {
alert(response.msg);
}})
.catch((err) => {
alert(err);
})
}

Yes, it is possible.
you have to be running React Native 0.45.0 or higher, which do support accessing videos from camera roll.
you have to receive reference to image/video access from camera roll by calling CameraRoll.getPhotos(params) (more on this in docs)
then, use RNUploader.upload(...) to send assets to your serve (you need to link lib before!)

Related

Cannot upload file with FormData on React Native

I can't upload file with FormData to React Native. I am using react-native-document-picker and here is my code:
try {
const pickerResult = await DocumentPicker.pickSingle({
presentationStyle: 'fullScreen',
copyTo: 'documentDirectory',
type: [DocumentPicker.types.pdf],
mode: 'import',
});
setAccountStatement(pickerResult);
let data = new FormData();
data.append('file', {
uri: pickerResult.fileCopyUri,
type: pickerResult.type,
name: pickerResult.name,
fileName: pickerResult.name,
size: pickerResult.size,
});
console.log(data);
http
.post('url', data, {
headers: {
'Content-Type': 'multipart/form-data',
},
})
.then(response => {
console.log(response);
})
.catch(error => {
console.log(error);
});
}
};
Here's the example response I get from react-native-document-picker
{
"fileCopyUri": "file:///data/user/0/com.crust/files/497ed9ec-79fb-4bfb-81d1-74907f851c08/receipt_20220929065209.pdf",
"name": "receipt_20220929065209.pdf",
"size": 36036,
"type": "application/pdf",
"uri": "content://com.android.providers.media.documents/document/document%3A223934"
}
Please how do I go about this? I get
Error: Request failed with status code 415
from the server and I do not know what I am doing wrong.
So i managed to solve the issue after 2 days of tirelessly trying to figure it out , i managed to have two different solutions to the problem
1. Using Fetch API
const fd = new FormData();
fd.append('file', {
uri: pickerResult.fileCopyUri,
type: pickerResult.type,
name: pickerResult.name,
fileName: pickerResult.name,
size: pickerResult.size,
});
try {
const res = await fetch(
'url',
{
method: 'POST',
mode: 'no-cors',
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'multipart/form-data',
},
body: fd,
},
);
console.log(res.status, res.statusText);
if (res.ok) {
console.log('Success');
} else {
console.log(await res.json());
}
} catch (error) {
console.error(error);
}
2. Downgrading Axios to "^0.24.0"
after i figured it out using the fetch api ,i was able to do a deeper research and found out that,
axios has a problem with the FormData() object, from version "^0.25.0"
, so i
downgraded my axios version to "^0.24.0"
and it worked like a charm including image upload using "FormData()"

how to upload internal storage image to server in react native. image not uploading to server. in react native

I am new to react native. I am trying to upload my digital signature image which is stored in internal storage.
path is like this = '/storage/emulated/0/DCIM/1616657741752.png'.
but image not uploading then think that the problem is with this path - '/storage/emulated/0'.
because there no folder called DCIM in '/storage/emulated/0' this path.
so I remove this - '/storage/emulated/0' by using below code
this.setState({base64: paths.split('/storage/emulated/0').pop()})
But still same problem my image not uploading to server. over all my image is visible in my phone internal storage in DCIM folder. I do not know what to do now.
here is my code
base64:null,
_onSaveEvent = (result) => {
this.checkAndroidPermission(result)
}
checkAndroidPermission = async (result) => {
if (Platform.OS === 'ios') {
save(result);
} else {
try {
const granted = await PermissionsAndroid.request(
PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE,
);
if (granted === PermissionsAndroid.RESULTS.GRANTED) {
// Once user grant the permission start downloading
this.save(result);
} else {
if (Platform.OS === 'android') {
ToastAndroid.show('Storage Permission denied.', ToastAndroid.SHORT);
} else {
AlertIOS.alert('Storage Permission denied.');
}
}
} catch (err) {
// To handle permission related exception
console.warn('tryerr', err);
}
}
};
save = async (result) => {
const paths = `${
RNFetchBlob.fs.dirs.DCIMDir
}/${new Date().getTime()}.png`; // where u need to put that
try {
RNFetchBlob.fs
.writeFile(paths, result.encoded, 'base64')//data.base64 is your photo with convert base64
.then((value) => {
RNFetchBlob.fs
.scanFile([{path: paths}]) //after save to notify gallry for that
.then(() => {
this.setState({base64: paths.split('/storage/emulated/0').pop()})
console.log('scan file success');
console.log("this is fuckiiing file"+ this.state.base64)
})
.catch((err) => {
console.log('scan file error');
});
})
.catch((e) => console.log(e.message));
} catch (error) {
console.log('fileerror', error.message);
}
}
formData.append('digital_signature',this.state.base64);
console.log(JSON.stringify(formData))
fetch('https://abc.tech/Android_API_CI/upload_multipart_data',
{
method: 'post',
body : formData,
headers: {
'Content-Type': 'multipart/form-data;',
},
<SignatureCapture
style={styles.signature}
ref="sign"
onSaveEvent={this._onSaveEvent}
onDragEvent={this._onDragEvent}
saveImageFileInExtStorage={true}
showNativeButtons={false}
showTitleLabel={false}
viewMode={'portrait'}
/>
Here is your Ans and also put into the function may this helps
const file = {
uri:
Platform.OS == 'android'
? '/storage/emulated/0/DCIM/1616657741752.png' //path to your file
: 'file:///storage/emulated/0/DCIM/1616657741752.png',
name: 'sign.png', // which go on server on your file name
type: 'image/png', // e.g. 'image/jpg'
};
formData.append('digital_signature',file);
console.log(JSON.stringify(formData))
fetch('https://abc.tech/Android_API_CI/upload_multipart_data',
{
method: 'post',
body : formData,
headers: {
'Content-Type': 'multipart/form-data;',
},

antd upload api: how to return promise

I am working with antd framework and I have to use upload API.
This is the signature:
action: Uploading URL : string|(file) => Promise
I am invoking the API in this way trying to return a Promise:
<Upload {...propsUpload}>
<Button> <Icon type="upload" />Upload</Button>
</Upload>
with propsUpload that refers to function uploadMedia
const propsUpload = {
action: this.uploadMedia,
listType: 'picture',
defaultFileList: [],
className: 'upload-list-inline',
};
and this is the function uploadMedia
uploadMedia = (file) => {
let formData = new FormData();
formData.append('file', file);
formData.append('uuid', this.generateuuid());
formData.append('domain', 'POST');
formData.append('filename', file.name );
return fetch(process.env.REACT_APP_API_URL +
'/v100/media/upload', {
method: 'POST',
credentials: 'include',
headers: {
Accept: 'application/json'
},
body: formData
})
.then(response => response.json())
.then(data => data.data)
.catch(error => {
console.log('Error fetching profile ' + error)
})
}
The file is uploaded to server correctly.
But after the call to API, antd try to do another call that fails, maybe because I am not returning the correct value from function.
As result the thumbnail is displayed with red border and and error is shownd. In the image below there are both (the call that fails and image with red border)
What type of object I have to return in function uploadMedia to use api correctly?
Thanks
I haven't used antd but looking at the docs of Uplaod component I think you're using it wrong. Look at the examples there and see the code, action expects either a URL or a Promise that will return this URl. And Upload in this case will make request itself, so you don't need to do fetch. And your promise returns the data (object) so the Upload sends the request to [object Object] (which is what's returned by .toString() when applied to an object in JS)
EDIT
Try to check all examples in docs, I can see that there is an example when you want to manually upload the file (if you really need it)
For anyone looking to access the response object after calling the API. There are two ways you can get access to the response.
Implement a custom API request mentioned as in other answers for this question.
Use the onChange method provided by AntD (Which is the easier than utilizing the custom request)
I will explain the second approach below using a code block.
const fileUploadProps = {
name: "file",
action: config.remote + "api/file",
method: "POST",
showUploadList: false,
headers: {
authorization: "authorization-text",
contentType: "multipart/form-data"
},
onChange(info) {
if (info.file.status === "done") {
const { response } = info.file;
updateProfile(response.payload.file);
} else if (info.file.status === "error") {
message.error("Error uploading the file");
props.endLoad();
}
},
beforeUpload(file) {
const isJpgOrPng = file.type === "image/jpeg" || file.type === "image/png";
if (!isJpgOrPng) {
message.error("You can only upload JPG/PNG file!");
}
const isLt2M = file.size / 1024 / 1024 < 2;
const isGT20K = file.size / 1024 > 20;
if (!isLt2M) {
message.error("Image must smaller than 2MB!");
}
if (!isGT20K) {
message.error("Image must larger than 20KB!");
}
if (isJpgOrPng && isLt2M && isGT20K) {
props.startLoad();
return true;
} else {
return false;
}
}
};
In Render function I have the AntD upload component
<Upload {...fileUploadProps}>
<Button icon={<CameraFilled style={{ fontSize: "30px" }} />}></Button>
</Upload>
You can notice how I got the access to the response object inside onChange function.
Once the upload is complete it will call the onChange function having response object inside the info object.
So from there you can get access to your data object easily and call the next method.
I solved using api customRequest in this way:
uploadMedia = (componentsData) => {
let formData = new FormData();
formData.append('file', componentsData.file);
formData.append('uuid', this.generateuuid());
formData.append('domain', 'POST');
formData.append('filename', componentsData.file.name );
fetch(process.env.REACT_APP_API_URL + '/v100/media/upload', {
method: 'POST',
credentials: 'include',
headers: {
Accept: 'application/json'
},
body: formData
})
.then(response => response.json())
.then(data => data.data)
.then(data=> componentsData.onSuccess())
.catch(error => {
console.log('Error fetching profile ' + error)
componentsData.onError("Error uploading image")
})
}
For those who are not clear how to actually implement it (and it is unclear in docs):
Just implement a customRequest function in the props that accepts two callbacks, which are onError and onSuccess, and other data such as file and filename.
Like this
const props = {
customRequest: (componentsData) => {
let formData = new FormData();
formData.append('file', componentsData.file);
formData.append('uuid', this.generateuuid());
formData.append('domain', 'POST');
formData.append('filename', componentsData.file.name );
fetch(process.env.REACT_APP_API_URL + '/v100/media/upload', {
method: 'POST',
credentials: 'include',
headers: {
Accept: 'application/json'
},
body: formData
})
.then(response => response.json())
.then(data => data.data)
.then(data=> componentsData.onSuccess())
.catch(error => {
console.log('Error fetching profile ' + error)
componentsData.onError("Error uploading image")
})
}
}
And let Upload component receive the props.
const App = () => {
return <Upload {...props} />
}

Missing request token for request

Get all contacts from phonebook and upload to server but got following error.
While append image in request body FormData
Tried code
pass file url contact thumbnailPath
const path = con.thumbnailPath
body.append('image', {
uri: path,
type: 'image/jpeg',
name: 'photo.jpg',
type: 'multipart/form-data'
})
Tried code
pass file url contact thumbnailPath without "file://"
const path = con.thumbnailPath.replace('file://', '')
body.append('image', {
uri: path,
type: 'image/jpeg',
name: 'photo.jpg',
type: 'multipart/form-data'
})
Tried code
check file exist on path or not with using react-native-fs
if (con.thumbnailPath != '') {
let isExist = RNFS.exists(con.thumbnailPath)
if (isExist) {
const path = con.thumbnailPath.replace('file://', '')
console.log("Exist", path)
body.append('image', {
uri: path,
type: 'image/jpeg',
name: 'photo.jpg',
type: 'multipart/form-data'
})
}
}
Request
fetch(url, {
method: 'POST',
headers: {
'Authorization': token,
'token': token
},
body: params
})
.then((res) => res.json())
.then((json) => {
console.log("RESPONSE:- ", json)
if (json.response[0].status == 'false') {
let msg = json.response[0].response_msg
callback(new Error(msg), json.response[0])
}
else {
callback(null, json.response[0])
}
})
.catch((err) => {
console.log(err)
callback(err, null)
})
The issues comes from react-native#0.63.2's internal bug.
A quick solution is to revert this commit: https://github.com/facebook/react-native/commit/31980094107ed37f8de70972dbcc319cc9a26339#diff-9a034658197479288c4d346a0eb4d98c
After manually revert this commit in node_modules, recompile the app and the image uploading will be working without any issues.
Replace the function loadImageForURL in /Libraries/Image/RCTLocalAssetImageLoader.mm with the following:
- (RCTImageLoaderCancellationBlock)loadImageForURL:(NSURL *)imageURL
size:(CGSize)size
scale:(CGFloat)scale
resizeMode:(RCTResizeMode)resizeMode
progressHandler:(RCTImageLoaderProgressBlock)progressHandler
partialLoadHandler:(RCTImageLoaderPartialLoadBlock)partialLoadHandler
completionHandler:(RCTImageLoaderCompletionBlock)completionHandler
{
__block auto cancelled = std::make_shared<std::atomic<bool>>(false);
RCTExecuteOnMainQueue(^{
if (cancelled->load()) {
return;
}
UIImage *image = RCTImageFromLocalAssetURL(imageURL);
if (image) {
if (progressHandler) {
progressHandler(1, 1);
}
completionHandler(nil, image);
} else {
NSString *message = [NSString stringWithFormat:#"Could not find image %#", imageURL];
RCTLogWarn(#"%#", message);
completionHandler(RCTErrorWithMessage(message), nil);
}
});
return ^{
cancelled->store(true);
};
}
This problem is fixed in 0.63.3 ✅
**For IOS** in
node_modules/react-native/Libraries/Image/RCTLocalAssetImageLoader.mm file
**Replace Below**
- -(RCTImageLoaderCancellationBlock)loadImageForURL:(NSURL *)imageURL
size:(CGSize)size
scale:(CGFloat)scale
resizeMode:(RCTResizeMode)resizeMode
progressHandler:(RCTImageLoaderProgressBlock)progressHandler
partialLoadHandler:(RCTImageLoaderPartialLoadBlock)partialLoadHandler
completionHandler:(RCTImageLoaderCompletionBlock)completionHandler
{
UIImage *image = RCTImageFromLocalAssetURL(imageURL);
if (image) {
if (progressHandler) {
progressHandler(1, 1);
}
completionHandler(nil, image);
} else {
NSString *message = [NSString stringWithFormat:#"Could not find image %#", imageURL];
RCTLogWarn(#"%#", message);
completionHandler(RCTErrorWithMessage(message), nil);
}
return nil;
}
**With**
- -(RCTImageLoaderCancellationBlock)loadImageForURL:(NSURL *)imageURL
size:(CGSize)size
scale:(CGFloat)scale
resizeMode:(RCTResizeMode)resizeMode
progressHandler:(RCTImageLoaderProgressBlock)progressHandler
partialLoadHandler:(RCTImageLoaderPartialLoadBlock)partialLoadHandler
completionHandler:(RCTImageLoaderCompletionBlock)completionHandler
{
__block auto cancelled = std::make_shared<std::atomic<bool>>(false);
RCTExecuteOnMainQueue(^{
if (cancelled->load()) {
return;
}
UIImage *image = RCTImageFromLocalAssetURL(imageURL);
if (image) {
if (progressHandler) {
progressHandler(1, 1);
}
completionHandler(nil, image);
} else {
NSString *message = [NSString stringWithFormat:#"Could not find image %#", imageURL];
RCTLogWarn(#"%#", message);
completionHandler(RCTErrorWithMessage(message), nil);
}
});
return ^{
cancelled->store(true);
};
}
This..
Like and Love , if it work
I have the same issue which perfectly reproducible on one of the iPhone 7 on my react-native project. It's strange but another iPhone 7's works perfectly as well as all Android devices.
My code:
formdata.append("file", {uri: photo.uri, name: name_img, type: 'image/jpeg' });
axios({
url: `${API}${'/upload'}`,
method: 'post',
headers: {
'Authorization': 'Basic ' + auth_token,
'Content-Type':'application/x-www-form-urlencoded'
},
data: formdata
}).then(response => this.saveRoute())
.catch(err => {
this.props.errorMessage({message: err})
}
})
Few things that I investigate:
I was not able to catch it in debug mode (seams smth wrong in async calls?)
I was not able to catch it with try-catch statement but seams it happened in Axios call.
So, I tried to play with Timeout and was able to make it totally unreproducible with 300ms timeout before Axios call.
formdata.append("file", {uri: photo.uri, name: name_img, type: 'image/jpeg' });
setTimeout(() =>
axios({
url: `${API}${'/upload'}`,
method: 'post',
headers: {
'Authorization': 'Basic ' + auth_token,
'Content-Type':'application/x-www-form-urlencoded'
},
data: formdata
}).then(response => this.saveRoute())
.catch(err => {
this.props.errorMessage({message: err})
}
})
, 300);
I know that it's a workaround but may help others to understand the issue for more deep research.
I temporary fixed using rn-fetch-blob, but the issue is present in 0.63.2 version and I didn't want to patch node_modules react-native images library.
To send file, you have to create a FormData and append your file into it. See EX: https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch#Uploading_a_file
I found solution. Just put delay when you post request.
let options = {}
options.headers = headers
options.method = 'POST'
let url = {SERVER_URL}
options.body = new FormData();
for (let key in data) {
options.body.append(key, data[key]);
}
setTimeout(() => {
fetch(url, options)
.then((response) => response.json())
.then((responseJson) => {
resolve(responseJson);
})
.catch((error) => {
let errParam = {}
errParam.errMsg = error.toString()
console.log(errParam)
resolve(errParam);
})
}, 1000);
Error fixed when updating React Native to version 0.63.3

React Native Fetch give error "Network request failed"

I have the following code for creating an event with a image and some body params. It was working fine when i was doing it without image, i am using react-native-image-crop-picker for selecting images. I am getting "Network request failed" error when posting data from react-native. The request never reach my backend as i am getting no logs there. It is working fine with postmen.
MY CODE:
const { name, date, description, location, uri, mime, time } = this.state;
const formData = new FormData();
formData.append('name', name)
formData.append('date', date)
formData.append('description', description)
formData.append('location', location)
formData.append('time', time)
formData.append('image',{
uri:uri,
mime:'image/jpeg',
name:`image${moment()}`
})
alert(JSON.stringify(formData));
const config = {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'multipart/form-data',
},
body: formData,
};
fetch(`http://${Config.apihost}:${Config.port}/events`,config).then((res) => res.json())
.then((res) => {
this.setState({ modalVisible: false, name:'', date: moment().format('YYYY-MM-DD'), description:'', Location: 'AlHedaya Masjid' })
this.props.addEvent(res.message);
// this.props.navigation.goBack();
}).catch((err) => alert(err));
I have another screen which contains different number of pictures like gallery i am uploading multiple picture to the gallery, the request is working fine with code below.
const data = new FormData();
data.append('name', 'avatar');
images.map((res, i) => {
data.append('fileData[]', {
uri: res.path,
type: res.mime,
name: `image${i}${moment()}`
});
})
const config = {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'multipart/form-data',
},
body: data,
};
fetch(`http://${Config.apihost}:${Config.port}/events/${this.state.item.id}/photos`, config)
.then((checkStatusAndGetJSONResponse) => checkStatusAndGetJSONResponse.json())
.then((response) => {
if (response.status && response.message.length > 0) {
var images = this.state.images;
response.message.map(file => {
images.push(`http:${Config.apihost}:${Config.port}/images/${file.id}`);
});
this.setState({ images });
}
}).catch((err) => { alert(err) });
I can't really see the difference between the two codes but the upper code giving me error.
I am testing on android
I am using the IP address instead of localhost (my others requests are working so thats out of equation)
None of the solution in this link worked
React Native fetch() Network Request Failed
Am I missing something?
In first code snippet you have written mime instead of type.
formData.append('image',{
uri:uri,
**mime:'image/jpeg**',
name:`image${moment()}`
})
it should be like below snippet
formData.append('image',{
uri:uri,
type:'image/jpeg',
name:`image${moment()}`
})

Categories

Resources