如何解决Flutter_inappwebview Android端弹窗阻塞与PDF下载无响应问题
问题解决方法
核心问题分析
你的代码存在三个关键问题导致Android端的弹窗阻止警告:
- 多个回调重复处理PDF链接(
onLoadResource、onDownloadStartRequest、onLoadStart),触发多次跳转/下载操作,导致Chrome内核认为存在未完成的弹窗请求 - 开启了
supportMultipleWindows但未实现对应的窗口创建回调,内核无法正确处理弹窗状态 - 使用
launch打开PDF链接时,Android端会触发外部浏览器弹窗,而webview的弹窗状态未被正确关闭
具体修复步骤
移除重复的PDF处理逻辑
保留onDownloadStartRequest作为唯一的PDF处理入口,删除onLoadResource和onLoadStart中的PDF相关代码,避免重复触发操作。关闭不必要的多窗口支持
将Android选项中的supportMultipleWindows设为false,除非你明确需要多窗口功能并准备好处理onCreateWindow回调。拦截PDF链接的默认导航
在shouldOverrideUrlLoading中判断PDF链接,返回NavigationActionPolicy.CANCEL阻止webview默认加载,直接交给下载逻辑处理。优化PDF打开方式
下载完成后通过本地文件打开,避免使用launch触发外部弹窗,或者使用flutter_inappwebview内置的方式打开PDF(如果需要在webview内显示)。
修改后的代码片段
import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_downloader/flutter_downloader.dart'; import 'package:flutter_inappwebview/flutter_inappwebview.dart'; import 'package:in_app_update/in_app_update.dart'; import 'package:path_provider/path_provider.dart'; import 'package:open_file/open_file.dart'; // 替换url_launcher为open_file,用于打开本地文件 class Home1 extends StatefulWidget { const Home1({super.key}); @override State<Home1> createState() => _Home1State(); } class _Home1State extends State<Home1> { InAppWebViewController? webViewController; bool isLoading = true; final String initialUrl = "你的初始URL"; // 补充你的初始URL @override void initState() { super.initState(); checkForUpdate(); } Future<void> checkForUpdate() async { InAppUpdate.checkForUpdate().then((info) { if (info.updateAvailability == UpdateAvailability.updateAvailable && info.immediateUpdateAllowed) { if (kDebugMode) { print('Update Available'); } InAppUpdate.performImmediateUpdate(); } }).catchError((e) { if (kDebugMode) { print(e.toString()); } }); } /// Method to download the pdf file to the external storage. Future<void> downloadFile(String url) async { final directory = await getExternalStorageDirectory(); // 使用外部存储方便用户访问 if (directory == null) return; final taskId = await FlutterDownloader.enqueue( url: url, savedDir: directory.path, showNotification: true, openFileFromNotification: true, ); // 监听下载完成,打开文件 FlutterDownloader.registerCallback((id, status, progress) { if (id == taskId && status == DownloadTaskStatus.complete) { OpenFile.open("${directory.path}/${url.split('/').last}"); } }); } @override Widget build(BuildContext context) { return Scaffold( body: WillPopScope( onWillPop: () async { if (webViewController != null && await webViewController!.canGoBack()) { webViewController!.goBack(); return false; } return true; }, child: Scaffold( body: SafeArea( child: Stack( children: [ InAppWebView( initialUrlRequest: URLRequest( url: Uri.parse(initialUrl), headers: { 'Content-Security-Policy': 'default-src \'self\';', 'X-content-type-options': 'nosniff' } ), initialOptions: InAppWebViewGroupOptions( crossPlatform: InAppWebViewOptions( useShouldOverrideUrlLoading: true, mediaPlaybackRequiresUserGesture: false, javaScriptEnabled: true, useOnDownloadStart: true, javaScriptCanOpenWindowsAutomatically: false, // 关闭自动弹窗 allowFileAccessFromFileURLs: true, allowUniversalAccessFromFileURLs: true, cacheEnabled: true, ), android: AndroidInAppWebViewOptions( useHybridComposition: true, useWideViewPort: false, builtInZoomControls: false, domStorageEnabled: true, supportMultipleWindows: false, // 关闭多窗口支持 allowFileAccess: true, allowContentAccess: true, databaseEnabled: true, hardwareAcceleration: true, ) ), shouldOverrideUrlLoading: (controller, action) async { final url = action.request.url?.toString(); if (url != null && url.endsWith('.pdf')) { // 拦截PDF链接,直接处理下载 await downloadFile(url); return NavigationActionPolicy.CANCEL; } return NavigationActionPolicy.ALLOW; }, onDownloadStartRequest: (controller, uri) { // 处理页面主动触发的下载请求 downloadFile(uri.toString()); }, onWebViewCreated: (controller) { webViewController = controller; }, onLoadStart: (controller, uri) { setState(() { isLoading = true; }); }, onLoadStop: (controller, url) { setState(() { isLoading = false; }); }, onLoadError: (controller, url, code, message) { if (kDebugMode) { print("Error loading: $message, error code: $code"); } }, ), if (isLoading) const Center( child: CircularProgressIndicator(), ), ], ) ), ), ), ); } }
额外说明
- 替换了
url_launcher为open_file插件,用于打开本地下载的PDF文件,避免触发外部浏览器弹窗 - 改用
getExternalStorageDirectory获取外部存储路径,方便用户在文件管理器中找到下载的PDF - 注册了下载回调,在下载完成后自动打开文件
- 关闭了
javaScriptCanOpenWindowsAutomatically,防止JS自动创建弹窗
内容的提问来源于stack exchange,提问作者Milan Goyal
相关产品推荐
相关产品推荐

