Open a file (pdf, word, excel, png etc.) on device with its default application in react-native

24.7k views Asked by At

I'm using react-native-fs to download a file(pdf, word, excel, png etc.) and I need to open it in other application. Is it possible to open downloaded file with Linking or better open a dialog with possible apps like when using Sharing? Linking in the code below tries to open the file but it closes immediately without any notification, but my app is still working fine. Is there some special way to build URLs for deep linking for a specific file type? Any ideas for the best solution?

I see that there is old package react-native-file-opener but it's no longer maintained. This solution would be great.

Simplified code for download component:

import React, { Component } from 'react';
import { Text, View, Linking, TouchableOpacity } from 'react-native';
import { Icon } from 'react-native-elements';
import RNFS from 'react-native-fs';

import { showToast } from '../../services/toasts';

class DownloadFile extends Component {
  state = {
    isDone: false,
  };

  handleDeepLinkPress = (url) => {
    Linking.openURL(url).catch(() => {
      showToast('defaultError');
    });
  };

  handleDownloadFile = () => {
    RNFS.downloadFile({
      fromUrl: 'https://www.toyota.com/content/ebrochure/2018/avalon_ebrochure.pdf',
      toFile: `${RNFS.DocumentDirectoryPath}/car.pdf`,
    }).promise.then(() => {
      this.setState({ isDone: true });
    });
  };

  render() {
    const preview = this.state.isDone
      ? (<View>
        <Icon
          raised
          name="file-image-o"
          type="font-awesome"
          color="#f50"
          onPress={() => this.handleDeepLinkPress(`file://${RNFS.DocumentDirectoryPath}/car.pdf`)}
        />
        <Text>{`file://${RNFS.DocumentDirectoryPath}/car.pdf`}</Text>
      </View>)
      : null;
    return (
      <View>
        <TouchableOpacity onPress={this.handleDownloadFile}>
          <Text>Download File</Text>
        </TouchableOpacity>
        {preview}
      </View>
    );
  }
}

export default DownloadFile;
3

There are 3 answers

1
mradziwon On

After some research, I decided to use react-native-fetch-blob. From version 0.9.0 it's possible to open downloaded file with Intent and use Download Manager. It also has API for iOS for opening documents.

Code now:

...
const dirs = RNFetchBlob.fs.dirs;
const android = RNFetchBlob.android;
...

  handleDownload = () => {
    RNFetchBlob.config({
      addAndroidDownloads: {
        title: 'CatHat1.jpg',
        useDownloadManager: true,
        mediaScannable: true,
        notification: true,
        description: 'File downloaded by download manager.',
        path: `${dirs.DownloadDir}/CatHat1.jpg`,
      },
    })
      .fetch('GET', 'http://www.swapmeetdave.com/Humor/Cats/CatHat1.jpg')
      .then((res) => {
        this.setState({ path: res.path() });
      })
      .catch((err) => console.log(err));
  };

...
render() {
...
        <Icon
          raised
          name="file-pdf-o"
          type="font-awesome"
          color="#f50"
          onPress={() => android.actionViewIntent(this.state.path, 'image/jpg')}
...
}
0
Ajay Parambath On

Opening Files from url with Default Applications in React Native

To open various types of files like PDF, Word document, Excel sheet, image, and more on a device with their default applications in React Native, you can follow these steps:

Install Dependencies

I'm using react-native-fs package alternate to RN fetch blob, which provides file system functionality. You also need react-native-file-viewer to open file with it's default application.

npm install react-native-fs
npm install react-native-file-viewer

Here's a function that allows you to open the document. You need to pass the URL of the file you want to open and the desired file name with extension (.pdf, .png, .csv, .xls, etc).

import FileViewer from "react-native-file-viewer";

export async function openDocument(url: string, fileName: string /* e.g., file.pdf; image.png, document.csv*/) {
  let RNFS = require('react-native-fs');
  return new Promise((resolve, reject) => {
    try {
      let originalName = fileName
      const localFile = `${RNFS.DocumentDirectoryPath}/${originalName}`;
      console.log("localFile ===>", localFile);
      const options = {
        fromUrl: url,
        toFile: localFile,
      };
      RNFS.downloadFile(options)
        .promise.then(() => FileViewer.open(localFile))
        .then((res) => {
          // Success
          console.log('res', res);
          resolve(res)
        })
        .catch((error) => {
          // Error
          console.log('error', error);
          reject(error)
        });
    } catch (error) {
      console.log(error)
      reject(error)
      toastAndroid('File Not Available')
    }
  })
}
  • Ensure that you provide the file name with its extension (e.g., .pdf, .png, .csv) when calling this function. The extension is crucial for it to work correctly.
0
Dusan Spasojevic On

Use react-native-file-viewer to preview file and react-native-f to get the path to file. Like this:

import RNFS from 'react-native-fs';
import FileViewer from 'react-native-file-viewer';

const returnFilePath = fileName => {
  const dirPath =
    Platform.OS === 'ios'
      ? `${RNFS.DocumentDirectoryPath}`
      : `${RNFS.DownloadDirectoryPath}`;
  const filePath = dirPath + `/${fileName}`;
  return filePath;
};

export function previewFile(filePath) {
  FileViewer.open(filePath)
    .then(() => {
      console.log('Success');
    })
    .catch(_err => {
      console.log(_err);
    });
}