pub.dev, официальном публичном репозитории библиотек для Dart и Flutter.
dependencies:
dependency_name: <version>
Зависимость из Git-репозитория.
dependencies:
<dependency_name>:
git: https://github.com/<repo_url>
## Зависимость лежит по указанному пути в корне проекта
Помимо указания ссылки мы можем добавлять параметры ref
и path
:
ref
— позволяет указывать номер коммита, название ветки или тега, чтобы тянуть зависимость не из ветки master
или main
, а исходя из идентификатора;path
— позволяет указывать пути до библиотеки, если пакет лежит не в корне проекта.dependencies:
<dependency_name>:
git:
url: https://github.com/<repo_url>
ref: some-branch
path: some-path
Зависимости, которые лежат в локальной файловой системе, могут устанавливаться локально. Для этого нужно прописать полный или относительный путь до этой зависимости.
dependencies:
<dependency_name>:
path: <your_local_path>
Зависимость, которая находится на pub.dev, публична и доступна для всех разработчиков. Не всегда разработчики готовы делиться своими наработками, так что существует возможность загружать пакет с удалённого хранилища пакетов, который имеет такой же API, что и pub.dev. Для установки таких зависимостей требуется указывать URL в параметре hosted.
dependencies:
<dependency_name>:
hosted: https://some-package-server.com
version: <version>
Такое приватное хранилище пакетов можно создать с помощью специального пакета unpub
, о котором можно прочитать по ссылке.
Как мы узнали в предыдущем параграфе, библиотеки имеют обязательное поле 'version' в файле pubspec.yaml
.
Для определения версии пакета в Dart используется семантическое версионирование (англ. semantic versioning), которое состоит из трёх чисел, разделённых точками: мажор.минор.патч
(англ. major.minor.patch
). Каждое из чисел обозначает различные изменения в пакете:
В Dart можно использовать операторы версионирования для указания ограничений версий зависимостей. Операторы версионирования, которые также называют констрейнтами (англ. constraints), включают в себя следующие:
О семантическом версионировании можно прочесть в официальной документации. В ней же, в последнем абзаце, рассказано о библиотеках с нулевой мажорной версией.
Также можно указывать диапазон версий с помощью комбинирования <, <=, >, >=. Например, конструкция >=1.12.8 <=3.0.0 означает, что мы хотим установить версию от 1.12.8 включительно до 3.0.0 включительно.
Но что значит максимально возможная версия? Чтобы это понять, нужно узнать ещё об одном варианте разделения зависимостей: прямые, транзитивные и совместно используемые.
Вот так выглядит прямая зависимость, мы добавляем пакет A напрямую в наше приложение.
Транзитивная (англ. transitive) же зависимость подтягивается из пакета, который мы устанавливаем как зависимость. Это зависимость нашей зависимости.
А общая (англ. shared) зависимость — зависимость, которую подтягиваем и мы, и используемый нами пакет.
Максимально возможная версия — та, которая удовлетворяет диапазону, образующемуся при подтягивании прямых, общих и транзитивных зависимостей. Для иллюстрации выше можно заметить, что мы пытаемся установить пакет в версии ^1.0.0 и одновременно версии ^2.0.0 — так как пересечения нет, возможной для установки версии тоже не существует. Такая ситуация называется конфликтом, и при вызове команды flutter pub get
в консоли появится следующее сообщение:
Because Package A depends on Package B ^2.0.0 and no version of Package A match, Package A requires Package B ^2.0.0.
So, because app depends on both Package B ^1.0.0 and Package A, version solving failed.
Существует три способа решения данной проблемы:
dependency_overrides
, и pub
будет использовать эти значения вместо тех, которые указаны в dependencies
или подтягиваются транзитивно.В нашем случае это работает так, что мы используем пакет A
, который устанавливает транзитивно пакет B
версии 2.0.0
, но мы хотим использовать версию 1.0.0
, и для этого можно указать в файле pubspec.yaml
следующее:
dependency_overrides:
package_B: ^1.0.0
С переопределением версий нужно быть аккуратными. Есть риск, что после переопределения проект перестанет компилироваться, так как библиотеке, которая использует версию выше или ниже, будет не хватать функционала в переопределённой версии. Также не стоит устанавливать в проект библиотеки неактуальных версий, ведь фреймворк и библиотеки развиваются быстро, так что могут появиться несовместимые изменения. Чем дольше не обновлять библиотеки, тем сложнее это сделать потом. Также в новых версиях могут появиться новые возможности и правки недочётов.
Помимо зависимостей, указывающихся в pubspec.yaml
как dependencies
, существуют dev_dependencies. Это зависимости, которые нужны только на этапе разработки, они не попадают в сборку приложения. К ним относится linter, различные зависимости для кодогенерации и аннотаций, зависимости для тестов и другие зависимости, которые не используются для сборки приложения.
dev_dependencies:
flutter_lints: ^2.0.2
pubspec.lock
— файл, который автоматически генерируется при успешном запуске команды pub get
в проекте Flutter или Dart. Он содержит информацию о фактических версиях зависимостей, которые были установлены для проекта, включая транзитивные зависимости.
Файл pubspec.lock
содержит информацию о конкретных версиях каждого пакета, установленного в проекте. Это гарантирует, что при повторной установке пакетов будут использованы те же версии зависимостей, что и в предыдущий раз.
# Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile
packages: # Тут содержится список всех зависимостей
dependency_name:
dependency: transitive # Тут содержится тип зависимости: transitive, shared, direct main, direct overridden
description:
... # Тут содержится короткое описание зависимости, для зависимости с pub.dev тут будут содержаться поля name и url с названием и путём до зависимости соответственно
source: ... # Тут содержится источник зависимости, для зависимости с pub.dev тут будет стоять hosted
version: ... # Тут — версия зависимости, которая установилась после прогона команды flutter pub get
sdks: # В этой части есть констрейнты для dart и flutter
dart: ">=2.15.0 <3.0.0" # Устанавливаем Dart версии выше или равной 2.15.0, но меньше 3.0.0
flutter: ">=2.8.0" # Устанавливаем Flutter версии выше или равной 2.8.0
Для приложений — да. Он гарантирует, что при локальном запуске на разных платформах у разработчиков не разойдутся версии библиотек. Это можно объяснить на таком примере: в команду может прийти новый разработчик, запустить команду pub get
— и у него не установятся новые мажорные версии библиотек, ведь lock-файл уже существует и не поменяется.
Однако для библиотек этот файл в репозитории следует игнорировать. Библиотеки должны содержать актуальные версии своих зависимостей, чтобы разработчик библиотеки не использовал старый сгенерированный lock-файл, с которым у него всё работает, а пользователи не устанавливали новые версии транзитивных библиотек, с которыми проект несовместим.
Для создания Flutter-проекта используется команда flutter create
. Для создания библиотеки или плагина указывается флаг --template
. Команда flutter create --template=package package_name
используется для создания пакета, а flutter create --template=plugin plugin_name
— для создания плагина.
Для библиотек принято создавать вот такую структуру:
Отличие от структуры проекта в том, что библиотека содержит папку lib/src
. Все реализации будут храниться в lib/src
и будут приватны, то есть недоступны для внешних пользователей. При этом в файлах, лежащих непосредственно в папке lib, будут файлы с экспортируемым функционалом с указанием путей до функционала, который хочется предоставить пользователю библиотеки.
export
используется в файле, который находится в корне библиотеки и который будет необходим для импорта в других частях проекта, зависимого от библиотеки. Часто названия экспорт-файлов совпадают с названием библиотеки.
// my_library.dart
library my_library; // Уникальный тег, должен совпадать с названием файла
export 'src/file1.dart'; // Экспортируем весь функционал файла file1.dart
export 'src/file2.dart' show ClassA; // Экспортируем только класс ClassA из файла file2.dart
export 'src/file3.dart' hide ClassB; // Экспортируем всё, кроме класса ClassB, из файла file3.dart
Для использования функционала из файлов проекта или из библиотеки следует использовать импорты.
import 'package:my_package/my_package.dart'; // Импортируем весь функционал, экспортированный в файле my_package.dart библиотеки my_package
import 'src/some_file.dart' show SomeClassThatOurClientWillUse; // Импортируем только класс SomeClassThatOurClientWillUse
import 'src/some_file.dart' hide SomeClassThatOurClientDoesNotNeed; // Импортируем всё, кроме класса SomeClassThatOurClientDoesNotNeed
import 'src/some_file.dart' as someName; // Импортируем файл как someName. Потом к функционалу можно будет обращаться с префиксом someName: someName.<ClassName>.<MethodToCall>()
Помимо экспорт-файлов у библиотек есть ещё одна особенность — файл CHANGELOG.md
.
Файл CHANGELOG.md
крайне рекомендуется актуализировать. В нём принято оставлять информацию о том, что было добавлено, исправлено, удалено в новой версии библиотеки. А ещё в нём иногда рассказывают о будущих релизах и о том, что не успели сделать в последней версии. Вот так выглядит часть файла для разработчика:
# 2.0.2
Fixed an assert error if a `family` depends on itself while specifying `dependencies`.
А вот так — для того, кто читает информацию о последней версии:
К сожалению, единой инструкции нет, но можно обратить внимание на несколько параметров:
Насколько давно библиотека была обновлена и поддерживается ли она сейчас
На pub.dev это можно увидеть сразу под названием библиотеки. Например, на момент создания статьи библиотека firebase_messaging
была опубликована последний раз пять дней назад.
Насколько подробен CHANGELOG
При поднятии версии библиотеки это поможет разработчику понять, какой функционал стоит перепроверить или поддержать.
Сколько обращений в issue_tracker
И насколько быстро разработчик правит все замечания и отвечает на новые открытые вопросы.
Различные метрики популярности
Можно смотреть на звёздочки на GitHub или на секцию Scores на pub.dev
— в этой секции показаны многие метрики, включая популярность библиотеки, лайки и собственную метрику pub points, которая показывает уровень библиотеки, актуальность зависимостей, добавлена ли документация, следует ли библиотека гайдлайнам и совместима ли она с Dart
версии 3.
Null safety — это концепция, которая обеспечивает безопасную работу с опциональными типами значений. Она стала доступной в Dart начиная с версии 2.12, требуя от проектов и библиотек поддержки безопасности от null-значений. До Dart
версии 3 проект можно было запускать с флагом --no-sound-null-safety
, игнорируя предупреждения о небезопасной работе с null-
значениями. С третьей мажорной версии так не сделаешь — все библиотеки и сам проект обязаны безопасно работать с nullable-значениями. Новый пункт Dart 3 compatibility в Scores показывает баллы, которые дают за полную поддержку null safety.
Источник: https://pub.dev/packages/dio/score
Не забывайте запускать команду flutter pub get
перед запуском проекта, чтобы установить все необходимые зависимости. Если проект не собирается по непонятным причинам, может помочь команда flutter clean
— она очистит .dart_tools
и удалит возможно повреждённый кеш. После неё снова предстоит переустановить зависимости с помощью команды flutter pub get
.
Можно использовать команду flutter pub get --offline
для установки библиотек из кеша, если в данный момент нет соединения с интернетом.
Когда мы запускаем команду flutter pub get
, создаётся папка .pub_cache
, она содержит закешированные библиотеки, которые мы установили. Бывает такое, что кеш слетает. К примеру, когда в него добавилась кодогенерация или мы сами непреднамеренно изменили код одной из библиотек. Ни в коем случае не стоит модифицировать файлы из кеша. Вместо этого стоит запустить flutter pub cache clean
для полной очистки кеша и flutter pub cache repair
для переустановки каждой библиотеки.
В некоторых случаях возникают ошибки, связанные с платформо-специфичными библиотеками. Это может произойти, если указанные библиотеки не были установлены. Для очистки нативных зависимостей с целью их переустановки следует запустить pod deintegrate && pod install
для iOS и gradlew clean
для Android.