Flutter通过--dart-define加载环境变量的踩坑经验

46 阅读1分钟

踩坑背景

为什么弃用flutter_dotenv

flutter_dotenv是一个在flutter下可以直接引用键值对格式.env文件的插件。对于写惯了KEY=VALUE格式环境变量的后端码农来说,很方便。

但是flutter_dotenv也有个致命缺点,就是flutter需要将.env文件作为资源打包,才能实现代码对.env的读取。那么如果你的.env中存放了API_BASE_URL或者JWT_SECRET_KEY之类敏感变量的话,ipa文件通过逆向,就有可能获取到你的敏感变量,非常危险!

回归--dart-define,但是新的坑来了

flutter原生加载环境变量的方法就是通过

  • --dart-define=KEY=VALUE, 或者
  • --dart-define-from-file=.env/dev.json

其中.env文件夹下的dev.json可以是如下格式:

{
  "API_BASE_URL": "localhost:8000"
}

但是我发现通过这种方式跑flutter run --dart-define..., 环境变量怎么都不生效

问题原因

我是通过一个统一的env_config.dart文件,其中所有变量,延用了之前dotenv的写法,用的getter来获取环境变量:

class EnvConfig {
    static String get apiBaseUrl => String.fromEnvironment("API_BASE_URL", defaultValue="localhost:8000")
}

这个getter写法就是问题的根源:

  1. ❌ 使用 getter + String.fromEnvironment():在运行时执行,无法访问编译时定义的值
  2. ✅ 使用 const 字段 + String.fromEnvironment():在编译时求值,正确获取 --dart-define 传入的值

核心原则:

  • String.fromEnvironment()在编译阶段可以获取,打包完成后就被清除,因此在代码运行时以及获取不到了,所以String.fromEnvironment()必须是 const 字段,不能是 getter
  • String.fromEnvironment() / int.fromEnvironment() / bool.fromEnvironment() 以此类推

问题解决

修改env_config.dart:

class EnvConfig {
    static const String apiBaseUrl = String.fromEnvironment("API_BASE_URL", defaultValue="localhost:8000")
}

问题解决,撒花!