Установка переменных среды в Flutter

Например, создание клиента для API, такого как Twitch.

В двоичном файле Dart CLI я мог бы использовать общую переменную среды или переменную определения Dart. Например, используя оба как запасные варианты:

main() {
  String clientId = 
      // dart -dCLIENT_ID='abc bin/example.dart
      // This is considered "compiled-into" the application.
      const String.fromEnvironment('CLIENT_ID') ??

      // CLIENT_ID='abc' dart bin/example.dart
      // This is considered a runtime flag.
      Platform.environment['CLIENT_ID'];

  // Use clientId.
}

Есть ли у Flutter способ установить один или оба из них, в частности...

  • Во время разработки
  • Когда отправлен в продукт

Рад помочь с некоторыми документами, как только я выясню, как:)

11 ответов

Начиная с Flutter 1.17, вы можете определять переменные времени компиляции, если хотите.

Для этого просто используйте --dart-define аргумент во время flutter run или flutter build

Если вам нужно передать несколько пар ключ-значение, просто определите --dart-define многократно:

flutter run --dart-define=SOME_VAR=SOME_VALUE --dart-define=OTHER_VAR=OTHER_VALUE

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

const SOME_VAR = String.fromEnvironment('SOME_VAR', defaultValue: 'SOME_DEFAULT_VALUE');
const OTHER_VAR = String.fromEnvironment('OTHER_VAR' defaultValue: 'OTHER_DEFAULT_VALUE');

Кроме того, их можно использовать и в собственных слоях.

Если что - вот статья, которая объясняет больше

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

flutter run -t lib/production_main.dart

а также

flutter build apk -t lib/debug_main.dart

А затем в этих разных основных файлах настройте нужные конфигурации.

С точки зрения чтения идентификаторов, вы можете сделать это из произвольных активов https://flutter.io/assets-and-images/.

Я полагаю, что во Flutter можно читать из среды, как вы предлагаете, однако я не знаю, как установить эти переменные среды на iOS или Android.

Так как я пытался решить эту проблему и столкнулся с этой темой, я просто хотел добавить это для людей, которые ищут решение в будущем... Если все, что вам нужно, это среды PROD/DEV, то теперь есть поддерживаемый способ получить, если приложение находится в производстве или нет:

const bool isProduction = bool.fromEnvironment('dart.vm.product');

По предложению:

https://twitter.com/FlutterDev/status/1048278525432791041

https://github.com/flutter/flutter/issues/4014

Чтобы запустить ваше приложение (в flutter run)

  • flutter run --dart-define=EXAMPLE_API_ENDPOINT=https://api.example.com/

Чтобы выпустить ваше приложение (в flutter build)

Мое приложение не позволяло пользователям входить в систему. Я понял, что переменные среды были пустыми строками в приложении, а не их фактическими значениями.

  • iOS: flutter build ipa --dart-define=EXAMPLE_API_ENDPOINT=https://api.example.com/
  • Андроид: flutter build apk --dart-define=EXAMPLE_API_ENDPOINT=https://api.example.com/

документация

От flutter run --helpили же flutter build ipa --help, --dart-defineпоказывает:

      Additional key-value pairs that will be available as 
constants from the String.fromEnvironment, bool.fromEnvironment, 
int.fromEnvironment, and double.fromEnvironment constructors. 
Multiple defines can be passed by repeating "--dart-define" 
multiple times.

Я использую простой сценарий оболочки для создания определений дротиков. В моем приложении есть 3 варианта сборки:, и. Переменные среды были определены в обычном файле.

      env/
├── dev.env
├── prod.env
└── staging.env

Вот сценарий для создания dart-defines из .env файл.

      #!/bin/bash

# scripts/generate_dart_defines.sh

case "$1" in
"dev") INPUT="env/dev.env"
;;
"staging") INPUT="env/staging.env"
;;
"prod") INPUT="env/prod.env"
;;
*)
  echo "Missing arguments [dev|staging|prod]"
  exit 1
;;
esac

while IFS= read -r line
do
  DART_DEFINES="$DART_DEFINES--dart-define=$line "
done < "$INPUT"
echo "$DART_DEFINES"

Вот сценарий для запуска сборки.

      #!/bin/bash

# build.sh

if [ -z "$1" ] || [ -z "$2" ] || [ -z "$3" ]; then
  echo -e "Missing arguments: [apk|appbundle|ios] [release|debug|profile] [dev|staging|prod]"
  # invalid arguments
  exit 128
fi

DART_DEFINES=$(scripts/generate_dart_defines.sh $3)

if [ $? -ne 0 ]; then
  echo -e "Failed to generate dart defines"
  exit 1
fi

echo -e "artifact: $1, type: $2, flavor: $3\n"
echo -e "DART_DEFINES: $DART_DEFINES\n"

eval "flutter build $1 --$2 --flavor $3 $DART_DEFINES"

Скрипт принимает 3 аргумента. Первый - артефакт apk, appbundle или ios. Второй - тип сборки release, debug или profile. Третий - вкус сборки, dev, staging или prod.

      ./build.sh apk release prod

Обратите внимание, что вам также необходимо отдельно настроить android и ios для разных сборок. https://developer.android.com/studio/build/build-variants

https://shockoe.com/ideas/development/how-to-setup-configurations-and-schemes-in-xcode/

https://developer.apple.com/library/archive/documentation/ToolsLanguages/Conceptual/Xcode_Overview/ManagingSchemes.html

