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
I am using react-native-image-to-pdf library to convert images to pdf in my react native app. from https://www.npmjs.com/package/react-native-image-to-pdf
var photoPath = ['https://images.pexels.com/photos/20787/pexels-photo.jpg?auto=compress&cs=tinysrgb&h=350','https://images.pexels.com/photos/20787/pexels-photo.jpg?auto=compress&cs=tinysrgb&h=350'];
const myAsyncPDFFunction = async () => {
try {
const options = {
imagePaths: photoPath,
name: 'PDFName',
};
const pdf = await RNImageToPdf.createPDFbyImages(options);
console.log(pdf.filePath);
} catch(e) {
console.log(e);
}
}
but this is giving error Error: Attempt to invoke virtual method 'int android.graphics.Bitmap.getWidth()' on a null object reference
I have also tried giving path as ['./assets/a.png', './assets/b.png']
but still getting same error
Based on the usage example, your photoPath needs to be a local file path and not a remote path.
My recommendation is to first use rn-fetch-blob to download the remote image to the device, and then pass your new local image path to react-native-image-to-pdf. Something like:
RNFetchBlob
.config({
// add this option that makes response data to be stored as a file,
// this is much more performant.
fileCache : true,
})
.fetch('GET', 'http://www.example.com/file/example.png', {
//some headers ..
})
.then(async (res) => {
// the temp file path
console.log('The file saved to ', res.path())
const options = {
imagePaths: [res.path()],
name: 'PDFName',
};
const pdf = await RNImageToPdf.createPDFbyImages(options);
})
from file path remove the text 'file://; with empty string('').
const options = {
imagePaths: [uri.replace('file://', '')],
name: 'FileName',
quality: .9, // optional compression paramter
};
replace('file://', '') it's work for me
I want to download a file in my react-native app when I press a download button. And I was able to do it using this code:
const handleDownload = (item) => {
let date = new Date();
let file = item.url;
let ext = getExtention(file);
ext = '.' + ext[0];
const { config, fs } = RNFetchBlob;
let PictureDir = fs.dirs.PictureDir;
let options = {
fileCache: true,
addAndroidDownloads: {
// Related to the Android only
useDownloadManager: true,
notification: true,
path:
PictureDir +
'/image_' +
Math.floor(date.getTime() + date.getSeconds() / 2) +
ext,
description: 'Image',
},
};
config(options)
.fetch('GET', file)
.then((res) => {
dispatch(
setToast({
type: 'success',
text1: t('business-categories.download_success'),
})
);
});
};
and it is successfully download, but whenever I try to open the file I get a toast error Can't open file.
Does anyone knows how to fix this ??
(EDIT)
I found out that the file downloaded is BIN FILE where the original file is a pdf file.
Is there a way that I can change this ?
I want to create pdf in my app in react-native for word to pdf or html to pdf converter.I have tried all possible react-native packages but none of them give me a desired result what should I do.
Are you using nodeJS on the server? If you are, send the html to the server and use this to convert the html to a pdf.
Have you Checked react-native-pdf-lib.
It is pretty good module.
Otherwise consider server side rendering
You can generate pdf file in react native with the npm package react-native-html-to-pdf.
Steps :
Create HTML template of your pdf file you want to generate.
Install the package and install pod in ios folder with pod install
Rebuild the app in android/ios.
import RNHTMLtoPDF from 'react-native-html-to-pdf';
const createPdf = async () => {
try {
let options = {
html: '<div>Hello pdf</div>',
fileName: 'demofile',
directory: 'Downloads',
base64: true,
};
let file = await RNHTMLtoPDF.convert(options);
console.log(file);
} catch (error) {
console.log(error);
}
}
Here is the more specific answer to your problem :
import RNHTMLtoPDF from 'react-native-html-to-pdf';
const createPdf = async () => {
let h1 = "Hey Heading 1";
let h2 = "heading 2";
let para = "Something description";
// use Backtick(`) to define html for your custom dynamic content
const pdf_html = `<div>
<h1>{h1}</h1>
<h1>{h2}</h1>
<h1>{para}</h1>
</div`;
try {
let options = {
html: pdf_html,
fileName: 'demofile',
directory: 'Downloads',
base64: true,
};
let file = await RNHTMLtoPDF.convert(options);
console.log(file);
} catch (error) {
console.log(error);
}
}
I am trying to learn react native and how to download files to the device. I know you can do this with react native file system but that does not support authentication which I need. React native fetch blob does support this.
For education purposes, I want to have the code from the first answer to this question recreated in react native fetch blob instead of react native file system.
I someone could write sutch an examlple form me I would be super tankfull.
Question: Downloading data files with React Native for offline use
Try this, it's work fine on Android:
export const download = (url, name) => {
const { config, fs } = RNFetchBlob;
let PictureDir = fs.dirs.PictureDir;
let options = {
fileCache: true,
addAndroidDownloads: {
useDownloadManager: true,
notification: true,
path: PictureDir + name,
description: t('downloading_file')
}
};
config(options)
.fetch('GET', url)
.then(res => {
if (res.data) {
alert(t('download_success'));
} else {
alert(t('download_failed'));
}
});
};
downloadImage(){
var date = new Date();
var url = "http://debasish.com/image.jpg";
var ext = this.getExtention(url);
ext = "."+ext[0];
const { config, fs } = RNFetchBlob ;
let PictureDir = fs.dirs.PictureDir
let options = {
fileCache: true,
addAndroidDownloads : {
useDownloadManager : true,
notification : true,
path: PictureDir + "/image_"+Math.floor(date.getTime()
+ date.getSeconds() / 2)+ext,
description : 'Image'
}
}
config(options).fetch('GET', url).then((res) => {
Alert.alert("Download Success !");
});
}
getExtention(filename){
return (/[.]/.exec(filename)) ? /[^.]+$/.exec(filename) :
undefined;
}
I have a page that includes a download button using jsPDF. On desktop machines it downloads the page as it should. However, pdf.save() does not work on my tablet or phone.
I tried to add a special case for mobile devices to open the PDF in a new window, since mobile devices don't download things the same as desktops, with the idea being that once the PDF is open in a new window the user can choose to save it manually.
var pdf = new jsPDF('p', 'pt', 'letter');
var specialElementHandlers = {
'#editor': function (element, renderer) {
return true;
}
};
html2canvas($("#pdf-area"), {
onrendered: function (canvas) {
$("#pdf-canvas").append(canvas);
$("#pdf-canvas canvas").css("padding", "20px");
}
});
var options = {
pagesplit: true
};
function download(doctitle) {
pdf.addHTML($("#pdf-area")[0], options, function () {
if (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) {
pdf.output('dataurlnewwindow');
} else {
pdf.save(doctitle);
}
});
}
But the download function still does nothing on my tablet/phone. I tested it with this to make sure the pdf.output() function was working:
pdf.addHTML($("#pdf-area")[0], options, function () {
pdf.output('dataurlnewwindow');
});
and it does still work on desktop, but does nothing on mobile.
jsPDF won't download files on mobile apps by this pdf.save(). I have tried and searched for this issue but could not find a complete solution in one place. I am using the file and file-opener plugin. I have developed the solution in Ionic React. Install below modules.
npm i jspdf
npm install cordova-plugin-file
npm install #ionic-native/file
npm install cordova-plugin-file-opener2
npm install #ionic-native/file-opener
ionic cap sync
Go to your file and add these import statements.
import { jsPDF } from "jspdf";
import 'jspdf-autotable';
import { FileOpener } from '#ionic-native/file-opener;
import { File } from '#ionic-native/file';
import { isPlatform } from "#ionic/react";
Check the pdfDownload function
const pdfDownload = async () => {
var doc = new jsPDF();
doc.setFontSize(40);
doc.text("Example jsPDF", 35, 25)
let pdfOutput = doc.output();
if (isPlatform("android")) {
// for Android device
const directory = File.externalRootDirectory + 'Download/';
const fileName = `invoice-${new Date().getTime()}.pdf`
File.writeFile(directory, fileName, pdfOutput, true).then(succ => {
FileOpener.showOpenWithDialog(directory + fileName, 'application/pdf')
.then(() => console.log('File opened'))
.catch(error => console.log('Error opening file', error));
},
err => {
console.log(" writing File error : ", err)
})
} else if (isPlatform("ios")) {
// for iOS device
console.log('ios device')
const directory = File.tempDirectory;
const fileName = `invoice-${new Date().getTime()}.pdf`
File.writeFile(directory, fileName, pdfOutput, true).then(success => {
FileOpener.showOpenWithDialog(directory + fileName, 'application/pdf')
.then(() => console.log('File opened'))
.catch(e => console.log('Error opening file', e));
},
err => {
console.log(" writing File error : ", err)
})
} else {
// for desktop
doc.save("invoice.pdf");
}
}
I had similar issue.
jsPDF won't download file on phones/ tablets / ipads using "pdf.save()".
Do it through File plugin if you are using cordova/phonegap, this will save pdf file in downloads folder (Android) - for the ios you can access pdf file through a path (which is saved somewhere in temp directory) and can send or share.
Hope this helps you.
Here is the solution of download on mobile with jspdf
if (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent))
{
var blob = pdf.output();
window.open(URL.createObjectURL(blob));
}
else
{
pdf.save('filename.pdf');
}
Here is the example if you're using the Cordova platform for your development:
https://github.com/saharcasm/Cordova-jsPDF-Email
The workaround of the pdf not being downloaded in the devices is to use cordova-plugin-file.
Use the output method on the doc that will give you the raw pdf which needs to be written & saved in a file.
For example,
var doc = new JsPDF();
//... some work with the object
var pdfOutput = doc.output("blob"); //returns the raw object of the pdf file
The pdfOutput is then written on an actual file by using the file plugin.
The easiest way which works on both Desktop and Mobile is to use:
window.open(doc.output("bloburl"), "_blank");