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

RNFetchBlob.android.actionViewIntent is opening an empty view. #483

Open alexisbronchart opened 4 years ago

alexisbronchart commented 4 years ago

I'm using rn-fetch-blob 0.11.2 with react-native 0.61.3 to download files. While it works perfectly on iOS, I have an issue on android. It happens on android 10 (8 & 9 seem fine).

My code:

const DIRS = RNFetchBlob.fs.dirs
const FileManager = Platform.select({
  ios: {
    getDownloadPath: filename => DIRS.CacheDir + '/' + filename,
    preview: path => RNFetchBlob.ios.openDocument(path)
  },
  android: {
    getDownloadPath: filename => DIRS.DownloadDir + '/' + filename,
    preview: RNFetchBlob.android.actionViewIntent
  }
})

const path = FileManager.getDownloadPath(filename)
try {
  const fetchConfig = {
    fileCache: true,
    path,
    appendExt: filename.split('.').slice(-1)[0],
    addAndroidDownloads: {
      title: filename,
      path,
      notification: true,
      mime: mimeType,
      useDownloadManager: true,
      mediaScannable: true
    }
  }
  this.currentTask = RNFetchBlob.config(fetchConfig)
    .fetch('GET', href, {
      Authorization: config.credentials.header
    })
    .progress((received, total) => {
      this.setState({ received, total })
    })
  const response = await this.currentTask
  const downloadPath = response.path()
  FileManager.preview(downloadPath, mimeType)
  this.currentTask = null
} catch (error) {
  this.currentTask = null
}

When I run this on android I'm getting this screen: Screenshot_1572863097

The file is correctly downloaded, the dl manager notification appears and if I tap the notification then the file is opened. But calling RNFetchBlob.android.actionViewIntent right at the end of the download won't open the file.

gorbatenkov commented 4 years ago

Hello, have you found a solution?

gorbatenkov commented 4 years ago

I solved the issue by manually add Storage permissions on my Android 10 emulator.

bockc commented 4 years ago

@gorbatenkov I granted access to both READ_EXTERNAL_STORAGE and WRITE_EXTERNAL_STORAGE but still I can't display it. Could I have a look at your file_provider paths please ?

Also, @alexisbronchart, if you found a solution please share it

olup commented 4 years ago

Any solutions around this ?

gorbatenkov commented 4 years ago

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

R4DIC4L commented 3 years ago

I also had this problem, you need to add request legacy for android 10, as stated by @gorbatenkov, but also request the READ_EXTERNAL_STORAGE and WRITE_EXTERNAL_STORAGE permissions (I believe only read is needed for opening a file with action view intent, if you don't also need to download the file from a server before-hand). Requesting permissions is done via manifest for older android versions (before SDK version 23) as below:

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

For newer android versions, it must be explicitly done before using the action view intent (see https://reactnative.dev/docs/permissionsandroid) as below:

import { PermissionsAndroid } from 'react-native';
const readGranted = await PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.READ_EXTERNAL_STORAGE);
//OR
const writeGranted = await PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE);
// For both, you can use as below and get as response the status in an array for each permission requested
const result = await PermissionsAndroid.requestMultiple([
    PermissionsAndroid.PERMISSIONS.READ_EXTERNAL_STORAGE,
    PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE,
  ]);
const isGranted = result[PermissionsAndroid.PERMISSIONS.READ_EXTERNAL_STORAGE] === 'granted' 
        && result[PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE] === 'granted';

You should do both to support devices before and after SDK version 23.