React Native使用Uri上传至谷歌云存储遇MediaDocumentsProvider权限拒绝问题求助
解决Android中通过content://Uri读取文件时的权限拒绝问题
错误信息
Error: Permission Denial: opening provider com.android.providers.media.MediaDocumentsProvider from ProcessRecord{...} (pid=16294, uid=10169) requires that you obtain access using ACTION_OPEN_DOCUMENT or related APIs
问题原因
你直接硬编码了content://格式的Uri并使用RNFS读取,但Android系统对媒体文档的访问有严格权限限制:这类Uri必须通过ACTION_OPEN_DOCUMENT(或ACTION_GET_CONTENT)系统文件选择器获取,才能获得对应的文件访问授权。直接使用未经过用户授权流程的Uri会被系统拦截。
解决方案
1. 通过文件选择器获取授权后的Uri
使用react-native-document-picker这类库调用系统文件选择器,获取用户选择文件的合法Uri(自动附带访问权限):
import DocumentPicker from 'react-native-document-picker'; const pickFile = async () => { try { const result = await DocumentPicker.pick({ type: [DocumentPicker.types.pdf], // 限制仅选择PDF文件 }); // 将授权后的Uri传入上传函数 await handleFileUpload(result.uri); } catch (err) { if (DocumentPicker.isCancel(err)) { // 用户取消文件选择 } else { console.error('文件选择出错', err); } } };
2. 修正上传函数逻辑
- 移除硬编码的Uri,改用文件选择器返回的授权Uri
- 修复模板字符串语法错误(原代码中
'Bearer: ${oauthToken}'用单引号导致变量不生效) - 确保文件读取适配授权后的
content://Uri(RNFS需确保权限,或改用expo-file-system更稳定)
const handleFileUpload = async (fileUri) => { try { // 读取文件内容(以RNFS为例,若用Expo可替换为expo-file-system的readAsStringAsync) const fileContent = await RNFS.readFile(fileUri, 'base64'); const binaryData = Buffer.from(fileContent, 'base64'); const response = await axios.post( 'https://storage.googleapis.com/upload/storage/v1/b/Bucket_Name/o?uploadType=media&name=Hello%20World', binaryData, { headers: { 'Authorization': `Bearer ${oauthToken}`, // 改用反引号实现模板变量 'Content-Type': 'application/pdf', }, responseType: 'json', } ); console.log('文件上传成功', response.data); } catch (error) { console.log('上传出错', error); } };
3. 关键注意事项
- 禁止硬编码
content://Uri:这类Uri是临时且依赖授权的,硬编码会导致权限失效 - 权限持久化:通过系统选择器获取的Uri可通过
takePersistableUriPermission持久化权限,多数文档选择器库会自动处理 - 适配不同Uri类型:若遇到无法读取的情况,可优先使用
expo-file-system,它对content://和file://Uri的兼容性更好
内容的提问来源于stack exchange,提问作者Dương Nguyễn Bá
相关产品推荐
相关产品推荐

