如何实现仅在指定静态IP下运行的Flutter应用并限制异IP联网?
需求可行性与实现方案
可行性结论
这个需求完全可行,核心逻辑是检测设备当前网络的IP地址,仅当与指定静态IP匹配时,才允许应用发起网络请求;不匹配时拦截所有请求并限制功能。
具体实现步骤
1. 获取设备当前网络IP地址
需根据需求区分局域网静态IP或公网静态IP,采用对应获取方式:
场景1:限制局域网静态IP
使用network_info_plus包获取设备本地局域网IP:
- 在
pubspec.yaml添加依赖:
dependencies: network_info_plus: ^4.0.1
- 编写IP获取方法:
import 'package:network_info_plus/network_info_plus.dart'; Future<String?> getCurrentLocalIp() async { final networkInfo = NetworkInfo(); // 获取WiFi连接下的局域网IP final wifiIp = await networkInfo.getWifiIP(); // 移动网络下的本地IP需通过原生API额外处理 return wifiIp; }
注意:iOS 13+获取WiFi IP需定位权限,需在
Info.plist添加NSLocationWhenInUseUsageDescription;Android需在AndroidManifest.xml添加ACCESS_WIFI_STATE权限。
场景2:限制公网静态IP
通过请求外部接口获取设备公网IP(如http://icanhazip.com),需在IP校验前发起请求:
import 'package:http/http.dart' as http; Future<String?> getCurrentPublicIp() async { try { final response = await http.get(Uri.parse("http://icanhazip.com")); if (response.statusCode == 200) { return response.body.trim(); } } catch (_) {} return null; }
2. 全局拦截网络请求
通过统一网络客户端拦截所有请求,仅允许IP匹配时发起请求,推荐使用dio拦截器方案:
- 添加
dio依赖:
dependencies: dio: ^5.3.2
- 自定义IP校验拦截器:
import 'package:dio/dio.dart'; class IpRestrictionInterceptor extends Interceptor { final String allowedIp; IpRestrictionInterceptor(this.allowedIp); @override void onRequest(RequestOptions options, RequestInterceptorHandler handler) async { // 根据需求选择获取本地IP或公网IP final currentIp = await getCurrentLocalIp(); if (currentIp == allowedIp) { // IP匹配,放行请求 handler.next(options); } else { // IP不匹配,拦截请求并返回错误 handler.reject(DioException( requestOptions: options, error: "当前网络IP不符合要求,无法访问互联网", type: DioExceptionType.cancel, )); } } }
- 初始化Dio时绑定拦截器:
final dio = Dio(); // 替换为你的指定静态IP dio.interceptors.add(IpRestrictionInterceptor("192.168.1.100"));
若使用原生http包,可封装自定义客户端:
import 'package:http/http.dart' as http; class IpRestrictedClient extends http.BaseClient { final http.Client _innerClient = http.Client(); final String allowedIp; IpRestrictedClient(this.allowedIp); @override Future<http.StreamedResponse> send(http.BaseRequest request) async { final currentIp = await getCurrentLocalIp(); if (currentIp == allowedIp) { return _innerClient.send(request); } else { throw Exception("当前网络IP不符合要求,无法访问互联网"); } } }
3. 应用启动与实时状态监听
- 启动时直接校验IP,不符合则显示限制页面:
import 'package:flutter/material.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); const allowedIp = "192.168.1.100"; final currentIp = await getCurrentLocalIp(); runApp(MaterialApp( home: currentIp == allowedIp ? const HomePage() : const RestrictedPage(), )); } class RestrictedPage extends StatelessWidget { const RestrictedPage({super.key}); @override Widget build(BuildContext context) { return Scaffold( body: Center( child: Text("当前网络环境不符合要求,无法使用应用"), ), ); } } class HomePage extends StatelessWidget { const HomePage({super.key}); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text("主页面")), body: const Center(child: Text("正常使用中")), ); } }
- 监听网络状态变化,实时更新IP校验状态:
使用connectivity_plus包监听网络切换,重新校验IP并更新界面:
dependencies: connectivity_plus: ^5.0.1
class HomePage extends StatefulWidget { const HomePage({super.key}); @override State<HomePage> createState() => _HomePageState(); } class _HomePageState extends State<HomePage> { late StreamSubscription<ConnectivityResult> _connectivitySubscription; const allowedIp = "192.168.1.100"; bool _isIpValid = true; @override void initState() { super.initState(); _connectivitySubscription = Connectivity().onConnectivityChanged.listen((result) async { final currentIp = await getCurrentLocalIp(); setState(() { _isIpValid = currentIp == allowedIp; }); }); } @override void dispose() { _connectivitySubscription.cancel(); super.dispose(); } @override Widget build(BuildContext context) { if (!_isIpValid) { return const RestrictedPage(); } return Scaffold( appBar: AppBar(title: const Text("主页面")), body: const Center(child: Text("正常使用中")), ); } }
4. 额外安全建议
- 双重校验:服务器端同步添加IP白名单校验,防止客户端被篡改绕过。
- 代码混淆:对Flutter代码进行混淆,提升逆向破解难度。
- 动态配置:通过远程配置中心动态获取允许的IP,避免频繁打包发布。
内容的提问来源于stack exchange,提问作者mohammad aslam ansari
相关产品推荐
相关产品推荐

