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

如何解决Flutter_inappwebview Android端弹窗阻塞与PDF下载无响应问题

问题解决方法

核心问题分析

你的代码存在三个关键问题导致Android端的弹窗阻止警告:

  • 多个回调重复处理PDF链接(onLoadResource、onDownloadStartRequest、onLoadStart),触发多次跳转/下载操作,导致Chrome内核认为存在未完成的弹窗请求
  • 开启了supportMultipleWindows但未实现对应的窗口创建回调,内核无法正确处理弹窗状态
  • 使用launch打开PDF链接时,Android端会触发外部浏览器弹窗,而webview的弹窗状态未被正确关闭

具体修复步骤

  1. 移除重复的PDF处理逻辑
    保留onDownloadStartRequest作为唯一的PDF处理入口,删除onLoadResource和onLoadStart中的PDF相关代码,避免重复触发操作。

  2. 关闭不必要的多窗口支持
    将Android选项中的supportMultipleWindows设为false,除非你明确需要多窗口功能并准备好处理onCreateWindow回调。

  3. 拦截PDF链接的默认导航
    在shouldOverrideUrlLoading中判断PDF链接,返回NavigationActionPolicy.CANCEL阻止webview默认加载,直接交给下载逻辑处理。

  4. 优化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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 02:17:35