all, I am new to React Native and Expo File System. I am now having an issue when I was trying to save the document I downloaded from an URL. The error I am facing is: [Error: Location 'content://com.android.providers.downloads.documents/tree/downloads' isn't writable.], which happened when the 'saveAndroidFile' function is called. Here is my code:
function myScreen () {
const [downloadProgress, setDownloadProgress] = React.useState()
const downloadPath =
FileSystem.documentDirectory +
(Platform.OS == 'android' ? '' : '')
const ensureDirAsync = async (dir, intermediates = true) => {
const props = await FileSystem.getInfoAsync(dir)
if (props.exist && props.isDirectory) {
return props
}
let _ = await FileSystem.makeDirectoryAsync(dir, { intermediates })
return await ensureDirAsync(dir, intermediates)
}
const downloadCallback = (downloadProgress) => {
const progress =
downloadProgress.totalBytesWritten /
downloadProgress.totalBytesExpectedToWrite
setDownloadProgress(progress)
}
const downloadFile = async (item) => {
const fileUrl = `whateverpath/Doc111.pdf`
if (Platform.OS == 'android') {
const dir = ensureDirAsync(downloadPath)
}
// get file name without extension and the extension
const list = fileUrl.split('/')
let fileNameWithExtension = list[list.length - 1]
let fileName = fileNameWithExtension.split('.')[0]
const fileType = fileNameWithExtension.split('.')[1]
const downloadResumable = FileSystem.createDownloadResumable(
fileUrl,
downloadPath + fileName,
{},
downloadCallback
)
try {
const { uri } = await downloadResumable.downloadAsync()
if (Platform.OS == 'android') saveAndroidFile(uri, fileName, fileType)
// else saveIosFile(uri)
} catch (e) {
console.error('download error:', e)
}
}
const saveAndroidFile = async (fileUri, fileName = 'File', fileType) => {
// find the mimeType for the downloading file
// memeTypes is a constant store the mapping relationship
const mimeType = mimeTypes[fileType]
try {
const fileString = await FileSystem.readAsStringAsync(fileUri, {
encoding: FileSystem.EncodingType.Base64,
})
const permissions =
await StorageAccessFramework.requestDirectoryPermissionsAsync()
if (!permissions.granted) {
return
}
try {
await StorageAccessFramework.createFileAsync(
permissions.directoryUri,
fileName,
mimeType
)
.then(async (uri) => {
await FileSystem.writeAsStringAsync(uri, fileString, {
encoding: FileSystem.EncodingType.Base64,
})
alert('Report Downloaded Successfully')
})
.catch((e) => {
console.log('save error', e)
})
} catch (e) {
throw new Error(e)
}
} catch (err) {}
}
return (
<View >
<Text style={[{ width: '60%' }]}>
Doc111.pdf
<Text>
<TouchableOpacity onPress={() => downloadFile()}>
<AntDIcon name='download' size={14} />
</TouchableOpacity>
</View>
)
}
Just mentioned here, the folder I have no write access is the "Downloads" folder. And I think this is the location "FileSystem.documentDirectory" will by default take the app download to. And after I change the location, like switch the location to some internal storage folder, for example device_internal_storage/whatever location, I can download the file.
So I am thinking, should I change "FileSystem.documentDirectory" to make it download to somewhere else, or should I find a way to allow the write access to the "Downloads" folder. But I cannot figure out how can I do either of these, if anyone can help to solve these two issue or have any other solution, I would appreciate that. Thank you