Flutter WebView无法显示/下载PDF的解决方案咨询
在Flutter应用内通过flutter_inappwebview实现PDF下载并打开
核心思路
利用flutter_inappwebview的下载监听回调拦截PDF下载请求,通过网络库将文件下载到本地存储,再调用PDF查看组件在应用内完成打开操作。
步骤1:添加依赖
在pubspec.yaml中引入所需依赖包:
dependencies: flutter_inappwebview: ^6.0.0 # 建议使用最新稳定版本 dio: ^5.0.0 path_provider: ^2.0.0 open_file: ^3.0.0 # 若需内嵌查看可替换为flutter_pdfview
步骤2:实现下载与打开逻辑
在InAppWebView组件中配置下载监听,拦截PDF请求并处理下载流程:
import 'dart:io'; import 'package:dio/dio.dart'; import 'package:flutter_inappwebview/flutter_inappwebview.dart'; import 'package:path_provider/path_provider.dart'; import 'package:open_file/open_file.dart'; class PDFDownloadPage extends StatefulWidget { @override _PDFDownloadPageState createState() => _PDFDownloadPageState(); } class _PDFDownloadPageState extends State<PDFDownloadPage> { InAppWebViewController? webViewController; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('PDF下载测试')), body: InAppWebView( initialUrlRequest: URLRequest( url: Uri.parse('https://www.wmata.com/schedules/maps/upload/2019-System-Map.pdf'), ), onWebViewCreated: (controller) => webViewController = controller, downloadListener: (DownloadTask task) async { // 仅拦截PDF格式的下载请求 if (task.url.path.endsWith('.pdf')) { await _handlePDFDownload(task.url.toString()); } }, ), ); } Future<void> _handlePDFDownload(String pdfUrl) async { try { // 获取本地存储目录 Directory? storageDir; if (Platform.isAndroid) { storageDir = await getExternalStorageDirectory(); } else if (Platform.isIOS) { storageDir = await getApplicationDocumentsDirectory(); } if (storageDir == null) return; // 生成文件存储路径 final fileName = pdfUrl.split('/').last; final savePath = '${storageDir.path}/$fileName'; final targetFile = File(savePath); // 使用Dio执行下载 final dio = Dio(); await dio.download( pdfUrl, targetFile.path, onReceiveProgress: (count, total) { // 可在此添加下载进度提示逻辑 print('下载进度:${(count / total * 100).toStringAsFixed(0)}%'); }, ); // 下载完成后打开PDF await OpenFile.open(targetFile.path); } catch (e) { print('下载失败:$e'); // 可在此添加错误提示UI } } }
步骤3:配置平台权限
- Android:在
android/app/src/main/AndroidManifest.xml中添加存储权限(Android 13+下载到应用私有目录无需额外动态申请):
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="32"/> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32"/>
- iOS:在
Info.plist中添加文件访问权限声明:
<key>LSSupportsOpeningDocumentsInPlace</key> <true/> <key>UIFileSharingEnabled</key> <true/>
关键说明
- 通过
flutter_inappwebview的downloadListener直接拦截请求,无需跳转外部浏览器。 - 下载到应用私有目录更安全,避免权限申请复杂流程。
- 若需内嵌查看PDF,可替换
open_file为flutter_pdfview,将下载后的文件路径传入PDFView组件即可实现内嵌预览。
内容的提问来源于stack exchange,提问作者Roman Soviak
相关产品推荐
相关产品推荐

