Flutter配置管理插件conf的使用

Flutter配置管理插件conf的使用

conf 是一个Dart包,用于定义配置模式并从多个来源加载配置值,例如:

  • 命令行参数
  • 环境变量
  • 从命令行参数或环境变量中的JSON字符串
  • JSON文件
  • YAML文件

这些来源以可配置的顺序覆盖彼此。

安装

pubspec.yaml 文件中添加 conf 作为依赖项:

dart pub add conf

示例

完整的示例可以在 这里 查看。

模式

在可以加载配置值之前,你需要定义一个模式。我建议将模式拆分成多个类,每个类包含相关的配置值。例如,如果你有一个需要连接到数据库的服务器,你可能会定义一个 DatabaseConfiguration 类,其中包含数据库URL、用户名和密码:

class DatabaseConfiguration {
  DatabaseConfiguration({
    required this.url,
    required this.username,
    required this.password,
  });

  factory DatabaseConfiguration._factory(Map<String, Object?> map) => 
      DatabaseConfiguration(
        url: map['url']! as Uri,
        username: map['username']! as String,
        password: map['password']! as String,
      );

  static final schema = ConfObject(
    propertiesMap: {
      'url': ConfUri(),
      'username': ConfString(),
      'password': ConfString(),
    },
    factory: DatabaseConfiguration._factory,
  );

  final Uri url;
  final String username;
  final String password;
}

注意 DatabaseConfiguration 类有一个 schema 字段,它定义了该类的配置模式。schema 字段是一个 ConfObject,它定义了该类的配置属性及其如何从属性值映射创建 DatabaseConfiguration 实例。

现在我们定义一个 ServerConfiguration 类,它包含 DatabaseConfiguration 以及监听的端口和地址:

class ServerConfiguration {
  ServerConfiguration({
    required this.port,
    required this.address,
    required this.database,
  });

  factory ServerConfiguration._factory(Map<String, Object?> map) =>
      ServerConfiguration(
        port: map['port']! as int,
        address: map['address']! as InternetAddress,
        database: map['database']! as DatabaseConfiguration,
      );

  static final schema = ConfObject(
    propertiesMap: {
      'port': ConfDefault(ConfInteger(), defaultValue: 8080),
      'address': ConfDefault(
        ConfInternetAddress(),
        defaultValue: InternetAddress.loopbackIPv4,
      ),
      'database': DatabaseConfiguration.schema,
    },
    factory: ServerConfiguration._factory,
  );

  final int port;
  final InternetAddress address;
  final DatabaseConfiguration database;
}

在这里我们使用 ConfDefault 类为 portaddress 属性定义默认值。我们还使用 DatabaseConfiguration.schema 字段来定义 database 属性。

标量值

conf 提供了许多内置的标量值模式类,用于加载标量值:

  • ConfBool
  • ConfNumber
  • ConfInteger
  • ConfDouble
  • ConfString
  • ConfDateTime
  • ConfUri
  • ConfInternetAddress
  • ConfEnum

你也可以通过扩展 ConfScalar 类或其子类来自定义标量值模式类。例如,这是 ConfInternetAddress 类的实现:

class ConfInternetAddress extends ParseConfScalar<InternetAddress> {
  ConfInternetAddress() : super('InternetAddress');

  @override
  InternetAddress parse(String value) {
    final address = InternetAddress.tryParse(value);
    if (address == null) {
      throw FormatException(
        'Expected an IPv4 or IPv6 address but got "$value".',
      );
    }
    return address;
  }
}

加载配置

要加载 ServerConfiguration,我们需要一个 ConfigurationSource,它提供配置值。为了简单起见,我们将直接在代码中提供配置值:

final source = CombiningSource([
  CommandLineSource(['--database.username=test']),
  EnvironmentSource({
    'PORT': '4567',
    'DATABASE_URL': 'postgres://localhost:5432/db',
    'DATABASE_USERNAME': 'dev',
    'DATABASE_PASSWORD': 'password',
  })
]);

try {
  final configuration = await ServerConfiguration.schema.load(source);
  // 对配置进行处理。
} on ConfigurationException catch (error) {
  stderr.writeln(error);
  exitCode = 1;
}

如果加载配置失败,load 将抛出 ConfigurationExceptionconf 不会在遇到第一个错误后停止。相反,它会收集所有错误并在 ConfigurationException.errors 中提供它们。这允许你一次性显示所有错误,而不是一次解决一个错误。

上述示例演示了 conf 的核心功能之一:能够从具有不同格式的多个来源加载配置值。

conf 会根据模式为每个配置值推断环境变量名称。例如,port 属性从 PORT 环境变量加载,而 database.url 属性从 DATABASE_URL 加载。

