一、前言
最近在写一个APP,目前已经写差不多了,需要用到防抓包检测,研究了一下捣鼓出来了,期间踩了很多坑,特此记录一下,大佬勿喷。
二、方法步骤
1.因为代理检测需要用到原生方法,所以需要用到kotlin,找到以下路径,新增一个文件 NetworkProxyPlugin.kt
D:\Flutter\demo_1\android\app\src\main\kotlin\com\example\demo_1
2.文件完整内容如下
package com.example.demo_1
import android.content.Context
import android.net.Proxy
import android.os.Build
import androidx.annotation.NonNull
import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
import io.flutter.plugin.common.MethodChannel.Result
import java.lang.reflect.Method
class NetworkProxyPlugin: FlutterPlugin, MethodCallHandler {
private lateinit var channel : MethodChannel
private lateinit var context: Context
override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
channel = MethodChannel(flutterPluginBinding.binaryMessenger, "network_proxy")
channel.setMethodCallHandler(this)
context = flutterPluginBinding.applicationContext
// 注册系统属性通道
val systemPropertiesChannel = MethodChannel(flutterPluginBinding.binaryMessenger, "system_properties")
systemPropertiesChannel.setMethodCallHandler { call, result ->
if (call.method == "getProperty") {
val propertyName = call.argument<String>("name") ?: ""
result.success(getSystemProperty(propertyName))
} else {
result.notImplemented()
}
}
}
override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) {
if (call.method == "getProxy") {
result.success(getProxySettings())
} else {
result.notImplemented()
}
}
@Suppress("DEPRECATION")
private fun getProxySettings(): String {
return try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
// 使用反射调用 ProxyInfo.getDefaultProxy() 方法
val proxyInfo = getDefaultProxyUsingReflection()
if (proxyInfo != null) {
val host = getProxyHost(proxyInfo)
val port = getProxyPort(proxyInfo)
if (host != null && port != null) {
"$host:$port"
} else {
"DIRECT"
}
} else {
"DIRECT"
}
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
// Android 4.0 - 9 使用 System.getProperty
val host = System.getProperty("http.proxyHost") ?: ""
val port = System.getProperty("http.proxyPort") ?: ""
if (host.isNotEmpty() && port.isNotEmpty()) {
"$host:$port"
} else {
"DIRECT"
}
} else {
// Android 4.0 以下使用旧的 android.net.Proxy 类
val host = Proxy.getHost(context) ?: ""
val port = Proxy.getPort(context)
if (host.isNotEmpty() && port != -1) {
"$host:$port"
} else {
"DIRECT"
}
}
} catch (e: Exception) {
"DIRECT"
}
}
// 使用反射调用 ProxyInfo.getDefaultProxy()
private fun getDefaultProxyUsingReflection(): Any? {
return try {
val proxyInfoClass = Class.forName("android.net.ProxyInfo")
val getDefaultProxyMethod: Method = proxyInfoClass.getMethod("getDefaultProxy")
getDefaultProxyMethod.invoke(null)
} catch (e: Exception) {
null
}
}
// 使用反射获取代理主机名
private fun getProxyHost(proxyInfo: Any): String? {
return try {
val getHostMethod: Method = proxyInfo.javaClass.getMethod("getHost")
getHostMethod.invoke(proxyInfo) as String?
} catch (e: Exception) {
null
}
}
// 使用反射获取代理端口
private fun getProxyPort(proxyInfo: Any): Int? {
return try {
val getPortMethod: Method = proxyInfo.javaClass.getMethod("getPort")
getPortMethod.invoke(proxyInfo) as Int?
} catch (e: Exception) {
null
}
}
private fun getSystemProperty(propertyName: String): String? {
return try {
System.getProperty(propertyName)
} catch (e: Exception) {
null
}
}
override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) {
channel.setMethodCallHandler(null)
}
}
3.配置MainActivity.kt内容
package com.example.demo_1
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
class MainActivity : FlutterActivity() {
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
// 注册网络代理插件
flutterEngine.plugins.add(NetworkProxyPlugin())
}
}
4.需要引入一个插件 在 pubspec.yaml 中引入 connectivity_plus: ^6.1.4
5.完整例子以及代码展示
import 'dart:io';
import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class NetworkUtils {
// 检测是否使用WiFi代理
static Future<bool> isWifiProxy() async {
var connectivityResult = await (Connectivity().checkConnectivity());
// 确保设备连接到WiFi
/*if (connectivityResult != ConnectivityResult.wifi) {
return false;
}*/
try {
if (Platform.isAndroid) {
return await _checkAndroidProxy();
}
return false;
} catch (e) {
print('检测WiFi代理时出错: $e');
return false;
}
}
// 检测Android代理
static Future<bool> _checkAndroidProxy() async {
print("_checkAndroidProxy");
try {
// 尝试通过MethodChannel获取代理设置
const platform = MethodChannel('network_proxy');
final proxy = await platform.invokeMethod('getProxy');
return proxy.isNotEmpty && proxy != 'DIRECT';
} catch (e) {
print('通过MethodChannel获取代理失败,尝试其他方法: $e');
// 备选方案:尝试通过系统属性获取
try {
final String? javaClass = 'android.net.Proxy';
final String? host = await _getSystemProperty('http.proxyHost');
final String? port = await _getSystemProperty('http.proxyPort');
if (host != null &&
host.isNotEmpty &&
port != null &&
port.isNotEmpty) {
print('检测到代理: $host:$port');
return true;
}
return false;
} catch (e) {
print('通过系统属性获取代理失败: $e');
// 最后手段:检查环境变量
final httpProxy = Platform.environment['http_proxy'] ?? '';
final httpsProxy = Platform.environment['https_proxy'] ?? '';
return httpProxy.isNotEmpty || httpsProxy.isNotEmpty;
}
}
}
// 通过MethodChannel获取系统属性
static Future<String?> _getSystemProperty(String propertyName) async {
try {
const platform = MethodChannel('system_properties');
return await platform.invokeMethod('getProperty', {'name': propertyName});
} catch (e) {
print('获取系统属性失败: $e');
return null;
}
}
// 检测是否正在使用VPN
static Future<bool> isVpnUsed() async {
try {
// 获取所有网络接口
final interfaces = await NetworkInterface.list(
includeLoopback: false,
type: InternetAddressType.any,
);
// 检查是否存在VPN接口
for (var interface in interfaces) {
if (interface.name.contains('tun') ||
interface.name.contains('ppp') ||
interface.name.contains('ipsec') ||
interface.name.contains('wg')) {
return true;
}
}
} catch (e) {
print('检测VPN时出错: $e');
}
return false;
}
}
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: '网络检测示例',
theme: ThemeData(primarySwatch: Colors.blue),
home: const NetworkDetectionScreen(),
);
}
}
class NetworkDetectionScreen extends StatefulWidget {
const NetworkDetectionScreen({Key? key}) : super(key: key);
@override
State<NetworkDetectionScreen> createState() => _NetworkDetectionScreenState();
}
class _NetworkDetectionScreenState extends State<NetworkDetectionScreen> {
bool _isProxyUsed = false;
bool _isVpnUsed = false;
String _statusMessage = '点击按钮开始检测';
bool _isChecking = false;
Future<void> _checkNetworkStatus() async {
setState(() {
_isChecking = true;
_statusMessage = '正在检测...';
});
try {
final isProxy = await NetworkUtils.isWifiProxy();
final isVpn = await NetworkUtils.isVpnUsed();
setState(() {
_isProxyUsed = isProxy;
_isVpnUsed = isVpn;
if (isProxy && isVpn) {
_statusMessage = '检测到同时使用WiFi代理和VPN';
} else if (isProxy) {
_statusMessage = '检测到使用WiFi代理';
} else if (isVpn) {
_statusMessage = '检测到使用VPN';
} else {
_statusMessage = '未检测到代理或VPN';
}
});
} catch (e) {
setState(() {
_statusMessage = '检测过程中出错: $e';
});
} finally {
setState(() {
_isChecking = false;
});
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('网络状态检测')),
body: Center(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text(
'网络连接检测',
style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
),
const SizedBox(height: 20),
Card(
elevation: 4,
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ListTile(
leading: Icon(
_isProxyUsed ? Icons.warning : Icons.check_circle,
color: _isProxyUsed ? Colors.red : Colors.green,
),
title: const Text('WiFi代理状态'),
subtitle: Text(_isProxyUsed ? '正在使用代理' : '未使用代理'),
),
const Divider(),
ListTile(
leading: Icon(
_isVpnUsed ? Icons.warning : Icons.check_circle,
color: _isVpnUsed ? Colors.red : Colors.green,
),
title: const Text('VPN状态'),
subtitle: Text(_isVpnUsed ? '正在使用VPN' : '未使用VPN'),
),
],
),
),
),
const SizedBox(height: 20),
Text(
_statusMessage,
style: TextStyle(
fontSize: 16,
color: _isProxyUsed || _isVpnUsed ? Colors.red : Colors.black,
),
textAlign: TextAlign.center,
),
const SizedBox(height: 30),
ElevatedButton(
onPressed: _isChecking ? null : _checkNetworkStatus,
child:
_isChecking
? const Row(
mainAxisSize: MainAxisSize.min,
children: [
CircularProgressIndicator(color: Colors.white),
SizedBox(width: 10),
Text('检测中...'),
],
)
: const Text('检测网络状态'),
),
],
),
),
),
);
}
}
6.成品效果展示


三、结言
本文旨在记录,若有不当之处,还请指正。