سعيد
سعيد

Reputation: 1764

Permission Denial Error when trying to upload file picked with [react-native-document-picker] to Firestore storage

I'm trying to upload an xlsx to Firestore storage, using react-native-document-picker to pick the file from ExternalStorageDirectoryPath so when I just log the files URI I don't get the error but as soon as try to upload the file it throws the error.

relevant code :

const uploadFile = async () => {
  try {
    const res = await DocumentPicker.pick({
      type: [DocumentPicker.types.allFiles],
    });
           
    const task = Storage().ref('catalogue/'+ res.name).putFile(res.uri);
           
    task.on('state_changed', 
      sn => {},
      err => console.log(err),
      () => {
        console.log('excel uploaded!'+res.name)
        Storage()
          .ref("catalogue").child(res.name).getDownloadURL()
          .then(url => {
            console.log('uploaded excel url', url);
          }).catch(err=>console.log(err))
      }
    )
    await task 
           
  } catch (err) {
    if (DocumentPicker.isCancel(err)) {
      // User cancelled the picker, exit any dialogs or menus and move on
    } else {
      throw err;
    }
  }
}

I already included the required permissions in myAndroidManifest.xml` file and rebuilt the project

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

but still I'm getting this error:

Permission Denial: reading com.android.externalStorageProvider uri content://com... requires android.permission.MANAGE_DOCUMENTS, or grantUriPermission()

Upvotes: 0

Views: 3933

Answers (4)

Clash Con
Clash Con

Reputation: 31

I got the answer, I have to make a copy for cachesDirectory, and then I can access it with fileCopyUri as the key.

Here's the code snippet:

function pickFile() {
    DocumentPicker.pickSingle({
      type: [DocumentPicker.types.allFiles],
      copyTo: "cachesDirectory",
    })
      .then((response) => {
        console.log(response);
        setPickedFile(response);
      })
      .catch((error) => {
        console.error(error);
      });
  }

The response will be looks like this:

 LOG  {
"fileCopyUri": "file:///data/user/0/com.anonymous.mobileodu/cache/4f74e0ae-a628-4a19-bef5-5d18f25f51b1/Flight%20of%20the%20Pigeon.pdf", 
"name": "Flight of the Pigeon.pdf", 
"size": 142754, 
"type": "application/pdf", 
"uri": "content://com.android.providers.downloads.documents/document/raw%3A%2Fstorage%2Femulated%2F0%2FDownload%2FFlight%20of%20the%20Pigeon.pdf"
}

With fileCopyUri, I can access it via ExternalStorage and then show it with react-native-pdf, here's the code snippet:

const DocumentDisplay = ({ url }) => {
    if (!url) {
      return;
    }
    return (
      <View style={{ flex: 1, backgroundColor: "green" }}>
        <Pdf
          trustAllCerts={false}
          source={{ uri: url, cache: true }}
          style={{ flex: 1 }}
          onError={(error) => {
            console.error(error);
            alert("Tidak bisa membuka file");
          }}
        />
        {/* <WebView source={{ uri: "" }} style={{ flex: 1 }} /> */}
      </View>
    );
  };

Upvotes: 0

Abdul Rehman
Abdul Rehman

Reputation: 45

Here is my code that solved this issue:

handleFileSelection = async (props) => {
  try {
    const response = await DocumentPicker.pickMultiple({
      presentationStyle: "fullScreen",
      allowMultiSelection: true,
      copyTo: "cachesDirectory",
    });
    await this.pickImageAndUpload(response[0].fileCopyUri);
  } catch (err) {
    console.warn(err);
  }
};

pickImageAndUpload = async (uri) => {
  const uploadTask = storage()
    .ref()
    .child(`/usersChatImages/${Date.now()}`)
    .putFile(uri);
  uploadTask.on(
    "state_changed",
    (snapshot) => {
      var progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
    },
    (error) => {
      alert("error uploading image");
    },
    () => {
      uploadTask.snapshot.ref
        .getDownloadURL()
        .then((downloadURL) => {
          alert(downloadURL);
        })
        .catch((err) => {
          alert("YESSS");
        });
    }
  );
};

Upvotes: 4

Antoine Laps
Antoine Laps

Reputation: 111

I had a similar problem with the frameworks Qt with the last android SDK version, I've fixed the problem by adding requestLegacyExternalStorage in the manifest (pat Application):

<application
  android:requestLegacyExternalStorage="true"
  android:hardwareAccelerated="true" 
  android:name="org.qtproject.qt5.android.bindings.QtApplication" 
  //...
/>

it's related to a recent change in the permission system: https://developer.android.com/about/versions/11/privacy/storage

Upvotes: 2

muthu raja
muthu raja

Reputation: 26

const res = await DocumentPicker.pickSingle({
  type: [DocumentPicker.types.allFiles],
  copyTo: 'cachesDirectory',
});

let fileCopyUri = res.fileCopyUri
const filename = fileCopyUri.substring(fileCopyUri.lastIndexOf('/') + 1);
const task = storage().ref(filename).putFile(fileCopyUri);

//  add "copyTo: 'cachesDirectory'",
//  add res.fileCopyUri

Upvotes: 0

Related Questions