You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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.xml inside 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 11:33:11