flutter工程化之动态配置

动机

很多公司在实际开发中都有不少动态化配置的需求,比如说要根据不同app渠道加载不同的URL、secrets等配置项。这其中的实现方法也有很多,今天的应用案例则是--dart-define--dart-define-from-file

目标

  • 一处配置多处使用
  • 尽量少用第三方库
  • 非入侵

用法

--dart-define

使用方法简单粗暴,直接把如下的命令添加上就好,无论是flutter build还是flutter build都可以:

shell 复制代码
 --dart-define API_URL=api.openflutter.dev

如果有需要添加多个变量也是可以的:

shell 复制代码
 --dart-define API_URL=api.openflutter.dev  --dart-define MAP_KEY=ds5jkh2jjhjkljh

如果我有大量的变量怎么办?

--dart-define-from-file

我们也可以从文件中加载配置文件,文件格式可以是json也可以是.env:

erlang 复制代码
--dart-define-from-file path/to/config.json
--dart-define-from-file path/to/.env

Flutter端获取变量

很简单:

dart 复制代码
final url = const String.fromEnvironment("API_URL");
final logEnabled = const bool.fromEnvironment("LOG_ENABLED");
final level = const bool.fromEnvironment("LEVEL");

补充一句:

千万别忘了写const

如果你使用的.env文件做为配置项,你也可以使用一个代码叫envied的代码生成工具,以简化相关操作。

但很多时候仅仅在Flutter端获取这些配置是不够的,我们也会需要在Android侧和iOS侧获取相关配置。

Android 端

找到app/build.gradle.kts,旧的Flutter应该是app/build.gradle,然后添加一些代码:

kotlin 复制代码
val dartDefines = mutableMapOf<String, String>()

if (project.hasProperty("dart-defines")) {
    project.property("dart-defines").toString().split(",").forEach { entry ->
        val decoded = String(Base64.getDecoder().decode(entry), Charsets.UTF_8)
        val pair = decoded.split("=")
        if (pair.size == 2) {
            dartDefines[pair[0]] = pair[1]
        }
    }
}


defaultConfig {
    applicationId = "com.example.flutter_dash_testing"
    minSdk = flutter.minSdkVersion
    targetSdk = flutter.targetSdkVersion
    versionCode = flutter.versionCode
    versionName = flutter.versionName
    dartDefines["API_URL"]?.let {
        resValue("string", "api_url", it)
    }
}

iOS侧

当我们用 Flutter 编译 iOS 端时,会在./ios/Flutter目录下生成两个文件Generated.xcconfigflutter_export_environment.sh。 在这两个文件中我们都会过来的dart-define:

shell 复制代码
// flutter_export_environment.sh
export "DART_DEFINES=S0VZPWtleSBpcyB0ZXN0aW5n,QVBJX1VSTD1odHRwczovL2FwaS5leGFtcGxlLmNvbQ==,QVBQX05BTUU9SGVsbG8gV29ybGQ=,RkxVVFRFUl9BUFBfRkxBVk9SPXN0YWdpbmc="
ini 复制代码
// Generated.xcconfig
DART_DEFINES=S0VZPWtleSBpcyB0ZXN0aW5n,QVBJX1VSTD1odHRwczovL2FwaS5leGFtcGxlLmNvbQ==,QVBQX05BTUU9SGVsbG8gV29ybGQ=,RkxVVFRFUl9BUFBfRkxBVk9SPXN0YWdpbmc=

首先我们需要把这些经过base64编码过的变量解析到某个.xcconfig中,然后再把该文件在Release.xcconfigDebug.xcconfig引入,假设它的名字是GeneratedDartDefines.xcconfig:

arduino 复制代码
// ./ios/Flutter/Debug.xcconfig

#include "Generated.xcconfig"
#include "GeneratedDartDefines.xcconfig"
arduino 复制代码
// ./ios/Flutter/Release.xcconfig

#include "Generated.xcconfig"
#include "GeneratedDartDefines.xcconfig"

假设我们要生成的文件名字为GeneratedDartDefines.xcconfig。首先我们在./ios/Flutter目录下生成一个空的GeneratedDartDefines.xcconfig。然后打开Xcode,在Targets=>Runner=>Build Phases选项卡中点击+号,选择New Run Script Phase并把如下代码复制进去:

sh 复制代码
DART_DEFINES=$(cat "${SRCROOT}/Flutter/Generated.xcconfig" | grep "DART_DEFINES" | sed -E 's/DART_DEFINES=(.+)/\1/')

IFS=',' read -ra DEFINES <<< "$DART_DEFINES"
ALL_DECODED=""

for DEFINE in "${DEFINES[@]}"; do
    # Decode Base64
    DECODED=$(echo "$DEFINE" | base64 --decode)
    echo "DECODED $DECODED"
    # Skip Flutter internal variables
    if [[ "$DECODED" != FLUTTER_* ]]; then
        if [ -z "$ALL_DECODED" ]; then
            ALL_DECODED="$DECODED"
        else
            # Use proper newline insertion
            ALL_DECODED="${ALL_DECODED}"$'\n'"${DECODED}"
        fi
    fi
done

echo "$ALL_DECODED" > "${SRCROOT}/Flutter/GeneratedDartDefines.xcconfig"

最后,按需修改下Info.plist即可,如修改app名字:

c 复制代码
// ./ios/Runner/Info.plist
// ...
<key>CFBundleName</key>
<string>$(APP_NAME)</string>
// ...

开发具怎么配置

Android Studio

在绿色的运行按钮左侧有个下拉框,然后点击Edit Configurations ,其中有一个项目叫做Addtional run args,把--dart-define-from-file .env类似的参数添加进去就好了。当然你也可以选择保存配置,这样大家就可以共享这个快捷键了。

VSCode

改改launch.json

json 复制代码
{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Flutter Dev",
      "request": "launch",
      "type": "dart",
      "flutterMode": "debug",
      "args": [
        "--dart-define=API_URL=https://api.dev.example.com",
        "--dart-define=APP_ENVIRONMENT=development",
        "--flavor=dev"
      ]
    },
    {
      "name": "Flutter Staging",
      "request": "launch",
      "type": "dart",
      "flutterMode": "debug",
      "args": [
        "--dart-define-from-file=.env",
        "--flavor=staging"
      ]
    }
  ]
}
相关推荐
肥肥呀呀呀2 小时前
flutter 的热更新方案shorebird
flutter
鸿蒙布道师3 小时前
鸿蒙NEXT开发动画案例3
android·ios·华为·harmonyos·鸿蒙系统·arkui·huawei
鸿蒙布道师3 小时前
AI原生手机:三大技术阵营的终极对决与未来展望
android·人工智能·ios·华为·智能手机·ai-native·hauwei
每次的天空3 小时前
移动应用开发:自定义 View 处理大量数据的性能与交互优化方案
android·java·学习·交互
Huang兄4 小时前
Android 项目中配置了多个 maven 仓库,但依赖还是下载失败,除了使用代理,还有其他方法吗?
android·gradle·maven
Echo-潔5 小时前
iOS创建Certificate证书、制作p12证书流程
ios·ios 生成app打包证书
snail2012115 小时前
Flutter接入ProtoBuff和原生Android通信【性能最优】
android·flutter
難釋懷6 小时前
Android开发-常用布局
android·gitee
程序猿阿伟6 小时前
《让歌声跨越山海:Flutter借助Agora SDK实现高质量连麦合唱》
flutter
墨菲斯托8886 小时前
fakebook
android