Если у вас есть несколько переменных среды, используйте опцию--dart-define-from-file=env.json.

Бывший:

      flutter build web --dart-define-from-file=env.json

или

      flutter run --dart-define-from-file=env_dev.json

Поместите env.json в корень, где находится pubspec.yaml.

Примеры json-файлов

  1. окр.json

    { "backend_url": "https://server.com" }

  2. env_dev.json

    { "backend_url": "https://dev.server.com" }

Пример использования:

      const backendUrl = String.fromEnvironment('backend_url', defaultValue: 'SOME_DEFAULT_VALUE');

Если вы используете версию Flutter >= 3.7, вы можете передать переменные среды двумя способами: через аргумент или через файл конфигурации. например:

      flutter run --dart-define=BASE_URL=http://localhost:3000

Или вы можете создать файл, такой как env.json, и установить в нем все нужные переменные, например:

      {
  "BASE_URL": "http://localhost:3000",
  "TEST_USER": "test_user"
}

а затем передайте файл:

      flutter run --dart-define-from-file=env.json

И если ваша версия Flutter <3.7, у вас есть только первый вариант.

Я делаю agreeс ответом, опубликованным @tatsuDn, но я хотел предоставить решение, которое загружает ваши переменные среды из файла .env .

Сначала создайте файл в корневой папке вашего проекта.
Убедитесь, что вы добавили файл в свой pubspec.yamlа также [git] ignoreЭто.

Вот как должен выглядеть ваш файл

      API_KEY=sampleapikey
# This line is a comment

# The white line above will be ignored
HEADER=sampleapiheader
ANOTHER_UNIQUE_KEY=theValueOfThisKey
KEY_CONTAINS_#=*234*5#
KEY_CONTAINS_EQUALS=IP8iwe=0&

Вот как будет выглядеть раздел ваших активов.

      # To add assets to your application, add an assets section, like this:
assets:
  - assets/images/
  - assets/flags/
  - .env

Наконец, загрузите переменную среды, прочитав и проанализировав файл, чтобы получить Map<String, String>который содержит ваши пары ключ-значение.

      Future<Map<String, String>> parseStringToMap({String assetsFileName = '.env'}) async {
  final lines = await rootBundle.loadString(assetsFileName);
  Map<String, String> environment = {};
  for (String line in lines.split('\n')) {
    line = line.trim();
    if (line.contains('=') //Set Key Value Pairs on lines separated by =
        &&
        !line.startsWith(RegExp(r'=|#'))) {
      //No need to add emty keys and remove comments
      List<String> contents = line.split('=');
      environment[contents[0]] = contents.sublist(1).join('=');
    }
  }
  return environment;
}

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

      ElevatedButton(
    onPressed: () async {
      final env = await parseStringToMap(assetsFileName: '.env');
      print(env);
    },
    child: Text('Print Environment Variables')
),

Вот вывод файла .env выше.

      >>>I/flutter ( 7182): {API_KEY: sampleapikey, HEADER: sampleapiheader, ANOTHER_UNIQUE_KEY: theValueOfThisKey, KEY_CONTAINS_#: *234*5#, KEY_CONTAINS_EQUALS: IP8iwe=0&}

Примечания. Вам нужно будет перезапустить приложение (не перезагружать в горячем режиме), чтобы .envАктив загружен.
Вы также можете просто загрузить свои переменные в файл json [это может быть полезно, когда у вас есть нестроковые переменные среды, и вы не хотите анализировать строку.
Чтобы избежать ввода-вывода, рекомендуется просто загрузить переменные среды один раз и получить к ним доступ через приложение, используя локаторы сервисов, такие как GetIt.

Flutter ввел переменные среды во время компиляции, используя--dart-defineаргумент. Если у вас есть более одной переменной среды, используйте--dart-define-from-fileаргумент желательно.

Для одной переменной среды выполните следующие действия:

      flutter run --dart-define=VAR_NAME=SOME_VALUE

Если существует более одной переменной среды, выполните следующие действия:

  • Создайте файл JSON, содержащий переменные.
      {
    "VAR_A": someValue,
    "VAR_B": anotherValue
}
  • передать этот файл команде сборки/запуска флаттера
      flutter run --dart-define-from-file=config.json

где config.json — созданный файл JSON, содержащий переменные.

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

      const VAR_A = String.fromEnvironment('VAR_A', defaultValue: 'SOME_DEFAULT_VALUE');
const VAR_B = int.fromEnvironment('VAR_B', defaultValue: 1);
const VAR_C = bool.fromEnvironment('VAR_C', defaultValue: false);

Следует отметить, что для double не существует конструкторов fromEnvironment. Приведенные выше аргументы также можно использовать сflutter buildкоманда.

В статье здесь подробно объясняется, как это сделать.

хотя приведенные выше ответы верны из python и reactjs, я использовал dotenv и нашел то же самое для флаттера для загрузки файла .env https://pub.dev/packages/dotenv

Создайте класс:

import 'package:flutter/foundation.dart';

class AppUtils {
  static String get clientId {
    if (kDebugMode) return 'debug_id';
    else if (kProfileMode) return 'profile_id';
    else if (kReleaseMode) return 'production_id';
    else if (kIsWeb) return 'web_mode_id';
    
    throw ArgumentError('No mode detected');
  }
}

Применение:

var id = AppUtils.clientId;
Другие вопросы по тегам