I am building an app with React Native, for Android and iOS. I am trying to let the user download a PDF file when clicking on a button.
react-native-file-download does not support Android
react-native-fs does nothing when I trigger downloadFile (nothing shows up on the notification bar), and I am not able to find the file after that. I added android.permission.WRITE_EXTERNAL_STORAGE to the Android Manifest file. I double-checked that the file I am trying to download exists (when it does not, the library throws an error)
I do not find other solutions for this problem. I have found libraries for viewing a PDF, but I would like to let the user download the PDF.
Just implemented the download feature an hour ago :p
Follow these steps:
a) npm install rn-fetch-blob
b) follow the installation instructions.
b2) if you want to manually install the package without using rnpm, go to their wiki.
c) Finally, that's how I made it possible to download files within my app:
const { config, fs } = RNFetchBlob
let PictureDir = fs.dirs.PictureDir // this is the pictures directory. You can check the available directories in the wiki.
let options = {
fileCache: true,
addAndroidDownloads : {
useDownloadManager : true, // setting it to true will use the device's native download manager and will be shown in the notification bar.
notification : false,
path: PictureDir + "/me_"+Math.floor(date.getTime() + date.getSeconds() / 2), // this is the path where your downloaded file will live in
description : 'Downloading image.'
}
}
config(options).fetch('GET', "http://www.example.com/example.pdf").then((res) => {
// do some magic here
})
If you're using Expo, react-native-fetch-blob won't work. Use FileSystem.
Here's a working example:
const { uri: localUri } = await FileSystem.downloadAsync(remoteUri, FileSystem.documentDirectory + 'name.ext');
Now you have localUri with the path to the downloaded file. Feel free to set your own filename instead of name.ext.
I Followed the solution from Jonathan Simonney, above on this post. But I had to change it a little:
const { config, fs } = RNFetchBlob;
const date = new Date();
const { DownloadDir } = fs.dirs; // You can check the available directories in the wiki.
const options = {
fileCache: true,
addAndroidDownloads: {
useDownloadManager: true, // true will use native manager and be shown on notification bar.
notification: true,
path: `${DownloadDir}/me_${Math.floor(date.getTime() + date.getSeconds() / 2)}.pdf`,
description: 'Downloading.',
},
};
config(options).fetch('GET', 'http://www.africau.edu/images/default/sample.pdf').then((res) => {
console.log('do some magic in here');
});
GetItem_downloadbtn = (item, itemname) => {
console.log("fiel url comiugn jdd " + item);
console.log("item name checkoing " + itemname);
const android = RNFetchBlob.android;
const filename = itemname;
const filepath = RNFetchBlob.fs.dirs.DownloadDir + '/foldernamae/' + filename;
const downloadAppUrl = item;
RNFetchBlob.config({
addAndroidDownloads: {
useDownloadManager: true,
title: 'great, download success',
description:'an apk that will be download',
mime: 'application/vnd.android.package-archive',
// mime: 'image/jpeg',
// mediaScannable: true,
notification: true,
path: filepath
}
})
.fetch('GET', downloadAppUrl)
.then((res) => {
// console.log('res.path ', res.path());
alert('res.path ', res.path());
android.actionViewIntent(res.path(), 'application/vnd.android.package-archive');
})
.catch((err) => {
alert('download error, err is', JSON.stringify(err));
});
}
I had the same issue, got it working using Expo WebBrowser Module
// install module
npm install react-native-webview
// import the module
import * as WebBrowser from 'expo-web-browser';
// then in your function you can call this function
await WebBrowser.openBrowserAsync(file_ur);
it will open preview of the file and then user can download using share button.
Related
What I want to do: On reset password button click send a letter to user's email using auth().sendSignInLinkToEmail(<user email>, actionCodeSettings);
After user clicks on the received link he gets navigated to the app and using dynamicLinks().getInitialLink() to get the email link he will be loged in with auth().signInWithEmailLink() method.
Here is my implementation for it:
Reset Password Screen
const handleContinue = async () => {
await FirebaseAuth.resetPassword(email);
await AsyncStorage.setItem('#email', email);
};
FirebaseAuth.js
const actionCodeSettings = {
handleCodeInApp: true,
// URL must be whitelisted in the Firebase Console.
url: 'https://examplemoxie.page.link/password_reset',
iOS: {
bundleId: '<my bundle id>',
},
android: {
bundleId: '<my bundle id>',
installApp: true,
},
};
class FirebaseAuthApp {
constructor(firebase) {
this.firebase = firebase;
}
resetPassword = emailAddress =>
auth()
.sendSignInLinkToEmail(emailAddress, actionCodeSettings)
.catch(error => logger(error));
...
}
At this point everything works pretty fine, I'm receiving an email, by clicking on it I'm getting navigated into my app and even able to read the initial link by this piece of code:
App.js
const App = () => {
const user = useAuthStatus();
useEffect(() => {
const handleDynamicLink = async link => {
// Check and handle if the link is a email login link
alert(JSON.stringify(link));
if (auth().isSignInWithEmailLink(link.url)) {
try {
// use the email we saved earlier
const email = await AsyncStorage.getItem('#email');
await auth().signInWithEmailLink(email, link.url);
/* You can now navigate to your initial authenticated screen
You can also parse the `link.url` and use the `continueurl` param to go to another screen
The `continueurl` would be the `url` passed to the action code settings */
} catch (e) {
alert(e);
}
}
};
const unsubscribe = dynamicLinks().onLink(handleDynamicLink);
/* When the app is not running and is launched by a magic link the `onLink`
method won't fire, we can handle the app being launched by a magic link like this */
dynamicLinks()
.getInitialLink()
.then(link => link && handleDynamicLink(link));
// When the component is unmounted, remove the listener
return () => unsubscribe();
}, []);
Link
https://testmoxiegirl.firebaseapp.com/__/auth/action?apiKey=<api key>&mode=signIn&oobCode=<oob code>&continueUrl=https://examplemoxie.page.link/password_reset&lang=en
My dynamic links settings
short URL link - https://examplemoxie.page.link/password_reset
dynamic link - https://moxiegirl.page/reset_password
behavior for Android - Open the deep link in your Android App / Open custom URL for not installed App
And here comes the problem, the link which i get in App.js file from getInitialLink() method is the same as my dynamic link in firebase dynamic link settings and using it for signInWithEmailLink will fail with Invalid email link error. For this to work i need to get a link sent to email but I have no clue on what I'm doing wrong.
My environment:
"react-native": "0.64.2",
"#react-native-firebase/app": "^12.4.0",
"#react-native-firebase/auth": "^12.4.0",
"#react-native-firebase/dynamic-links": "^12.4.0",
So, before posting this question I decided to check everything once more and I found a problem.
In my case, instead of using packageName in my FirebaseAuth.js
I was using bundleId for the Android settings, assuming that for the Android and iOS it should be the same keys.
Before:
const actionCodeSettings = {
...
android: {
bundleId: '<my bundle id>',
installApp: true,
},
};
After:
const actionCodeSettings = {
...
android: {
packageName: '<my bundle id>',
installApp: true,
},
};
Im using electron with a python backend (for a stand alone desktop application) and I need to supply the python script with a directory. With the following code I can get a dialog to open however, it will not output the folder path to the console.
const OpenBtn = document.getElementById('OpenBtn')
OpenBtn.addEventListener('click', function(event) {
const { dialog } = require('electron').remote;
//Synchronous
let dir = dialog.showOpenDialog({properties:["openDirectory"]})
console.log(dir)
})
I am new to the frontend aspects of creating apps and I am trying to understand what is contained in dir. I see it produces a "promise" (I've tried various ways of accessing the filePaths string, but without success.
There is an HTML button with id=OpenBtn, and I have
webPreferences: {
nodeIntegration: true,
enableRemoteModule: true
}
in my main.js file.
Either use the synchronous showOpenDialogSync:
let dirs = dialog.showOpenDialogSync({properties:["openDirectory"]})
if (typeof dirs !== "undefined") {
console.log("Selected paths:");
console.log(dirs);
}
Or the asynchronous showOpenDialog:
dialog.showOpenDialog({properties: ["openDirectory"]}).then(result => {
if (result.canceled === false) {
console.log("Selected paths:");
console.log(result.filePaths);
}
}).catch(err => {
console.log(err);
})
I am trying to rename files in uppy.js. According to the documentation, there are 2 functions that are capable of providing this functionality. I defined both of these functions, however, they are having no effect on the file name and no errors are being thrown. How can I use these functions to rename a file?
onBeforeFileAdded: (currentFile, files) => {
const modifiedFile = {
...currentFile,
name: currentFile.name + '__' + Date.now()
}
return modifiedFile
}
onBeforeUpload: (files) => {
if (Object.keys(files).length < 2) {
// log to console
uppy.log(`Aborting upload because only ${Object.keys(files).length} files were selected`)
// show error message to the user
uppy.info(`You have to select at least 2 files`, 'error', 500)
return false
}
}
You need to make sure that the callback you posted is passed into your main uppy core initialization. It should work then as it is for me. Best of luck.
Hopefully, the code below can help you out.
const Uppy = require('#uppy/core');
let uppy = Uppy({
autoProceed: false,
allowMultipleUploads: true,
logger: Uppy.debugLogger,
restrictions: {
maxNumberOfFiles: 15,
maxFileSize: 10000000,
minNumberOfFiles: 1,
allowedFileTypes: ['image/*']
},
onBeforeFileAdded: (currentFile, files) => {
const modifiedFile = {
...currentFile,
name: 'yourfilename' + Date.now()
}
return modifiedFile
}
})
So I'm creating YouTube Downloader using node.js. The problem is the files are already created after I ran the code, but the files are 0kb and it prints Successfully. What I want is the program must be print successfully when I successfully download the video, also must not be created the file yet. the file must be created after the one video successfully downloaded
const playlist = [
{
title: "What is DevOps",
videoUrl: "https://www.youtube.com/watch?v=mBBgRdlC4sc",
},
{
title: "Introduction To DevOps ",
videoId: "Me3ea4nUt0U",
videoUrl: "https://www.youtube.com/watch?v=Me3ea4nUt0U",
},
{
title: "DevOps Tutorial For Beginners ",
videoId: "YSkDtQ2RA_c",
videoUrl: "https://www.youtube.com/watch?v=YSkDtQ2RA_c",
},
];
const fs = require("fs");
const ytdl = require("ytdl-core");
const length = playlist.length;
playlist.forEach((pl, i) => {
const { videoUrl, title } = pl;
const item = i + 1;
ytdl(videoUrl, {
format: "mp4",
}).pipe(fs.createWriteStream(`${title}.mp4`));
console.log(`${item}/${length} - ${title} downloaded successfully`);
});
You are logging "downloaded successfully" before the writing is finished. You have a few possibilities. One might be listening on certain events on the "WriterStream".
from the docs : https://nodejs.org/dist/latest-v12.x/docs/api/fs.html#fs_fs_createwritestream_path_options
// Create WriteableStream
const writeableStream = fs.createWriteStream(`${title}.mp4`);
// Listening for the 'finish' event
writeableStream .on('finish', () => {
console.log(`${item}/${length} - ${title} downloaded successfully`);
});
// Plug it into the ReadableStream
ytdl(videoUrl, {
format: "mp4",
}).pipe(writeableStream);
Now this will create a new file as soon the writing starts. I suggest using a temporary name like filename.temp.mp4 and then rename it after it finished writing.
I have the similar problem like here:
How to download file to Download's directory with Ionic Framework?
I got success alert after download but I can't see the file in an Android file explorer under the path displayed after succeed download: file:///data/user/0/io.ionic.fileTest/image.jpg
My code:
download(){
const fileTransfer: FileTransferObject = this.transfer.create();
const url = "http://cdna.allaboutvision.com/i/conditions-2016/heterochromia-kate-bosworth-660x660-with-credit.jpg";
fileTransfer.download(url, this.file.dataDirectory + 'laska.jpg', true).then((entry) => {
const alertSuccess = this.alertCtrl.create({
title: `Download Succeeded!`,
subTitle: `was successfully downloaded to: ${entry.toURL()}`,
buttons: ['Ok']
});
alertSuccess.present();
}, (error) => {
const alertFailure = this.alertCtrl.create({
title: `Download Failed!`,
subTitle: `was not successfully downloaded. Error code: ${error.code}`,
buttons: ['Ok']
});
alertFailure.present();
});
}
Could I somehow manage to save this file in e.g "Download" folder or "Documents"? I also tried changing destination path to:
cordova.file.externalRootDirectory + '/Download/'
In that case, I received error 1.
In many examples I see people use
window.requestFileSystem()
but it looks like the window doesn't have this method for me. I use visual studio code and ionic 3.
You got little bit mistake in fileTransfer.download
instead of this.file.applicationStorageDirectory use this.file.dataDirectory
Working code that downloads a file to Downloads directory:
downloadFile() {
this.fileTransfer.download("https://cdn.pixabay.com/photo/2017/01/06/23/21/soap-bubble-1959327_960_720.jpg", this.file.externalRootDirectory +
'/Download/' + "soap-bubble-1959327_960_720.jpg").then()
}
getPermission() {
this.androidPermissions.hasPermission(this.androidPermissions.PERMISSION.READ_EXTERNAL_STORAGE)
.then(status => {
if (status.hasPermission) {
this.downloadFile();
}
else {
this.androidPermissions.requestPermission(this.androidPermissions.PERMISSION.READ_EXTERNAL_STORAGE)
.then(status => {
if(status.hasPermission) {
this.downloadFile();
}
});
}
});
}