React Native Firebase Storage Upload fails with Unknown error - ios

I am using react-native-firebase to work with our Firebase account for authentication, firestore and storage. Attempting to upload a photo to Storage is failing with an unknown error. Here is the code attempted:
_pickImage = async () => {
await this.getCameraRollPermission()
let result = await ImagePicker.launchImageLibraryAsync({
allowsEditing: true,
aspect: [4, 3],
});
console.log(result);
if (!result.cancelled) {
// this.setState({ photoURL: result.uri });
this._handlePhotoChoice(result)
}
};
_handlePhotoChoice = async pickerResult => {
let userId = this.state.userId
firebase
.storage()
.ref('photos/profile_' + userId + '.jpg')
.putFile(pickerResult.uri)
.then(uploadedFile => {
console.log("Firebase profile photo uploaded successfully")
})
.catch(error => {
console.log("Firebase profile upload failed: " + error)
})
}
Testing in iOS Simulator and using the debugger to detect the errors I'm just getting back this error:
"Error: An unknown error has occurred.
at createErrorFromErrorData (blob:http://localhost:19001/e9d43477-4e42-4f7a-b494-16485def4c28:2371:17)
at blob:http://localhost:19001/e9d43477-4e42-4f7a-b494-16485def4c28:2323:27
at MessageQueue.__invokeCallback (blob:http://localhost:19001/e9d43477-4e42-4f7a-b494-16485def4c28:2765:18)
at blob:http://localhost:19001/e9d43477-4e42-4f7a-b494-16485def4c28:2510:18
at MessageQueue.__guardSafe (blob:http://localhost:19001/e9d43477-4e42-4f7a-b494-16485def4c28:2678:11)
at MessageQueue.invokeCallbackAndReturnFlushedQueue (blob:http://localhost:19001/e9d43477-4e42-4f7a-b494-16485def4c28:2509:14)
at http://localhost:19001/debugger-ui/debuggerWorker.js:70:58"
UPDATE:
A file is uploaded to the storage bucket, but the file is not the JPEG photo, but instead is JSON content about the file:
{"contentType":"image\/jpeg","name":"photos\/profile_XPIO2lHjlYbdLPchACZHBsmY9Jr1.jpg"}
So somehow a JSON file is ending up in the bucket instead of the actual photo and then the error is thrown.
It looks like this issue is tracked a couple times, but not resolved:
https://github.com/invertase/react-native-firebase/issues/1177
https://github.com/invertase/react-native-firebase/issues/302

Finally found my issue. The URI of the image from the ImagePicker had a '%' character in it from the local app cache. This percent was being URI encoded to '%25' which resulted in the file not being found by the putFile code. Adding a decodeURI call around the uri fixed the issue.
let fileUri = decodeURI(pickerResult.uri)

In case you are using react-native-document-picker, check out this:
https://github.com/rnmods/react-native-document-picker/issues/235

Related

ReactJS: Download file to IOS device (file-saver and firebase)

I am using the following in an attempt to download a document onto the user's device. This document has been uploaded to Firebase Storage.
import { saveAs } from 'file-saver';
const handleDownload = (url, filename) => {
axios.get(url, {
responseType: 'blob',
})
.then((res) => {
// fileDownload(res.data, filename)
saveAs(url)
})
}
The URL looks something like:
https://firebasestorage.googleapis.com/v0/b/appspot.com/o/rWFZhAKk9eOSIIFoP0DqqvrC6WJ3%2F2022-07-31%2FXXX.pdf?alt=media&token=9ea477b5-4371-4369-947a-368bc01043d5
And then calling this via a onClick (as per docs)
<IconButton size="small" aria-label="download" onClick={() => {handleDownload(el.url, el.name)}}><CloudDownloadIcon /></IconButton>
However on IOS I get no response, no download and no error in console.
Is this something with Firebase that I need to correct, or am I doing something else wrongly? If I open that URL from the app, then it loads, but I want to give the user the option to download.

Cant download on iOS with expo-file-system

Im trying to download using Expo-File-System on an expo project with react native.
The download option works on Expo-Go during testing but wont work when i push it in production mode.
It says that it is "unable to save file in the local URI because you dont have Document Permissions" as shown in the Picture below.
Here is the code (Using typescript):
import * as MediaLibrary from 'expo-media-library';
///For downloading the file
const download = async (item: ICurriculumCourseDocument) => {
setIsloading(true)
await FileSystem.downloadAsync(
`https:/baseUrl`,
FileSystem.documentDirectory + item.filename,
options
)
.then(({ uri }) => {
setIsloading(false)
console.log('Finished downloading to', uri);
onShareIOS(uri)
})
.catch(error => {
setIsloading(false)
alert(error);
});
}
//For sharing the file using the Share
const onShareIOS = async (uri: string) => {
const imageFileExts = ['jpg', 'png', 'gif', 'heic', 'webp', 'bmp'];
if (imageFileExts.every(x => !uri.endsWith(x))) {
const UTI = 'public.item';
await Sharing.shareAsync(uri, {UTI});
}
};
Here is the full Alert with the error message:

Trouble reading user accessible files

I am using nativescript-mediafilepicker as means of choosing a file, and this can read external storage successfully (I have downloaded a PDF to the 'downloads' folder on iOS and I am able to pick it.) I then try to load the file using the file system module from nativescript library, and this fails because it is listed as NativeScript encountered a fatal error: Uncaught Error: You can’t save the file “com.xxxxxx” because the volume is read only. This doesn't make sense as I am trying to read anyway - I don't understand where the saving part is from. The error comes from fileSystemModule.File.fromPath() line.
Something to note that file['file'] is file:///Users/adair/Library/Developer/CoreSimulator/Devices/82F397CE-B0B3-4ADD-AD52-805265C7AC49/data/Containers/Data/Application/7B47A8BD-6DBA-42CF-8792-38A8C5E61174/tmp/com.xxxxxx/test.pdf
Is the file automatically being pulled to an application specific directory after this media picker?
getFiles() {
let extensions = [];
if (app.ios) {
extensions = [kUTTypePDF]; // you can get more types from here: https://developer.apple.com/documentation/mobilecoreservices/uttype
} else {
extensions = ["pdf"];
}
const mediaFilePicker = new Mediafilepicker();
const filePickerOptions = {
android: {
extensions,
maxNumberFiles: 1,
},
ios: {
extensions,
maxNumberFiles: 1,
},
};
masterPermissions
.requestPermissions([masterPermissions.PERMISSIONS.READ_EXTERNAL_STORAGE,masterPermissions.PERMISSIONS.WRITE_EXTERNAL_STORAGE])
.then((fulfilled) => {
console.log(fulfilled);
mediaFilePicker.openFilePicker(filePickerOptions);
mediaFilePicker.on("getFiles", function (res) {
let results = res.object.get("results");
let file = results[0];
console.dir(file);
let fileObject = fileSystemModule.File.fromPath(file["file"]);
console.log(fileObject);
});
mediaFilePicker.on("error", function (res) {
let msg = res.object.get("msg");
console.log(msg);
});
mediaFilePicker.on("cancel", function (res) {
let msg = res.object.get("msg");
console.log(msg);
});
})
.catch((e) => {
console.log(e);
});
},
The issue I have experienced is resultant of the expectation of File.fromPath and what is returned by the file picker. File picker is returning a "file://path" URI, and File.fromPath is expecting a string of just "path".
Simply using the following instead is enough.
let fileObject = fileSystemModule.File.fromPath(file["file"].replace("file://","");

undefined is not an object (evaluating '_ExponentImagePicker.default.requestMediaLibraryPermissionsAsync') in expo-image-picker

Error from catch error block Image
Hi, I am using expo-image-picker and I stumbled with this error for a while now.
and this is all the necessary code that I use. I'll give a green checkmark for appreciation.
For more information, I have already handled the permission in info.plist.
// Camera & Image Picker
import * as ImagePicker from 'expo-image-picker';
const openImagePicker = async () => {
try {
// Ask the user for the permission to access the media library
const permissionResult = await ImagePicker.requestMediaLibraryPermissionsAsync()
if (permissionResult.granted === false) {
alert("You've refused to allow this appp to access your photos!");
return;
}
const result = await ImagePicker.launchImageLibraryAsync();
// Explore the result
console.log(result);
if (result.cancelled === false) {
setPickedImagePath(result.uri);
console.log(result.uri);
}
} catch (error) {
alert('Error Occur: ' + error.message)
closeSheet()
}
}
If you are using SDK 44, a permission request is no longer necessary for launching the image picker so you can remove the related code.
Simply call
const result = await ImagePicker.launchImageLibraryAsync({});
If you really want to ask for permission (which as I said is no longer necessary) the correct method is
ImagePicker.getMediaLibraryPermissionsAsync()
and not
ImagePicker.requestMediaLibraryPermissionsAsync()

Ionic - Some functionnalities are not working while compiling on IOS

Context:
Hello, I am working on a Ionic application (made in Typescript). In this application, I control a wifi camera via HTTP Request to the IP (http://192.72.1.1/myCommand to be precise).
Main actions I do with the camera:
Start recording
Stop recording
Get videos list
Download a video
When I use the Ionic DevApp:
With the Ionic DevApp, everything works perfectly, I can do all mains actions without a problem.
When I compile the application on IOS:
I compile with the command ionic cordova build ios --prod, then I archive with Xcode and send it to the AppStore to test it with Test Flight.
I got no errors while compiling / archive the application. But when I try it on my iPhone, I can start / stop recording, but can't download the video.
Problem:
Some commands are not working, but I don't know if it is getting the list or downloading the video, I have no logs. I don't understand why some commands are working but others no.
IOS is blocking download requests? How to solve my problem?
Notes:
I already tried all basic things like delete the IOS platform, recompile, uninstall, ...
I tried different Ionic HTTP plugins, same problem with all of them.
Some code:
Start / Stop the camera: (it is the same command to start / stop).
startCamera(){
var url = "http://192.72.1.1/changeRecordStatus";
var result = this.http.get(url);
result.subscribe(data => {
console.log("Works");
},
err => {
console.log("Error" + err);
}
);
}
Getting the name of the last video:
getLastVideo(){
var url = "http://192.72.1.1/listVideos";
this.http.get(url, {}, {})
.then(data => {
var xml = data.data
var xmlDOM = new DOMParser().parseFromString(xml, 'text/xml');
var temp = this.xmlToJson(xmlDOM); // function that convert XML to JSON
var resultArray = Object.keys(temp).map(function(i){
let ite = temp[i];
return ite;
});
resultArray = resultArray[0]['file'].reverse();
this.lastVideo = resultArray[0]['name']; // lastVideo is a global variable
},
(error) =>{
console.log("Error while getting the name of the last video" + error);
});
}
Downloading the file from the camera:
downloadFileFromCamera() {
this.getLastVideo();
var basename_file = this.lastVideo;
var url = "http://192.72.1.1" + basename_file;
this.fileTransfer.download(encodeURI(url), this.file.dataDirectory + '/videos/' + basename_file, true).then((entry) => {
this.video[this.counterVideos] = entry; // video is a global array
this.counterVideos +=1;
}, (error) => {
console.log("Error while downloading the last video" + error);
});
}
If someone knows how to solve my problem, I would be so grateful! Thanks in advance.

Resources