如何通过react-native-fs/react-native-blob获取安卓设备所有PDF文件并展示?
安卓设备获取所有PDF文件名称和路径的解决方案
1. 权限配置(核心前提)
首先在AndroidManifest.xml中添加对应安卓版本的存储权限:
- 安卓12及以下版本:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <application ... android:requestLegacyExternalStorage="true"> <!-- 适配安卓10分区存储规则 -->
- 安卓13及以上版本:
<uses-permission android:name="android.permission.READ_MEDIA_DOCUMENTS" />
若需访问所有文件(含其他应用私有目录),需添加特殊权限(仅适用于合规场景,需用户手动在设置开启):
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
2. 用react-native-fs实现递归扫描
先确保依赖安装完成:
npm install react-native-fs --save # RN0.59及以下版本需执行link react-native link react-native-fs
编写扫描逻辑:
import RNFS from 'react-native-fs'; // 存储扫描到的PDF文件 let pdfFiles = []; // 递归扫描目录 const scanDirectory = async (dirPath) => { try { const files = await RNFS.readDir(dirPath); for (const file of files) { if (file.isDirectory()) { // 递归扫描子目录 await scanDirectory(file.path); } else { // 筛选PDF文件(不区分大小写) if (file.name.toLowerCase().endsWith('.pdf')) { pdfFiles.push({ name: file.name, path: file.path }); } } } } catch (err) { console.error('扫描目录出错:', err); } }; // 启动扫描流程 const startScanning = async () => { pdfFiles = []; // 安卓外部存储根目录 const externalRoot = RNFS.ExternalStorageDirectoryPath; // 优先扫描常用公共目录(减少不必要的扫描耗时) const targetDirs = [ `${externalRoot}/Download`, `${externalRoot}/Documents`, `${externalRoot}/Books` ]; for (const dir of targetDirs) { // 先校验目录是否存在 const isExist = await RNFS.exists(dir); if (isExist) { await scanDirectory(dir); } } // 扫描完成后更新状态,用于页面渲染 // setPdfList(pdfFiles); // 需在组件中定义对应state console.log('扫描到的PDF文件:', pdfFiles); };
3. 运行时权限请求
必须先获取用户授权才能访问存储,可直接用React Native内置API处理:
import { PermissionsAndroid } from 'react-native'; const requestStoragePermission = async () => { try { const granted = await PermissionsAndroid.request( // 安卓13+替换为PermissionsAndroid.PERMISSIONS.READ_MEDIA_DOCUMENTS PermissionsAndroid.PERMISSIONS.READ_EXTERNAL_STORAGE, { title: "存储权限申请", message: "需要访问您的存储以查找PDF文件", buttonPositive: "确定", buttonNegative: "取消" } ); if (granted === PermissionsAndroid.RESULTS.GRANTED) { // 权限通过,启动扫描 await startScanning(); } else { console.log("存储权限被拒绝"); } } catch (err) { console.warn(err); } };
4. 页面渲染扫描结果
在组件中调用权限请求,并将扫描到的PDF列表渲染到屏幕:
import { useState, useEffect } from 'react'; import { View, Text, FlatList, StyleSheet } from 'react-native'; export default function PDFScannerPage() { const [pdfList, setPdfList] = useState([]); useEffect(() => { // 重写startScanning中的结果处理,将数据同步到state const customStartScanning = async () => { pdfFiles = []; const externalRoot = RNFS.ExternalStorageDirectoryPath; const targetDirs = [ `${externalRoot}/Download`, `${externalRoot}/Documents` ]; for (const dir of targetDirs) { const isExist = await RNFS.exists(dir); if (isExist) await scanDirectory(dir); } setPdfList(pdfFiles); }; // 包装权限请求与扫描逻辑 const initScan = async () => { await requestStoragePermission(); }; initScan(); }, []); return ( <View style={styles.container}> <Text style={styles.title}>扫描到的PDF文件</Text> <FlatList data={pdfList} keyExtractor={(item) => item.path} renderItem={({ item }) => ( <View style={styles.itemCard}> <Text style={styles.fileName}>{item.name}</Text> <Text style={styles.filePath}>{item.path}</Text> </View> )} /> </View> ); } const styles = StyleSheet.create({ container: { flex: 1, padding: 16, backgroundColor: '#fff' }, title: { fontSize: 20, fontWeight: '600', marginBottom: 16 }, itemCard: { padding: 12, borderBottomWidth: 1, borderBottomColor: '#eee', marginBottom: 8 }, fileName: { fontSize: 16, fontWeight: '500' }, filePath: { fontSize: 12, color: '#666', marginTop: 4 } });
常见问题排查
- 无法获取全部PDF:安卓10+的分区存储限制,无法访问其他应用的私有目录(如
Android/data下其他应用的文件夹),这是系统级限制;若需访问所有文件,必须引导用户开启MANAGE_EXTERNAL_STORAGE权限。 - 扫描速度慢:可跳过系统隐藏目录、临时文件目录,或仅扫描常用的几个公共目录(如Download、Documents)。
- 权限失效:确保在运行时主动请求权限,而非仅在Manifest中声明。
内容的提问来源于stack exchange,提问作者Anujfresco Fresco
相关产品推荐
相关产品推荐