命令行格式化配置值略有不同。例如,database.username 属性从 --database.username 命令行参数加载。

因为我们首先指定了 CommandLineSource,所以 database.username 属性从命令行参数而不是环境变量加载。

配置源

ConfigurationSource 是配置值的低级表示形式,使加载配置值变得容易,来源包括:

  • CommandLineSource:从命令行参数加载配置值。
  • EnvironmentSource:从环境变量加载配置值。
  • DataSource:从JSON样式的数据结构加载配置值。通常用于从JSON和YAML文件加载配置值。
  • CombiningSource:将多个来源组合成一个来源。

应用程序源

AppSources 提供了一种简单的方法,以适合Dart应用程序(如服务器)的方式加载配置源。

AppSources 假设应用程序定义了一组配置文件。配置文件是一组命名的配置值。例如,服务器可能有一个 dev 配置文件用于开发,一个 prod 配置文件用于生产。多个配置文件可以同时激活,并由 Profiles 类表示。

enum Profile {
  dev,
  prod,
  test;

  /// 当前活动的配置文件。
  static Profiles<Profile> get active => Profiles.active as Profiles<Profile>;
}

你可以在 --profiles 命令行参数或 PROFILES 环境变量中指定活动的配置文件,以逗号分隔列表的形式。例如:

$ dart run server.dart --profiles="dev,test"

继续上一节中的示例,我们可以使用 AppSources.load 来加载一个 CombiningSource,它结合了命令行和环境源以及配置文件源,这些源位于已知位置。

class ServerConfiguration {

  // ...

  static Future<ServerConfiguration> load(
    List<String> arguments, {
    Set<Profile>? additionalProfiles,
  }) async {
    final sources = await AppSources.load(
      arguments: arguments,
      allProfiles: Profile.values,
      defaultProfiles: {Profile.dev},
      additionalProfiles: additionalProfiles,
    );
    return schema.load(sources);
  }

  // ...

}

更多关于Flutter配置管理插件conf的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter配置管理插件conf的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


在Flutter项目中,使用配置管理插件可以帮助我们更好地管理和维护应用的配置信息。conf 是一个流行的配置管理插件,它允许我们从外部文件(如 JSON 文件)中加载配置,并在整个应用中轻松访问这些配置。

以下是一个使用 conf 插件的示例代码案例,包括如何在 Flutter 项目中集成 conf 插件、加载配置以及访问配置。

1. 添加依赖

首先,在你的 pubspec.yaml 文件中添加 conf 插件的依赖:

dependencies:
  flutter:
    sdk: flutter
  conf: ^1.0.0  # 请确保使用最新版本,这里只是一个示例版本号

然后运行 flutter pub get 来获取依赖。

2. 配置 JSON 文件

assets 文件夹中创建一个名为 config.json 的文件,并添加一些配置信息:

{
  "api_url": "https://api.example.com",
  "theme": {
    "primary_color": "#FF5733",
    "font_size": 16
  }
}

别忘了在 pubspec.yaml 中声明 assets

flutter:
  assets:
    - assets/config.json

3. 初始化并加载配置

在你的 Flutter 应用的入口文件(通常是 main.dart)中,初始化并加载配置:

import 'package:flutter/material.dart';
import 'package:conf/conf.dart';
import 'dart:convert';
import 'package:flutter/services.dart' show rootBundle;

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  // 加载配置
  var configData = await rootBundle.loadString('assets/config.json');
  var jsonMap = jsonDecode(configData) as Map<String, dynamic>;

  // 初始化 Conf
  Conf.init(jsonMap);

  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Conf Demo',
      theme: ThemeData(
        primarySwatch: Color(int.parse(Conf.get('theme.primary_color') ?? "#FFFFFF", radix: 16)),
      ),
      home: ConfigScreen(),
    );
  }
}

class ConfigScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Config Screen'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text('API URL: ${Conf.get('api_url')}'),
            Text('Font Size: ${Conf.get('theme.font_size')}'),
          ],
        ),
      ),
    );
  }
}

4. 使用配置

在应用的任何位置,你都可以使用 Conf.get 方法来获取配置值。例如,在上面的 ConfigScreen 中,我们获取并显示了 api_urltheme.font_size 配置值。

注意事项

  • 确保 conf 插件的版本与 Flutter SDK 兼容。
  • 配置文件(如 config.json)应放在 assets 文件夹中,并在 pubspec.yaml 中声明。
  • Conf.init 方法应在应用启动时尽早调用,以确保配置信息在应用生命周期中可用。

通过以上步骤,你就可以在 Flutter 项目中成功集成并使用 conf 插件来管理配置了。

回到顶部