rn-fetch-blob icon indicating copy to clipboard operation
rn-fetch-blob copied to clipboard

Can't open pdf after download

Open mMarcos208 opened this issue 5 years ago • 19 comments

Configurations of my pdf

CONTENT-TYPE | application/octet-stream

My code

const downloadPdf = (uri: string, nome: string): void => {
    setLoading(true)
    const {config, fs} = RNFetchBlob
    const PictureDir = fs.dirs.DownloadDir
    const options = {
      fileCache: true,
      addAndroidDownloads: {
        useDownloadManager: true,
        notification: true,
        title: nome,
        path: `${PictureDir}/${nome}`,
      },
      appendExt: 'pdf',
    }
    config(options)
      .fetch('GET', uri, {
        // Accept: 'application/json',
        // 'Content-Type': 'multipart/form-data,octet-stream',
        'Content-Type': 'multipart/form-data',
      })
      .then((_) => {
        Snackbar.show({
          text: 'Download realizado com sucesso!',
          backgroundColor: colors.silverTree,
        })
      })
      .catch((_) => {
        Snackbar.show({
          text: 'Error ao realizar download!',
          backgroundColor: colors.valencia,
        })
      })
      .finally(() => setLoading(false))
  }

mMarcos208 avatar Aug 25 '20 18:08 mMarcos208

Só falta seu código pra abrir aquele file, né?

leonardoballand avatar Aug 31 '20 12:08 leonardoballand

@mMarcos208 You need to add code to open file. E.g.:

RNFetchBlob
    .config({ ...defaultOptions, ...options })
    .fetch('GET', url, {
      // Headers...
    })
    .progress((received, total) => {
      Console.log('progress', received / total);
    })
   .then((res) => {
      // The temp file path
      Console.log('File:', res);
      Console.log('The file saved to:', res.path());

      if (Platform.OS === 'android') {
        RNFetchBlob.android.actionViewIntent(res.path(), mimeType || 'application/pdf');
      }

      if (Platform.OS === 'ios') {
        RNFetchBlob.ios.previewDocument(res.path());
      }
    });

adaerodriguez avatar Sep 01 '20 14:09 adaerodriguez

Hi @adaerodriguez,

I'm doing exactly this in my app. It works well on iOS ! However, on Android, it goes to a black screen on

RNFetchBlob.android.actionViewIntent(res.path(), mimeType || 'application/pdf');

And come back to the app. If i touch my notification on my phone, it redirects me to the file, which has been successfully downloaded on my phone.

Would you know what causes this issue ?

RN: 0.63.2 RN-Fetch-Blob: 0.12.0

louisiscoding avatar Sep 01 '20 14:09 louisiscoding

Hi @LouisJS, is possible you forgot some parameter in the config? or do you forgot to ask for permissions? This is my config:

const options = Platform.select({
    android: {
      // appendText: fileType || defaultFileType, // if you need file extension
      path: `${DownloadDir}/${name}`,
      /** With Download manger */
      // addAndroidDownloads: {
      //   path: `${DownloadDir}/${name}`,
      //   useDownloadManager: true,
      //   mediaScannable: true,
      //   notification: true,
      //   overwrite: true,
      //   // Optional, but recommended since android DownloadManager will fail when
      //   // the url does not contains a file extension, by default the mime type will be text/plain
      //   // mime: 'text/plain',
      //   description: strings('files.downloadByManager'),
      // },
    },
    ios: {
      // appendText: fileType || defaultFileType, // if you need file extension
      path: `${DocumentDir}/${name}`,
      // IOSBackgroundTask: true,
      // IOSUploadTask: true,
    },
  });

if (Platform.OS === 'android') {
    getPermissionWriteExternalStorage(
      (status, tag) => { Console.log('getPermissionWriteExternalStorage - status:', status, ' | tag: ', tag); },
      () => { downloadFile(url, options, fileType, callbackSuccess); },
    );
  }

  if (Platform.OS === 'ios') {
    downloadFile(url, options, fileType, callbackSuccess);
  }

My permission method is:

