Flutter 100问:http怎样自动获取代理配置

本文介绍了在Flutter中,如何使用http_proxy插件自动获取并应用系统代理设置,以便进行网络请求时能配合抓包工具如Charles进行网络数据抓取。内容包括插件引入、代理配置、工作原理、获取系统代理的时机以及Android和iOS端的原生实现方法。
部署运行你感兴趣的模型镜像

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端
  1. 初始化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;
    }
}
  1. 获取系统代理
private static String getProxyHost() {
    return System.getProperty("http.proxyHost");
}

private static String getProxyPort() {
    return System.getProperty("http.proxyPort");
}
IOS端
  1. 初始化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];
}
  1. 获取系统代理
- (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

https://github.com/wslaimin/http_proxy

Communication

如果对Flutter感兴趣,来Flutter泡泡群冒个泡吧!

QQ: 905105199

您可能感兴趣的与本文相关的镜像

Stable-Diffusion-3.5

Stable-Diffusion-3.5

图片生成
Stable-Diffusion

Stable Diffusion 3.5 (SD 3.5) 是由 Stability AI 推出的新一代文本到图像生成模型,相比 3.0 版本,它提升了图像质量、运行速度和硬件效率

<think>我们正在处理用户的题:“Flutter doctor Error: Unable to determine engine version solution” 根据引用[1][2][3],用户之前遇到了“Unable to find git in your PATH”的错误,但当前题变成了“Unable to determine engine version”。 然而,引用中并没有直接提到“Unable to determine engine version”的错误。因此,我们需要根据Flutter的常见题来推测解决方案。 常见原因: 1. Flutter SDK损坏或不完整。 2. 网络题导致无法下载引擎版本信息。 3. 环境变量配置题(如git题,但用户已经解决git题)。 4. 缓存题。 解决方案: 步骤1:检查网络连接,确保可以访flutter服务器(如storage.googleapis.com)。 步骤2:运行`flutter doctor -v`获取详细日志。 步骤3:尝试清除或重置Flutter环境: - `flutter clean` - `flutter upgrade` (升级Flutter到最新版本) 步骤4:如果升级失败,可以尝试重新安装Flutter SDK。 但是,根据引用[3]中提到的git安全目录题,我们注意到git对Flutter目录的访权限也很重要。因此,我们也可以尝试将Flutter目录添加到git的安全目录中(尽管该题原本是解决git不在PATH的题,但可能权限题也会影响引擎版本的获取)。 具体步骤: 1. 打开终端(或命令提示符)。 2. 运行以下命令,将Flutter SDK目录添加到git的安全目录(注意替换路径为你的Flutter SDK实际路径): ``` git config --global --add safe.directory <你的Flutter SDK路径> ``` 例如: ``` git config --global --add safe.directory C:/src/flutter ``` 3. 然后再次运行`flutter doctor`。 如果以上步骤不能解决,可以尝试以下步骤: 步骤5:检查Flutter SDK目录的权限,确保当前用户有读写权限。 步骤6:检查Flutter的缓存和临时文件,可以尝试删除`<Flutter SDK目录>/bin/cache`目录,然后运行`flutter doctor`重新生成缓存。 注意:删除缓存目录是安全的,因为`flutter`命令会自动重新下载必要的文件。 步骤7:如果题仍然存在,考虑重新克隆Flutter仓库: ``` git clone https://github.com/flutter/flutter.git -b stable ``` 然后更新环境变量PATH指向新的Flutter SDK目录。 由于用户之前已经解决了git不在PATH的题,所以现在的题可能是由于Flutter缓存损坏或权限题导致无法确定引擎版本。 我们按照上述步骤给出解决方案。 注意:由于用户的环境可能不同(Windows/Mac/Linux),需要适当调整路径格式。 如果用户是在Windows上,使用PowerShell,那么命令可能是: ``` git config --global --add safe.directory "C:\src\flutter" ``` 在Mac/Linux上: ``` git config --global --add safe.directory "/path/to/flutter" ``` 最后,如果用户遇到模拟器无法启动的题(如引用[4]),但当前题是关于引擎版本的,所以先解决引擎版本题。 生成相关题: 1. 如何检查Flutter SDK是否完整? 2. 如何清除Flutter的缓存? 3. 如何重新安装Flutter SDK? 4. 为什么需要将Flutter目录添加到git的安全目录? 5. 运行`flutter doctor -v`后如何分析日志?</think>### Flutter doctor 报错:Unable to determine engine version 解决方案 当执行 `flutter doctor` 出现 **"Unable to determine engine version"** 错误时,通常是由于 Flutter SDK 完整性受损或环境配置题导致引擎版本检测失败。以下是逐步解决方案: --- ### **1. 验证 Flutter SDK 完整性** 首先检查 SDK 是否完整: ```bash flutter doctor -v ``` 观察输出中是否包含 `Bad state: Unable to find git in your PATH` 或文件缺失提示。若存在: - **重新克隆 Flutter SDK**(保留现有配置): ```bash cd <原Flutter目录> git clean -xfd git stash git pull flutter doctor ``` --- ### **2. 修复 Git 安全目录配置** Flutter 依赖 Git 获取引擎版本,需确保 SDK 目录被 Git 信任: ```bash git config --global --add safe.directory <你的Flutter SDK绝对路径> ``` 例如: ```bash git config --global --add safe.directory C:/src/flutter ``` --- ### **3. 清除缓存并强制刷新** 删除缓存文件强制重建: ```bash rm -rf <Flutter目录>/bin/cache flutter doctor -v ``` 此时 Flutter自动下载所需依赖。 --- ### **4. 检查网络和代理** 确保可访 Google 服务(引擎信息从 `storage.googleapis.com` 获取): - 测试连接:`curl https://storage.googleapis.com` - 若有代理配置环境变量: ```bash export PUB_HOSTED_URL=https://pub.flutter-io.cn export FLUTTER_STORAGE_BASE_URL=https://storage.flutter-io.cn ``` --- ### **5. 验证环境变量** 确保 `PATH` 包含: - Flutter 的 `bin` 目录(如 `C:\src\flutter\bin`) - Git 的 `bin` 目录(如 `C:\Program Files\Git\bin`) --- ### **6. 重装 Flutter(最后手段)** 若上述步骤无效: 1. 备份 `flutter/.pub-cache` 目录 2. 删除旧 SDK 并重新安装 3. 恢复备份到新 SDK 目录 --- ### **常见原因总结** | 原因 | 解决方案 | |---------------------|----------------------------------| | SDK 文件损坏 | 重新克隆或清除缓存 | | Git 安全目录未配置 | `git config --add safe.directory` | | 网络阻塞 | 检查代理/镜像配置 | | PATH 缺失关键路径 | 添加 Flutter/Git 到环境变量 | > 引用案例:用户通过添加 Git 安全目录解决类似题[^3],网络题也可能导致版本检测失败[^1][^2]。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值