Flutter中如何获取内外存储的所有PDF文件并实现点击全屏打开?
Hey there! Let's build this feature step by step—we'll scan both internal and external storage for all PDF files, display them in a list, and open any selected file in a full-screen dialog. Here's a practical, working guide with code you can adapt:
Step 1: Add Required Dependencies
First, add these packages to your pubspec.yaml to handle permissions, storage access, and PDF viewing:
dependencies: flutter: sdk: flutter permission_handler: ^10.2.0 flutter_pdfview: ^1.2.1 path_provider: ^2.0.15 device_info_plus: ^9.0.2
Run flutter pub get to install them.
Step 2: Request Storage Permissions
We need permissions to access device storage. Create a helper function to handle this (works for Android and iOS):
import 'package:permission_handler/permission_handler.dart'; import 'package:device_info_plus/device_info_plus.dart'; Future<bool> requestStoragePermission() async { PermissionStatus status; if (Platform.isAndroid) { final androidInfo = await DeviceInfoPlugin().androidInfo; if (androidInfo.version.sdkInt >= 33) { status = await Permission.manageExternalStorage.request(); } else { status = await Permission.storage.request(); } } else if (Platform.isIOS) { status = await Permission.photosAddOnly.request(); } else { status = PermissionStatus.granted; } return status.isGranted; }
Don't forget to declare permissions in native config files:
- Android: Add these to
AndroidManifest.xmlinside the<manifest>tag:<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32"/> <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" /> - iOS: Add this to
Info.plist:<key>NSDocumentsFolderUsageDescription</key> <string>Need access to documents to scan PDF files</string>
Step 3: Scan for All PDF Files
Next, write a function to fetch PDFs. For Android 10+, we use MediaStore (since direct directory access is restricted), and traverse directories for older versions/iOS:
import 'dart:io'; import 'package:path_provider/path_provider.dart'; import 'package:sqflite/sqflite.dart'; Future<List<File>> getAllPdfFiles() async { List<File> pdfFiles = []; if (Platform.isAndroid) { final androidInfo = await DeviceInfoPlugin().androidInfo; // Handle Android 10+ with MediaStore if (androidInfo.version.sdkInt >= 29) { final database = await openDatabase( '/data/data/com.android.providers.media/databases/external.db', readOnly: true, ); final result = await database.rawQuery(''' SELECT _data FROM files WHERE mime_type = 'application/pdf' '''); for (var row in result) { final path = row['_data'] as String; if (await File(path).exists()) pdfFiles.add(File(path)); } await database.close(); } else { // Traverse external storage for older Android versions final externalDir = await getExternalStorageDirectory(); if (externalDir != null) pdfFiles.addAll(await _scanDirForPdfs(externalDir)); } // Scan internal app storage final internalDir = await getApplicationDocumentsDirectory(); pdfFiles.addAll(await _scanDirForPdfs(internalDir)); } else if (Platform.isIOS) { // Scan iOS documents directory final docsDir = await getApplicationDocumentsDirectory(); pdfFiles.addAll(await _scanDirForPdfs(docsDir)); } // Remove duplicate files return pdfFiles.toSet().toList(); } Future<List<File>> _scanDirForPdfs(Directory dir) async { List<File> pdfs = []; try { await for (var entity in dir.list(recursive: true)) { if (entity is File && entity.path.endsWith('.pdf')) pdfs.add(entity); } } catch (e) { print('Error scanning directory: $e'); } return pdfs; }
Step 4: Display the PDF List
Build the UI to show the scanned PDFs in a list:
class PdfListScreen extends StatefulWidget { const PdfListScreen({super.key}); @override State<PdfListScreen> createState() => _PdfListScreenState(); } class _PdfListScreenState extends State<PdfListScreen> { List<File> _pdfFiles = []; bool _isLoading = true; @override void initState() { super.initState(); _loadPdfFiles(); } Future<void> _loadPdfFiles() async { final hasPermission = await requestStoragePermission(); if (hasPermission) _pdfFiles = await getAllPdfFiles(); setState(() => _isLoading = false); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('All PDF Files')), body: _isLoading ? const Center(child: CircularProgressIndicator()) : _pdfFiles.isEmpty ? const Center(child: Text('No PDF files found')) : ListView.builder( itemCount: _pdfFiles.length, itemBuilder: (context, index) { final file = _pdfFiles[index]; final fileName = file.path.split('/').last; return ListTile( title: Text(fileName), subtitle: Text(file.path), onTap: () => _openPdfInFullScreen(file), ); }, ), ); } }
Step 5: Open PDF in Full-Screen Dialog
Add a function to open the selected PDF in a full-screen dialog:
import 'package:flutter_pdfview/flutter_pdfview.dart'; void _openPdfInFullScreen(File pdfFile) { showDialog( context: context, barrierDismissible: false, builder: (context) => Dialog( insetPadding: EdgeInsets.zero, child: SizedBox( width: MediaQuery.of(context).size.width, height: MediaQuery.of(context).size.height, child: Stack( children: [ PDFView( filePath: pdfFile.path, enableSwipe: true, swipeHorizontal: true, pageFling: true, onError: (error) { print('PDF Error: $error'); Navigator.pop(context); }, ), // Add a close button Positioned( top: 20, right: 20, child: IconButton( icon: const Icon(Icons.close, color: Colors.white), onPressed: () => Navigator.pop(context), ), ), ], ), ), ), ); }
Quick Notes:
- Android 10+ Scoped Storage: The MediaStore path might vary slightly across devices—test on multiple devices to handle edge cases.
- iOS Restrictions: iOS limits access to certain directories; you can add access to the Downloads folder by enabling appropriate capabilities in Xcode.
- Error Handling: Expand the try/catch blocks to handle cases like deleted files or permission denials gracefully.
内容的提问来源于stack exchange,提问作者Tushar Pol

