joltup / rn-fetch-blob

A project committed to making file access and data transfer easier, efficient for React Native developers.
MIT License
2.84k stars 784 forks source link

PDF's are corrupted sometimes and will not open on android #734

Open FrankieJLyons opened 3 years ago

FrankieJLyons commented 3 years ago

RN Version: 0.63.4 RNFB Version: ^0.12.0 Android version: Multiple, is happening on many devices and mac emulator Dev Machine: 2019 MacBook Pro running 11.4

Hello, i have a messaging system in my app where users can send a message with files to each other.

On iOS, this is working perfectly. However, on android, it appears PDF files only work sometimes, and are possibly being corrupted somewhere in my android specific code, as the same files open without issue on iOS devices and the simulator.

I did believe that this code was totally broken and unable to open PDF's, however one PDF did open completely randomly, I suspect file size may have something to do with it?

Whenever I try to open or preview the PDF, android tells me: 'Cannot display PDF (filename.pdf is of invalid format)'

Any help would be greatly appreciated

Here is the code for downloading files:

  downloadFiles = async (isReply) => {
    let {enquiry, reply} = this.state;

    this.setState({isLoading: true});

    const token = await AsyncStorage.getItem('userToken');

    let filePaths = [];
    let fileCount = 0;

    let files = enquiry.files;
    if (isReply) {
      files = reply.files;
    }

    const dirToSave =
      Platform.OS == 'ios'
        ? RNFetchBlob.fs.dirs.DocumentDir
        : RNFetchBlob.fs.dirs.DownloadDir;

    new Promise((resolve, reject) => {
      for (var i = 0; i < files.length; i++) {
        var id = files[i].file_id;
        var name = files[i].file.file_name;
        var ext = extension(name);

        const configOptions = Platform.select({
          ios: {
            appendExt: ext,
            fileCache: true,
            title: name,
            path: `${dirToSave}/${name}`,
          },
          android: {
            addAndroidDownloads: {
              useDownloadManager: true,
              notification: false,
              mediaScannable: true,
              fileCache: true,
              title: name,
              path: `${dirToSave}/${name}`,
            },
          },
        });

        var mime = content(ext);
        let headers = {
          'Content-Type': mime,
          'Access-Control-Allow-Origin': '*',
          'Access-Control-Allow-Method': 'POST, GET, DELETE, PUT',
          Authorization: 'Bearer ' + token,
        };

        RNFetchBlob.config(configOptions)
          .fetch('GET', BASE_API + '/enquiries/files/download/' + id, headers)
          .then(async (response) => {
            if (Platform.OS == 'ios') {
              RNFetchBlob.fs
                .writeFile(configOptions.path, response.data, 'base64')
                .catch((error) => {
                  console.log('File Write Error: ', error);
                });

              filePaths.push({
                title: configOptions.title,
                path: configOptions.path,
                ext: extension(configOptions.title),
                mime,
              });
            } else if (Platform.OS == 'android') {
              if (!this.requestWritePermission()) {
                return;
              }

              RNFetchBlob.fs
                .writeFile(
                  configOptions.addAndroidDownloads.path,
                  response.data,
                  'base64',
                )
                .catch((error) => {
                  console.log('File Write Error: ', error);
                });

              filePaths.push({
                title: configOptions.addAndroidDownloads.title,
                path: configOptions.addAndroidDownloads.path,
                ext: extension(configOptions.addAndroidDownloads.title),
                mime,
              });
            }

            fileCount++;
            if (fileCount >= files.length) {
              resolve('Download Successful!');
            }
          })
          .catch((error) => {
            console.log('File Download Error: ', error.message);
            reject('Download Failed');
          });
      }
    })
      .then((data) => {
        if (isReply) {
          this.setState({isLoading: false, filePathsRep: filePaths});
        } else {
          this.setState({isLoading: false, filePathsEnq: filePaths});
        }
      })
      .catch((error) => {
        console.log('Download Promise Error: ', error);
        this.setState({isLoading: false});
      });
  };

  previewDocument = (id, isReply) => {
    let {filePathsEnq, filePathsRep} = this.state;

    let filePaths = filePathsEnq;
    if (isReply) {
      filePaths = filePathsRep;
    }

    if (Platform.OS == 'ios') {
      RNFetchBlob.ios.openDocument(filePaths[id].path);
    } else if (Platform.OS == 'android') {
      RNFetchBlob.android.actionViewIntent(
        filePaths[id].path,
        filePaths[id].mime,
      );
    }
  };
Anudnya93 commented 1 year ago

Hi @FrankieJLyons . Were you able to resolve the issue ?

lucasGabrielDeAA commented 1 year ago

I was facing a similar problem, and the addandroidDownloads was the root of my problem. After some tests I changed my rn-fetch-blob's config param to work this way:

...
      const { path } = await RNFetchBlob.config({
        fileCache: true,
        path: filePath, // the path where you want to store your file
        appendExt: file.ext // the file extension. e.g: csv, pdf, jpg...
      }).fetch('GET', file.path);
...

After that, you can call path() to access the downloaded file.

Hope some of this can help you! 😉