export const getPermissionWriteExternalStorage = async (callbackError, callbackSuccess) => {
  const permission = PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE;
  const permissionTag = Permission.PERMISSION_WRITE_EXTERNAL_STORAGE;

  try {
    const status = await PermissionsAndroid.request(permission);
    permissionResult(status, permissionTag, callbackError, callbackSuccess);
  } catch (err) {
    Console.warn(err);
  }
};

And my defaultConfig that I have in RNFetchBlob:

const defaultOptions = {
    fileCache: true,
    timeout: 1000 * 15, // 15 seconds
  };

I hope that my code could help you :)

adaerodriguez avatar Sep 01 '20 14:09 adaerodriguez

I do ask for permission

const grantPermission = async () => {
    if (Platform.OS === 'android') {
      return requestMultiple([
        PERMISSIONS.ANDROID.WRITE_EXTERNAL_STORAGE,
        PERMISSIONS.ANDROID.READ_EXTERNAL_STORAGE,
      ]);
    } else {
      return request(PERMISSIONS.IOS.WRITE_EXTERNAL_STORAGE);
    }
  };

And the file is downloaded on my phone. I can open it then via the notification :/

louisiscoding avatar Sep 01 '20 15:09 louisiscoding

Maybe your path is wrong? The path for iOS and Android is differente. Look at my config

const { dirs: { DownloadDir, DocumentDir } } = RNFetchBlob.fs;

adaerodriguez avatar Sep 01 '20 16:09 adaerodriguez

The file is well downloaded. The thing i can't do is open it with RNFetchBlob.android.actionViewIntent

louisiscoding avatar Sep 01 '20 16:09 louisiscoding

Only to discard mistakes. Could you see if you have the correct permissions selected into Settings > Apps > "Your app" > Permissions. Are you using the "Download Manager" ?

adaerodriguez avatar Sep 01 '20 16:09 adaerodriguez

Here is a demo of what happens.

It tries to open the file. But come back to the app immediately after that.

louisiscoding avatar Sep 02 '20 14:09 louisiscoding

I see.... You are using Download Manager as well. Before I used Download Manager as you can see in my config and it works perfectly. In my opinion, there is some option that you haven't put in your config. Test this options in your code:

