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
相关产品推荐
相关产品推荐

