Сравнение простых старых переменных Dart, JSON, YAML и окружения

К настоящему времени вы привыкли настраивать параметры конфигурации в pubspec.yaml, но что, если вы хотите определить свои собственные значения конфигурации и прочитать их в своем приложении? Как ты это делаешь? В этой статье я дам вам обзор некоторых вариантов.

Обычный старый дротик

Одно из простых решений - использовать простой старый класс Dart. Создайте файл с именем my_config.dart и добавьте следующий код:

class MyConfig {
  static const String country = 'Mongolia';
  static const String animal = 'horse';
}

Затем вы можете использовать его в любом месте своего кода, импортировав этот файл:

import 'my_config.dart';
void main() {
  print(MyConfig.country);
  print(MyConfig.animal);
}

Использование библиотеки, а не класса

На самом деле нет необходимости использовать имя класса, например MyConfig, когда все, что он содержит, - это статические члены. Замените my_config.dart следующим упрощенным кодом:

const String country = 'Mongolia';
const String animal = 'horse';

Вы по-прежнему можете использовать эти значения в любом месте вашего приложения, но теперь вы также можете дать им любое пространство имен и показать или скрыть их по своему усмотрению:

import 'my_config.dart' as config show country;
void main() {
  print(config.country);
}

Пространство имен - config, и вы показываете только переменную country, поэтому animal не будет доступен. Это полезно для предотвращения конфликтов имен, когда в вашем проекте есть другие переменные или библиотеки.

Не рассказывай свои секреты

Прежде чем перейти к другим параметрам, я хочу напомнить вам, что нужно быть осторожным с любыми личными данными, которые могут быть в вашем файле конфигурации. Вы не хотите случайно поделиться этим со всем миром, отправив файл в репозиторий Git. Чтобы этого не произошло, вам следует добавить файл конфигурации в .gitignore.

Откройте .gitignore и добавьте имя файла конфигурации в новую строку:

# Configuration
my_config.dart

Конечно, теперь, когда кто-то клонирует ваш проект из репозитория Git, он не будет компилироваться, пока они не добавят отсутствующий файл конфигурации.

JSON

Если вы предпочитаете текстовый файл для конфигурации, использование JSON - простой вариант.

Чтение файла JSON в Dart

Создайте файл с именем my_config.json в корне вашего проекта Dart и добавьте следующее содержимое:

{
    "country": "Mongolia",
    "animal": "horse"
}

Теперь вы можете прочитать это в своем приложении так:

import 'dart:convert';
import 'dart:io';
Future<void> main() async {
  final configFile = File('my_config.json');
  final jsonString = await configFile.readAsString();
  final dynamic jsonMap = jsonDecode(jsonString);
  print(jsonMap['country']);
  print(jsonMap['animal']);
}

Здесь вам нужно сделать три вещи:

  1. Получите файл, указав путь. Для этого требуется библиотека dart:io.
  2. Извлеките текстовое содержимое файла с помощью readAsString.
  3. Преобразуйте строку JSON в карту Dart с jsonDecode, которая поступает из библиотеки dart:convert.

Не забудьте добавить my_config.json в .gitignore, если в вашем файле конфигурации есть конфиденциальная информация.

Примечание. Если вам сложно скопировать файл конфигурации при развертывании приложения в новое место, а не добавлять его в .gitignore, вы можете просто использовать безопасные значения по умолчанию, а затем отредактировать файл после перемещения проекта на рабочий сервер. Спасибо этой статье за идею.

Чтение файла JSON во Flutter

Если у вас есть текстовый файл конфигурации, к которому вы хотите получить доступ во время выполнения во Flutter, вам необходимо поместить его в пакет ресурсов вашего приложения.

Создайте папку с именем assets в корне вашего проекта Flutter и добавьте в нее my_config.json (все еще с тем же содержимым JSON, которое вы использовали в примере с Dart).

Затем объявите этот файл в pubspec.yaml следующим образом:

flutter:
  assets:
    - assets/my_config.json

Теперь вы можете получить к нему доступ и прочитать его во Flutter, используя rootBundle или DefaultAssetBundle.of(context). (Последний вариант рекомендуется, поскольку его можно настроить на уровне виджета).

import 'dart:convert';
import 'package:flutter/material.dart';
Future<void> loadAsset(BuildContext context) async {
  final jsonString = await DefaultAssetBundle.of(context)
      .loadString('assets/my_config.json');
  final dynamic jsonMap = jsonDecode(jsonString);
  print(jsonMap['country']);
  print(jsonMap['animal']);
}

Метод loadString получает текст из файла. После этого он такой же, как Дарт.

YAML

Формат YAML - еще один распространенный формат файлов конфигурации. Его немного проще редактировать вручную, чем JSON. Это также формат, который Dart использует для своих собственных файлов конфигурации.

Чтение файла YAML в Dart

Создайте файл с именем my_config.yaml в корне вашего проекта Dart и добавьте следующее содержимое:

country: Mongolia
animal: horse

Для чтения файлов YAML у команды Dart есть пакет под названием yaml, который вы можете использовать. Добавьте его в свои зависимости pubspec.yaml:

dependencies:
  yaml: ^3.1.0