const options = Platform.select({
  android: {
  /** With Download manger */
    addAndroidDownloads: {
       path: `${DownloadDir}/${name}`,
       useDownloadManager: true,
       mediaScannable: true,
       notification: true,
       overwrite: true,
       // Optional, but recommended since android DownloadManager will fail when
       // the url does not contains a file extension, by default the mime type will be text/plain
       // mime: 'text/plain',
      //   description: strings('files.downloadByManager'),
     },
});

adaerodriguez avatar Sep 02 '20 15:09 adaerodriguez

I've tried with this image so we can try with the same file ;)

My Code is this exactly this one

const downloadFile = async () => {
  const {
    dirs: { DownloadDir, DocumentDir },
  } = RNFetchBlob.fs;

  const name = 'airplane.png';

  const options = Platform.select({
    android: {
      /** With Download manger */
      addAndroidDownloads: {
        path: `${DownloadDir}/${name}`,
        title: name,
        useDownloadManager: true,
        mediaScannable: true,
        notification: true,
        overwrite: true,
      },
    },
    ios: {
      path: `${DocumentDir}/${name}`,
    },
  });

  return RNFetchBlob.config({ ...options })
    .fetch('GET', 'https://homepages.cae.wisc.edu/~ece533/images/airplane.png')
    .then((res) => {
      // The temp file path
      console.log('File:', res);
      console.log('The file saved to:', res.path());

      if (Platform.OS === 'android') {
        RNFetchBlob.android.actionViewIntent(res.path(), 'image/png');
      }

      if (Platform.OS === 'ios') {
        RNFetchBlob.ios.previewDocument(res.path());
      }
    });
};

So this time it does not go back directly to the app, but it infinitely loads the content. Right after that, i can tap my notification and see my file instantaneously

You can preview the result here

louisiscoding avatar Sep 02 '20 15:09 louisiscoding

Same here, it opens the pdf app for a split second but comes back directly to my app. Pressing the notification or accessing through the file app works fine tho...

olup avatar Sep 07 '20 20:09 olup

Same issue here, any update?

Here's my code :

return RNFetchBlob.config({
    path,
    addAndroidDownloads: {
      useDownloadManager: true,
      path,
      notification: true,
      title: notificationTitle,
      mime: 'application/pdf',
      mediaScannable: true,
    },
  })
    .fetch('GET', apiUrl)
    .then((res) => {
      if (Platform.OS === 'android') {
        RNFetchBlob.android.actionViewIntent(res.path(), 'application/pdf');
      } else {
        RNFetchBlob.ios.openDocument(res.path());
      }

      return res;
    });

Before this I ask READ and WRITE permission on Android :

PERMISSIONS.ANDROID.WRITE_EXTERNAL_STORAGE
PERMISSIONS.ANDROID.READ_EXTERNAL_STORAGE

And I have the following in AndroidManifest :

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
 <intent-filter>
    <action android:name="android.intent.action.MAIN" />
    <category android:name="android.intent.category.LAUNCHER" />
    <action android:name="android.intent.action.DOWNLOAD_COMPLETE"/>
</intent-filter>

Thanks,

kaayru avatar Sep 18 '20 16:09 kaayru

Was able to fix it by adding android:requestLegacyExternalStorage="true" to my manifest file. Based on this https://medium.com/@sriramaripirala/android-10-open-failed-eacces-permission-denied-da8b630a89df

gorbatenkov avatar Oct 01 '20 11:10 gorbatenkov

Was able to fix it by adding android:requestLegacyExternalStorage="true" to my manifest file. Based on this https://medium.com/@sriramaripirala/android-10-open-failed-eacces-permission-denied-da8b630a89df

Confirmed, works like a charm 👍

maxowy avatar Oct 22 '20 23:10 maxowy

I'm fix it by

  1. Add below permissions in AndroidManifest.xml
  2. To use downloadmanager, add below action in intent in AndroidManifest.xml
  3. import PermissionsAndroid, Alert from react native (android only)

Credit : https://stackoverflow.com/questions/56887851/react-native-download-pdf-file-with-rn-fetch-blob-on-click-a-button?answertab=votes#tab-top

tanapon395 avatar Jun 27 '21 22:06 tanapon395

In my case using mime type in config object made it work. RNFetchBlob.config({ path, addAndroidDownloads: { useDownloadManager: true, path, notification: true, title: notificationTitle, mime: 'application/pdf', mediaScannable: true, },

kv77724-dot avatar Feb 04 '22 10:02 kv77724-dot

A mi me srivio este codigo tanto en Ios y Android

const { config, fs } = RNFetchBlob;
config({
    fileCache: true,
    addAndroidDownloads: {
        useDownloadManager: true,
        notification: true,
        path: fs.dirs.PictureDir + '/IU-APP/' + file.name.split('/').pop(),
    },
    path: fs.dirs.DocumentDir + '/' + file.name.split('/').pop()
}).fetch('GET', encodeURI(file.url)).then(async(res) => {
    if (Platform.OS === "ios") RNFetchBlob.ios.previewDocument(res.path());
}).catch(error => {
    showAlert('Error al descargar el documento!', 'danger')
})

cirilojesus avatar Jul 15 '23 03:07 cirilojesus

const { dirs } = ReactNativeBlobUtil.fs
		const directory = isIos ? dirs.DocumentDir : dirs.DownloadDir

		setIsLoading(true)

		ReactNativeBlobUtil.config({
			addAndroidDownloads: {
				storeInDownloads: true,
				useDownloadManager: true,
				notification: true,
				path: directory + '/' + fileName,
				mime: 'application/pdf',
				description: 'Download contract',
				mediaScannable: true,
				title: fileName,
			},
			path: directory + '/' + fileName,
			fileCache: true,
		})	

in my case, i followed the android permissions rules but i didn't work, then i added title, and it starts working as expected

Kaung-Htet-Hein avatar Jan 19 '24 06:01 Kaung-Htet-Hein