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

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.

Related

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:

IOS Safari issue of download file name is "Unknown"

I implemented a Jersey REST service to download the zip file.
Now, I would like to use axios in front end to download the zip file.
Everything is fine in PC Chrome but when tried with Safari on iPad it opens a tab with name "unknown".
I have searched some articles and mentioned that this may related to IOS safari compatibility.
e.g. https://caniuse.com/#feat=download
However, I also want know if there is any method to show the downloaded file as "file.zip" for safari.
Below is my code
Backend:
#GET
#Path("/getTestingReport")
#Produces("application/zip")
public Response getTestingReport() throws Exception {
// set file (and path) to be download
File file = new File("C:/Users/abc/Desktop/test.zip");
ResponseBuilder responseBuilder = Response.ok((Object) file);
responseBuilder.header("Content-Disposition", "attachment; filename=\"MyJerseyZipFile.zip\"");
return responseBuilder.build();
}
Frontend:
axios.get("report/getTestingReport").then((response) => {
console.log("response", response)
var blob = new Blob([response.data], { type: "application/zip" });
const url = window.URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', 'file.zip');
document.body.appendChild(link);
link.click();
}).catch((error) => {
console.error("error response", error.response)
});
May I have any suggestion?

Dropzone + Active Storage event listener in rails

I am using dropzone with and active storage to upload files directly upload files to the s3 server from the client side. Currently I am getting file from dropzone with addedfile event of dropzone and uploading it via new ActiveStorage.DirectUpload(file, url);. Now according to the documentation they have provided some event listeners which I can use to show progress of upload to the user but they are only working if I am using a normal form and a submit button. It does not work if I upload files via Javascript.
Here is my code:
dropzone.on("addedfile", function (file) {
const upload = new ActiveStorage.DirectUpload(file, url);
upload.create((error, blob) => {
if(error) return;
alert('file uploaded');
}
}
addEventListener("direct-upload:start", event => {
console.log('This does not work');
})
DirectUpload doesn't dispatch events.
DirectUploadController does, and it uses DirectUpload to do the actual upload, like you are doing in your example code. You don't need to listen for events from DirectUploadController since you can infer when the event would be dispatched.
To do something where you would expect the direct-upload:start and direct-upload:end events, change your code to something like:
dropzone.on("addedfile", function (file) {
const upload = new ActiveStorage.DirectUpload(file, url);
console.log("direct-upload:start")
upload.create((error, blob) => {
if(error) {
console.log("direct-upload:error")
return;
}
}
console.log("direct-upload:end")
}

Is there a way to upload media to the Twitter API using the URL of the media resource?

I've created an app that allows users to upload their images to a Google Cloud Storage bucket - which is then used in social media sharing previews.
The image is uploaded directly to the bucket from the user's browser - using the Firebase API.
What I also want to do is - when an image is saved - to automatically post that image on my app's twitter feed.
The way I've done this is to use a Cloud Function trigger on Cloud Storage - which downloads the image and then uploads via the Twitter API.
There's essentially an unnecessary double handling of traffic here is there a way to just give the Twitter API the public location of the file and have it source the file directly?
Here's my code for the current solution:
class Defferred {
constructor() {
const that = this;
this.prom = new Promise((resolve, reject) => {
that.resolve = resolve;
that.reject = reject;
});
}
}
exports.onNewImage = functions.storage.object().onFinalize((object) => {
const prom = new Defferred();
bucket.file(object.name).download((err, file, response) => {
if (err) {
return prom.reject(err);
} else {
twitterClient.post('media/upload', {
media: file
}, (err, media, response) => {
if (!err) {
let status = {
status: "Somebody created this at https://geoplanets.io #geometry #geometricart",
media_ids: media.media_id_string
}
twitterClient.post('statuses/update', status, (error, tweet, response) => {
if (!error) {
return prom.resolve(response);
} else {
return prom.reject(error);
}
});
} else {
return prom.reject(err);;
}
});
}
});
return prom.prom;
});
Is there an alternative way of doing this that doesn't involve downloading the file? - A good answer would highlight the relevant parts of the API documentation that highlight how I would go about working this out myself.
The Twitter node api doesn't have a way to simply pass an URL for media upload. The example they give shows what you're doing now - sending the full content with the request.
The node client is just a wrapper around the REST API, and if you read its docs, you'll see that you have to provide the file content directly to the POST.
Yes!
We can upload media using URL of file by making the downstream of a file.
First we need to make Axios request to have a buffer of it then we can pass it with file type using
twitter-api-v2
use it in this package or REST API
const client = new TwitterApi({
appKey: CONSUMER_KEY,
appSecret: CONSUMER_SECRET,
accessToken: oauth_token,
accessSecret: oauth_token_secret,
});
const url = 'URL OF THE FILE';
const downStream = await axios({
method: 'GET',
responseType: 'arraybuffer',
url: url,
}).catch(function (error) {
res.send({error:error});
});
const mediaId = await client.v1.uploadMedia(downStream.data,{ mimeType: 'png'});
const newTweet = await client.v1.tweet('Hello link tweet!', { media_ids: mediaId });
sample Image

React Native Firebase Storage Upload fails with Unknown error

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

Resources