Затем вы можете использовать его для анализа файла YAML следующим образом:

import 'dart:io';
import 'package:yaml/yaml.dart';
Future<void> main() async {
  final configFile = File('my_config.yaml');
  final yamlString = await configFile.readAsString();
  final dynamic yamlMap = loadYaml(yamlString);
  print(yamlMap['country']);
  print(yamlMap['animal']);
}

Вам все еще нужно было получить строку из текстового файла, как вы это делали раньше с JSON, но как только вы ее получите, вы можете преобразовать ее в карту с помощью loadYaml. Следует отметить, что эта карта относится к типу YamlMap, который включает некоторые отличия от Dart Map. Вы можете просмотреть документацию по исходному коду для получения дополнительной информации об этом.

Не забудьте добавить my_config.yaml в .gitignore, если в вашем файле конфигурации есть конфиденциальная информация.

Чтение файла YAML во Flutter

Если вы читали статью до этого момента, то здесь нет ничего нового. Добавьте my_config.yaml к своим ресурсам и объявите его в pubspec.yaml:

dependencies:
  yaml: ^3.1.0
flutter:
  assets:
    - assets/my_config.yaml

Затем прочтите это во Flutter вот так:

import 'package:flutter/material.dart';
import 'package:yaml/yaml.dart';
Future<void> loadAsset(BuildContext context) async {
  final yamlString = await DefaultAssetBundle.of(context)
      .loadString('assets/my_config.yaml');
  final dynamic yamlMap = loadYaml(yamlString);
  print(yamlMap['country']);
  print(yamlMap['animal']);
}

Но я хочу прочитать сам pubspec.yaml!

Если вы работаете в простом проекте Dart, это довольно просто. Опять же, используя пакет yaml, вы можете сделать это так:

import 'dart:io';
import 'package:yaml/yaml.dart';
Future<void> main() async {
  final configFile = File('pubspec.yaml');
  final yamlString = await configFile.readAsString();
  final dynamic yamlMap = loadYaml(yamlString);
  print(yamlMap['name']);
  print(yamlMap['description']);
  print(yamlMap['version']);
}

Однако в проекте Flutter pubspec.yaml не входит в набор ресурсов (насколько мне известно), поэтому вы не можете получить к нему прямой доступ. Вопрос в том, зачем вам к нему доступ? Если вы хотите знать такие вещи, как название версии или номер сборки, вам следует использовать package_info_plus, который является фаворитом Flutter. Вот информация об использовании из документации:

import 'package:package_info_plus/package_info_plus.dart';
PackageInfo packageInfo = await PackageInfo.fromPlatform();
String appName = packageInfo.appName;
String packageName = packageInfo.packageName;
String version = packageInfo.version;
String buildNumber = packageInfo.buildNumber;

Переменные среды

Вместо того, чтобы возиться с чтением и анализом файлов конфигурации, другой вариант - использовать переменные среды. Это переменные, которые вы передаете в качестве параметров командной строки при запуске приложения.

Использование переменных окружения в Dart

Замените main.dart следующим кодом:

void main() {
  const country = String.fromEnvironment('country');
  const animal = String.fromEnvironment('animal');
  print(country);
  print(animal);
}

Метод fromEnvironment получает свое значение из аргумента командной строки, который вы передадите при запуске приложения.

Теперь запустите приложение из командной строки следующим образом:

dart run --define=country=Mongolia --define=animal=horse

Параметр --define позволяет вам установить пару "ключ-значение" для переменной среды. Ключ является первым, а значение вторым, причем все элементы разделяются символом = равно. Для двух пар ключ-значение просто дважды используйте --define.

Консоль отладки должна показать ожидаемые результаты:

Mongolia
horse

Вы даже можете следовать тому же шаблону, который мы использовали в разделе «Обычный старый дротик» выше, и создать файл my_config.dart со следующим содержанием:

const country = String.fromEnvironment('country');
const animal = String.fromEnvironment('animal');

fromEnvironment также принимает значение по умолчанию (которое вы можете использовать, например, во время разработки):

String.fromEnvironment('country', defaultValue: 'unknown')

Использование переменных окружения во Flutter

Во Flutter все то же, что и в Dart, за исключением того, как вы устанавливаете переменные в командной строке:

flutter run --dart-define=country=Mongolia --dart-define=animal=horse

На этот раз вы используете --dart-define вместо --define.

Преимущество использования переменных среды заключается в том, что у вас нет файла конфигурации, который нужно добавить в .gitignore, а затем скопировать для нового проекта.

Обновлять

Flutter Intellij Plugin, по-видимому, теперь поддерживает добавление переменных среды в IDE. Вероятно, это касается пользователей Android Studio. Я еще не использовал эту функцию. Оставьте комментарий, если есть.

Вывод

В этой статье рассказывалось только о том, как получить доступ к значениям конфигурации из кода Dart самого приложения. Если вам нужно что-то вроде сборки разновидностей для приложения Flutter, вам также придется выполнить дополнительную настройку для конкретной платформы. Вы можете узнать больше о том, как это сделать, в списке статей, включенных в документацию Flutter:

Оставьте комментарий ниже о том, какой метод вы предпочитаете для установки значений конфигурации или о вещах, на которые следует обратить внимание.