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

Flutter WebView如何实现实时断网展示离线页 重连返回原页面

Flutter WebView 离线场景适配实现

实现逻辑拆解

  • 用connectivity_plus做全局网络状态实时监听,不需要用户手动触发检测,状态变化由系统自动回调
  • 网络断开时直接替换WebView为自定义离线提示页,内置重试按钮
  • 每次WebView页面加载完成记录当前访问URL,网络恢复后自动加载该地址,直接回到用户断网前的停留页

具体实现步骤

  • 先在pubspec.yaml添加需要的依赖:
dependencies:
  flutter:
    sdk: flutter
  webview_flutter: (使用项目当前适配的稳定版本即可)
  connectivity_plus: (选择最新稳定版)
  • 替换原有main.dart代码,注意旧版的WebView默认构造方法已被官方废弃,改用新版控制器写法,页面加载控制更稳定:
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
import 'package:connectivity_plus/connectivity_plus.dart';
import 'dart:async';

void main() {
  runApp(
    const MaterialApp(
      debugShowCheckedModeBanner: false,
      home: WebViewApp(),
    ),
  );
}

class WebViewApp extends StatefulWidget {
  const WebViewApp({Key? key}) : super(key: key);

  @override
  State<WebViewApp> createState() => _WebViewAppState();
}

class _WebViewAppState extends State<WebViewApp> {
  late final WebViewController _webController;
  // 存储断网前的访问地址,初始值填写项目默认加载页
  String _lastUrl = 'https://google.com';
  bool _isOffline = false;
  late StreamSubscription<ConnectivityResult> _netSubscription;

  @override
  void initState() {
    super.initState();
    // 初始化WebView控制器
    _webController = WebViewController()
      ..setJavaScriptMode(JavaScriptMode.unrestricted)
      ..setNavigationDelegate(
        NavigationDelegate(
          onPageFinished: (url) {
            // 仅联网状态下更新记录的URL,避免存入离线错误页地址
            if (!_isOffline) _lastUrl = url;
          },
        ),
      )
      ..loadRequest(Uri.parse(_lastUrl));

    // 注册网络状态监听
    _netSubscription = Connectivity().onConnectivityChanged.listen((res) {
      final connected = res != ConnectivityResult.none;
      setState(() => _isOffline = !connected);
      // 网络恢复后自动加载之前停留的页面
      if (connected) _webController.loadRequest(Uri.parse(_lastUrl));
    });

    // 冷启动时主动做一次网络检测,避免刚打开应用就是断网状态、直接加载WebView报错
    Connectivity().checkConnectivity().then((res) {
      setState(() => _isOffline = res == ConnectivityResult.none);
    });
  }

  @override
  void dispose() {
    // 页面销毁时取消监听,防止内存泄漏
    _netSubscription.cancel();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Colors.white,
        elevation: 0,
        toolbarHeight: 0,
      ),
      body: _isOffline ? _buildOfflineWidget() : WebViewWidget(controller: _webController),
    );
  }

  // 离线提示组件
  Widget _buildOfflineWidget() {
    return Center(
      child: Padding(
        padding: const EdgeInsets.symmetric(horizontal: 40),
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            const Icon(Icons.wifi_off_rounded, size: 72, color: Colors.black45),
            const SizedBox(height: 24),
            const Text(
              '网络连接断开',
              style: TextStyle(fontSize: 18, fontWeight: FontWeight.w500),
            ),
            const SizedBox(height: 12),
            const Text(
              '请检查设备网络设置后重试',
              style: TextStyle(fontSize: 14, color: Colors.black54),
              textAlign: TextAlign.center,
            ),
            const SizedBox(height: 32),
            SizedBox(
              width: double.infinity,
              height: 44,
              child: ElevatedButton(
                onPressed: () async {
                  final netState = await Connectivity().checkConnectivity();
                  if (netState != ConnectivityResult.none) {
                    setState(() => _isOffline = false);
                    _webController.loadRequest(Uri.parse(_lastUrl));
                  }
                },
                child: const Text('重试'),
              ),
            )
          ],
        ),
      ),
    );
  }
}

踩坑提醒

  • 不要在页面跳转过程中记录URL,必须放在onPageFinished回调里存储,否则会把重定向的中间地址记下来,网络恢复时跳错页
  • Android端记得在AndroidManifest.xml里加网络状态权限声明,否则网络检测会失效:<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
  • iOS端在Info.plist里补全网络相关配置,避免真机运行报错
  • 不要用定时轮询的方式检测网络,耗电且状态更新不及时,直接用connectivity_plus的流监听即可,状态变化由系统实时触发

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 06:45:41