React Native如何实现设备内.pdf/.doc等多格式文档的检索功能
React Native 多格式文档检索实现方案
第一步:权限配置
Android端权限
- Android 13及以上:需要申请
READ_MEDIA_IMAGES等媒体权限,如需扫描整个设备存储,还需要引导用户手动开启「所有文件访问」特殊权限 - Android 12及以下:申请
READ_EXTERNAL_STORAGE、WRITE_EXTERNAL_STORAGE权限
所有权限除了在AndroidManifest.xml中声明,还需要做动态申请。
iOS端权限
需要在Info.plist中添加NSDocumentFolderUsageDescription、NSLibrariesFolderUsageDescription权限说明,明确告知用户访问文件的用途。
第二步:核心实现逻辑
你之前使用的lstat仅能获取当前目录的一级文件/文件夹信息,要检索全设备文档需要做递归目录遍历,Android端也可以调用MediaStore实现更高效率的查询,以下是跨平台的递归遍历实现代码:
import { PermissionsAndroid, Platform } from 'react-native'; import RNFetchBlob from 'rn-fetch-blob'; // 允许匹配的文档后缀 const ALLOWED_EXTENSIONS = ['pdf', 'doc', 'docx', 'ppt', 'pptx', 'xls', 'xlsx', 'txt']; // 动态申请存储权限 const requestStoragePermission = async () => { if (Platform.OS !== 'android') return true; if (Platform.Version >= 33) { const granted = await PermissionsAndroid.request( PermissionsAndroid.PERMISSIONS.READ_MEDIA_IMAGES, { title: '存储访问权限', message: '需要访问设备存储以查找文档', buttonPositive: '允许', } ); return granted === PermissionsAndroid.RESULTS.GRANTED; } else { const granted = await PermissionsAndroid.request( PermissionsAndroid.PERMISSIONS.READ_EXTERNAL_STORAGE, { title: '存储访问权限', message: '需要访问设备存储以查找文档', buttonPositive: '允许', } ); return granted === PermissionsAndroid.RESULTS.GRANTED; } }; // 递归遍历目录筛选符合条件的文件 const scanDirectory = async (dirPath, resultList = []) => { try { const stats = await RNFetchBlob.fs.lstat(dirPath); for (const item of stats) { // 跳过系统目录、隐藏目录,避免无权限报错 if (item.type === 'directory' && !item.path.includes('/Android/') && !item.path.startsWith('.')) { await scanDirectory(item.path, resultList); } else if (item.type === 'file') { const fileExtension = item.filename.split('.').pop().toLowerCase(); if (ALLOWED_EXTENSIONS.includes(fileExtension)) { resultList.push({ name: item.filename, path: item.path, size: item.size, lastModified: item.lastModified, type: fileExtension }); } } } return resultList; } catch (err) { // 跳过无权限访问的目录不报错 return resultList; } }; // 业务调用示例 useEffect(() => { const getDocuments = async () => { const hasPermission = await requestStoragePermission(); if (!hasPermission) return; const rootDir = RNFetchBlob.fs.dirs.SDCardDir; const documents = await scanDirectory(rootDir); console.log('检索到的文档列表:', documents); }; getDocuments(); }, []);
性能优化建议
- Android端如果需要更高的扫描效率,建议自行封装原生模块调用MediaStore接口,通过SQL语句直接筛选指定后缀的文件,查询速度比递归遍历高10倍以上
- iOS端如果不需要后台自动扫描,也可以调用系统文档选择器让用户主动选择目标文档,不需要申请全存储访问权限
内容的提问来源于stack exchange,提问作者Engr.Aftab Ufaq
相关产品推荐
相关产品推荐

