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

Flutter如何实现WebView加载前带网络检测及Snackbar提示的启动页

Flutter 集成WebView应用启动页前置网络检测实现方案

1. 引入所需依赖

在项目根目录的pubspec.yaml中添加功能所需依赖:

dependencies:
  flutter:
    sdk: flutter
  webview_flutter: ^4.4.2 # 官方维护的WebView组件
  connectivity_plus: ^5.0.2 # 跨平台网络状态检测组件

保存后执行flutter pub get完成依赖安装。

2. 配置平台必要权限

  • Android端:在android/app/src/main/AndroidManifest.xml的<manifest>标签下添加权限声明:
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
  • iOS端:在ios/Runner/Info.plist中添加网络访问配置:
<key>NSAppTransportSecurity</key>
<dict>
  <key>NSAllowsArbitraryLoads</key>
  <true/>
</dict>

3. 编写启动页逻辑

将启动页设为应用初始路由,页面初始化时自动触发网络检测:无网络则弹出常驻SnackBar提示用户重试,检测到可用网络后自动跳转至WebView页面。

import 'package:flutter/material.dart';
import 'package:connectivity_plus/connectivity_plus.dart';
import 'webview_page.dart';

class SplashPage extends StatefulWidget {
  const SplashPage({super.key});

  @override
  State<SplashPage> createState() => _SplashPageState();
}

class _SplashPageState extends State<SplashPage> {
  final Connectivity _connectivity = Connectivity();

  @override
  void initState() {
    super.initState();
    // 首帧渲染完成后触发网络检测
    WidgetsBinding.instance.addPostFrameCallback((_) {
      _checkNetworkAndNavigate();
    });
  }

  Future<void> _checkNetworkAndNavigate() async {
    // 获取当前网络连接状态
    final connectivityResult = await _connectivity.checkConnectivity();
    
    // 判定为无网络时弹出提示
    if (connectivityResult.contains(ConnectivityResult.none)) {
      if (mounted) {
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(
            content: const Text('当前无可用网络,请检查网络设置后重试'),
            duration: const Duration(days: 365), // 常驻不自动消失
            action: SnackBarAction(
              label: '重试',
              onPressed: () {
                ScaffoldMessenger.of(context).hideCurrentSnackBar();
                _checkNetworkAndNavigate();
              },
            ),
          ),
        );
      }
      return;
    }

    // 可选:延迟1秒展示启动页品牌元素,可根据需求调整时长或删除
    await Future.delayed(const Duration(seconds: 1));
    if (mounted) {
      // 替换路由进入WebView页面,禁止返回启动页
      Navigator.of(context).pushReplacement(
        MaterialPageRoute(builder: (context) => const WebViewPage()),
      );
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.white,
      body: Center(
        // 替换为自身业务的启动页Logo、slogan等元素
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            const FlutterLogo(size: 120),
            const SizedBox(height: 24),
            const Text('应用加载中', style: TextStyle(fontSize: 16, color: Colors.grey)),
          ],
        ),
      ),
    );
  }
}

4. 编写WebView页面

import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';

class WebViewPage extends StatefulWidget {
  const WebViewPage({super.key});

  @override
  State<WebViewPage> createState() => _WebViewPageState();
}

class _WebViewPageState extends State<WebViewPage> {
  late final WebViewController _webController;
  bool _pageLoading = true;

  @override
  void initState() {
    super.initState();
    _webController = WebViewController()
      ..setJavaScriptMode(JavaScriptMode.unrestricted) // 按需开启JS权限
      ..setNavigationDelegate(
        NavigationDelegate(
          onPageStarted: (url) {
            setState(() => _pageLoading = true);
          },
          onPageFinished: (url) {
            setState(() => _pageLoading = false);
          },
        ),
      )
      ..loadRequest(Uri.parse('替换为实际需要加载的Web页面地址'));
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Stack(
        children: [
          WebViewWidget(controller: _webController),
          if (_pageLoading)
            const Center(
              child: CircularProgressIndicator(),
            ),
        ],
      ),
    );
  }
}

实现注意事项

  • 基础网络检测的局限性:connectivity_plus仅能判断设备是否连接到WiFi/蜂窝网络,无法验证是否能正常访问外网。如果需要更严谨的判断,可以在检测到网络连接后,发起一次轻量的HTTP请求验证连通性,确认正常后再跳转。
  • Context安全校验:所有涉及页面跳转、SnackBar弹出的操作,必须先判断mounted属性为true再执行,避免异步检测过程中页面销毁导致的上下文异常。
  • SnackBar展示逻辑:无网络时SnackBar设置为常驻状态,避免提示自动消失导致用户无感知,用户点击重试按钮后再触发新一轮网络检测。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 09:54:21