Why
Flutter官网推荐使用http插件进行网络请求。抓包是开发、测试的有效排查网络异常的手段,但是,http插件的网络请求是不走系统代理的。也就是在不进行代码配置的情况下是无法使用抓包工具进行抓包的。
既然网络不走系统代理,那么能不能获取系统代理的host和port,在Flutter端自动设置?http_proxy插件就是为了解决这个问题。
How
引入插件
在项目的pubspec.yaml添加:
dependencies:
http_proxy: ^1.1.0
代理配置
在main()函数里初始化代理配置
void main() async {
WidgetsFlutterBinding.ensureInitialized();
HttpProxy httpProxy = await HttpProxy.createHttpProxy();
HttpOverrides.global=httpProxy;
runApp(MyApp());
}
这就是Flutter端的所有代码了,然后设置系统代理的host和port就可以使用Charles等抓包工具抓包了。
More
http_proxy是如何工作的呢?下面将会对实现过程做详细介绍。
时机
第一个问题,网络请求是在什么时候进行代理配置?流程如图:
可以发现在HttpClient的findProxyFromEnvironment方法返回代理连接。
static String findProxyFromEnvironment(Uri url,
{Map<String, String>? environment}) {
HttpOverrides? overrides = HttpOverrides.current;
if (overrides == null) {
return _HttpClient._findProxyFromEnvironment(url, environment);
}
return overrides.findProxyFromEnvironment(url, environment);
}
在上面方法中HttpOverrides类负责获取代理配置。因此,只要给http设置一个全局HttpOverrides就可以获取代理配置了。
继承HttpOverrides,重写findProxyFromEnvironment(Uri url, Map<String, String> environment)方法,默认environment是null,这里给environment设置代理host和port。最后调用super方法返回代理连接。
@override
String findProxyFromEnvironment(Uri url, Map<String, String> environment) {
if (host == null) {
return super.findProxyFromEnvironment(url, environment);
}
if (environment == null) {
environment = {};
}
if (port != null) {
environment['http_proxy'] = '$host:$port';
environment['https_proxy'] = '$host:$port';
} else {
environment['http_proxy'] = '$host:8888';
environment['https_proxy'] = '$host:8888';
}
return super.findProxyFromEnvironment(url, environment);
}
$host
和$port
是获取的系统代理host和port。后面再讲如何获取这两个值。
获取系统代理
Flutter端与原生交互是通过MethodChannel,所以通过MethodChannel获取系统代理配置。
MethodChannel _channel = MethodChannel('com.lm.http.proxy');
Future<String> _getProxyHost() async {
return await _channel.invokeMethod('getProxyHost');
}
Future<String> _getProxyPort() async {
return await _channel.invokeMethod('getProxyPort');
}
class HttpProxy extends HttpOverrides {
String host;
String port;
HttpProxy._(this.host, this.port);
static Future<HttpProxy> createHttpProxy() async {
return HttpProxy._(await _getProxyHost(), await _getProxyPort());
}
}
提供系统代理
相应的原生部分需要使用MethodChannel提供系统当前代理host和port
Android端
- 初始化MethodChannel
@Override
public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) {
channel = new MethodChannel(flutterPluginBinding.getFlutterEngine().getDartExecutor(), "com.lm.http.proxy");
channel.setMethodCallHandler(this);
}
@Override
public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) {
switch (call.method) {
case "getProxyHost":
result.success(getProxyHost());
break;
case "getProxyPort":
result.success(getProxyPort());
break;
}
}
- 获取系统代理
private static String getProxyHost() {
return System.getProperty("http.proxyHost");
}
private static String getProxyPort() {
return System.getProperty("http.proxyPort");
}
IOS端
- 初始化MethodChannel
+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
FlutterMethodChannel* channel = [FlutterMethodChannel
methodChannelWithName:@"com.lm.http.proxy"
binaryMessenger:[registrar messenger]];
HttpProxyPlugin* instance = [[HttpProxyPlugin alloc] init];
[registrar addMethodCallDelegate:instance channel:channel];
}
- 获取系统代理
- (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result {
if ([@"getProxyHost" isEqualToString:call.method]) {
CFDictionaryRef proxySettings = CFNetworkCopySystemProxySettings();
NSDictionary *dictProxy = (__bridge_transfer id)proxySettings;
//是否开启了http代理
if ([[dictProxy objectForKey:@"HTTPEnable"] boolValue]) {
NSString *proxyHost = [dictProxy objectForKey:@"HTTPProxy"];
result(proxyHost);
}else{
result(nil);
}
} else if ([@"getProxyPort" isEqualToString:call.method]) {
CFDictionaryRef proxySettings = CFNetworkCopySystemProxySettings();
NSDictionary *dictProxy = (__bridge_transfer id)proxySettings;
//是否开启了http代理
if ([[dictProxy objectForKey:@"HTTPEnable"] boolValue]) {
NSString *proxyPort = [NSString stringWithFormat: @"%ld", [[dictProxy objectForKey:@"HTTPPort"] integerValue]];
result(proxyPort);
}else{
result(nil);
}
}else{
result(FlutterMethodNotImplemented);
}
}
Repository
Communication
如果对Flutter感兴趣,来Flutter泡泡群冒个泡吧!
QQ: 905105199