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

Flutter中WebView加载失败时如何从Assets加载自定义HTML

解决webview_flutter中onWebResourceError先于onWebViewCreated执行的问题

方案一:缓存错误事件,等待控制器初始化后处理

通过变量缓存错误信息,等控制器创建完成后再执行错误页面加载逻辑,避免因控制器未就绪导致的空指针问题。

修改后的代码示例:

WebViewController? webViewController;
WebResourceError? _pendingError;

@override
Widget build(BuildContext context) {
  return SafeArea(
    child: WebView(
      initialUrl: widget.url,
      javascriptMode: JavascriptMode.unrestricted,
      allowsInlineMediaPlayback: true,
      debuggingEnabled: true,
      userAgent: "",
      onWebViewCreated: (controller) {
        webViewController = controller;
        // 控制器初始化完成后,检查是否有待处理的错误
        if (_pendingError != null) {
          controller.loadFlutterAsset("assets/error.html");
          _pendingError = null;
        }
      },
      initialMediaPlaybackPolicy: AutoMediaPlaybackPolicy.always_allow,
      onWebResourceError: (webResourceError) {
        // 控制器未就绪时缓存错误,否则直接加载错误页
        if (webViewController == null) {
          _pendingError = webResourceError;
        } else {
          webViewController?.loadFlutterAsset("assets/error.html");
        }
      },
    ),
  );
}

方案二:调整加载顺序,先初始化控制器再加载目标URL

让WebView先加载空白页确保控制器优先创建完成,之后再加载目标业务URL,这样后续的错误回调能直接拿到可用的控制器。

代码示例:

WebViewController? webViewController;

@override
Widget build(BuildContext context) {
  return SafeArea(
    child: WebView(
      initialUrl: "about:blank", // 先加载空白页触发控制器初始化
      javascriptMode: JavascriptMode.unrestricted,
      allowsInlineMediaPlayback: true,
      debuggingEnabled: true,
      userAgent: "",
      onWebViewCreated: (controller) {
        webViewController = controller;
        // 控制器就绪后再加载目标URL
        controller.loadUrl(widget.url);
      },
      initialMediaPlaybackPolicy: AutoMediaPlaybackPolicy.always_allow,
      onWebResourceError: (webResourceError) {
        webViewController?.loadFlutterAsset("assets/error.html");
      },
    ),
  );
}

方案三:用Completer异步等待控制器就绪

利用Completer封装控制器的初始化过程,在错误回调中异步等待控制器创建完成后执行加载逻辑。

代码示例:

final Completer<WebViewController> _controllerCompleter = Completer();

@override
Widget build(BuildContext context) {
  return SafeArea(
    child: WebView(
      initialUrl: widget.url,
      javascriptMode: JavascriptMode.unrestricted,
      allowsInlineMediaPlayback: true,
      debuggingEnabled: true,
      userAgent: "",
      onWebViewCreated: (controller) {
        _controllerCompleter.complete(controller);
      },
      initialMediaPlaybackPolicy: AutoMediaPlaybackPolicy.always_allow,
      onWebResourceError: (webResourceError) async {
        // 等待控制器初始化完成
        final controller = await _controllerCompleter.future;
        controller.loadFlutterAsset("assets/error.html");
      },
    ),
  );
}

以上三种方案均可解决你遇到的问题,你可以根据项目实际场景选择合适的实现方式。

内容的提问来源于stack exchange,提问作者ammcom

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 05:16:00