目录

包依赖项

依赖项是 pub 包管理器 的核心概念之一。 依赖项 是你的包需要工作才能正常运行的另一个包。依赖项在你的 pubspec 中指定。你只需要列出 直接依赖项 :你的包直接使用的软件。Pub 会帮你处理 传递依赖项

本页详细介绍了如何指定依赖项。最后列出了 包依赖项的最佳实践

概述

#

对于每个依赖项,你需要指定你依赖的包的 名称 和允许的包的 版本范围 。你还可以指定 来源 。来源告诉 pub 如何定位包。

例如,你可以按以下格式指定依赖项:

yaml
dependencies:
  transmogrify: ^1.0.0

这段 YAML 代码创建了对 transmogrify 包的依赖,使用默认的包存储库( pub.dev ),并允许使用从 1.0.02.0.0 (但不包括 2.0.0 )的任何版本。要了解这种语法,请查看 版本约束

要指定 pub.dev 以外的来源,请使用 sdkhostedgitpath 。例如,以下 YAML 代码使用 path 来告诉 pub 从本地目录获取 transmogrify

yaml
dependencies:
  transmogrify:
    path: /Users/me/transmogrify

下一节将描述每个依赖项来源的格式。

依赖项来源

#

Pub 可以使用以下来源来查找包:

托管包

#

托管 包是可以从 pub.dev 网站(或使用相同 API 的其他 HTTP 服务器)下载的包。以下是如何声明对托管包的依赖的示例:

yaml
dependencies:
  transmogrify: ^1.4.0

此示例指定你的包依赖于名为 transmogrify 的托管包,并且可以与 1.4.0 到 2.0.0(但不包括 2.0.0 本身)之间的任何版本一起使用。

如果你想使用 你自己的包存储库 ,你可以使用 hosted 来指定它的 URL。以下 YAML 代码使用 hosted 来源创建了对 transmogrify 包的依赖:

yaml
environment:
  sdk: '^2.19.0'

dependencies:
  transmogrify:
    hosted: https://some-package-server.com
    version: ^1.4.0

版本约束是可选的,但建议使用。如果没有给出版本约束,则假定为 any

Git 包

#

有时,你处于技术前沿,需要使用尚未正式发布的包。也许你的包本身仍在开发中,并且正在使用同时开发的其他包。为了方便起见,你可以直接依赖于存储在Git存储库中的包。

yaml
dependencies:
  kittens:
    git: https://github.com/munificent/kittens.git

这里的 git 表示此包是使用 Git 找到的,后面的 URL 是可用于克隆包的 Git URL。

即使包仓库是私有的,你也可以配置你的 git 设置,使用 HTTPS 访问密钥SSH 密钥对 访问仓库。然后,你可以使用仓库的相应 URL 来依赖包:

yaml
dependencies:
  kittens:
    # SSH URL:
    git: [email protected]:munificent/kittens.git

dart pub 命令会将 git clone 作为子进程调用,因此你只需要提供在执行 git clone <url> 时有效的 <url>

如果你想依赖于特定的提交、分支或标签,请向描述中添加 ref 密钥:

yaml
dependencies:
  kittens:
    git:
      url: [email protected]:munificent/kittens.git
      ref: some-branch

ref 可以是 Git 允许[标识提交]的任何内容。(https://www.kernel.org/pub/software/scm/git/docs/user-manual.html#naming-commits)

Pub 假设包位于 Git 存储库的根目录中。要指定仓库中不同的位置,请指定相对于仓库根目录的 path

yaml
dependencies:
  kittens:
    git:
      url: [email protected]:munificent/cats.git
      path: path/to/kittens

此路径相对于 Git 仓库的根目录。

不允许将 Git 依赖项作为上传到 pub.dev 的包的依赖项。

路径包

#

有时,你会发现自己同时处理多个相关的包。也许你正在创建一个框架,同时构建一个使用它的应用程序。在这些情况下,在开发过程中,你真的想依赖于本地文件系统上该包的 实时 版本。这样,一个包中的更改会立即被依赖它的包获取。

为了处理这种情况,pub 支持 路径依赖

yaml
dependencies:
  transmogrify:
    path: /Users/me/transmogrify

这意味着 transmogrify 的根目录是 /Users/me/transmogrify 。对于此依赖项,pub 会直接生成指向引用的包目录的 lib 目录的符号链接。你对依赖包所做的任何更改都会立即显示。你不需要每次更改依赖包时都运行 pub。

允许使用相对路径,并且这些路径被认为是相对于包含你的 pubspec 的目录的。

路径依赖项对于本地开发很有用,但在与外部世界共享代码时不起作用——并非每个人都可以访问你的文件系统。因此,如果你的 pubspec 中有任何路径依赖项,则无法将包上传到 pub.dev 网站

相反,典型的流程是:

  1. 在本地编辑你的 pubspec 以使用路径依赖项。
  2. 处理主包及其依赖的包。
  3. 一旦它们都工作正常,就发布依赖包。
  4. 将你的 pubspec 更改为指向其依赖项的现在托管的版本。
  5. 如果你想,也可以发布你的主包。

SDK

#

SDK 源用于与包一起提供的任何 SDK,这些 SDK 本身也可能是依赖项。目前,Flutter 是唯一支持的 SDK。

语法如下所示:

yaml
dependencies:
  flutter_driver:
    sdk: flutter

sdk: 后面的标识符指示包来自哪个 SDK。如果它是 flutter ,则只要满足以下条件,依赖项就可以满足:

  • Pub 在 flutter 可执行文件的上下文中运行
  • Flutter SDK 包含一个具有给定名称的包

如果它是一个未知的标识符,则始终认为依赖项不满足。

版本约束

#

假设你的包 A 依赖于包 B。你如何向其他开发者传达哪个版本的包 B 与给定版本的包 A 保持兼容?

为了让开发者知道版本兼容性,请指定版本约束。你希望允许尽可能广泛的版本范围,以便为你的包用户提供灵活性。该范围应排除不起作用或未经测试的版本。

Dart 社区使用语义版本化1

你可以使用 传统语法 或从 Dart 2.19 开始的 脱字符语法 来表达版本约束。两种语法都指定了兼容版本的范围。

传统语法提供了一个明确的范围,例如 '>=1.2.3 <2.0.0' 。脱字符语法提供了一个明确的起始版本 ^1.2.3

yaml
environment:
  # 此包必须从 3.2 开始使用 3.x 版本的 Dart SDK。
  sdk: ^3.2.0

dependencies:
  transmogrify:
    hosted:
      name: transmogrify
      url: https://some-package-server.com
    # 此包必须从 1.4 开始使用 1.x 版本的 transmogrify。
    version: ^1.4.0

要了解有关 pub 版本系统的更多信息,请参阅 包版本控制页面

传统语法

#

使用传统语法的版本约束可以使用以下任何值:

允许使用?备注
any所有版本用作版本约束为空的显式声明。
1.2.3仅限给定版本由于它对使用你的包的应用程序施加了额外的限制,因此限制了你的包的采用率。
>=1.2.3给定版本或更高版本
>1.2.3高于给定版本的版本
<=1.2.3给定版本或更低版本
<1.2.3低于给定版本的版本当你知道一个 适用于你的包的上限版本时使用此版本。此版本可能是第一个引入某些重大更改的版本。

你可以将任何版本的组合指定为它们的范围相交。例如,如果你将版本值设置为 '>=1.2.3 <2.0.0' ,则此操作会将两个限制结合起来,因此依赖项可以是从 1.2.32.0.0 的任何版本,但不包括 2.0.0 本身。

脱字符语法

#

脱字符语法以简洁的方式表达版本约束。 ^version 表示 保证与给定版本向后兼容的所有版本的范围 。此范围将包括所有版本,直到下一个引入重大更改的版本。由于 Dart 使用语义版本控制,对于任何 1.0 或更高版本的包,这将是下一个主要版本

或者对于任何早于 1.0 的包版本,则为下一个次要版本。

版本值涵盖范围脱字符语法传统语法
>=1.0下一个主要版本^1.3.0'>=1.3.0 <2.0.0'
<1.0下一个次要版本^0.1.2'>=0.1.2 <0.2.0'

以下示例显示了脱字符语法:

yaml
dependencies:
  # 涵盖从 1.3.0 到 1.y.z 的所有版本,但不包括 2.0.0
  path: ^1.3.0
  # 涵盖从 1.1.0 到 1.y.z 的所有版本,但不包括 2.0.0
  collection: ^1.1.0
  # 涵盖从 0.1.2 到 0.1.z 的所有版本,但不包括 0.2.0
  string_scanner: ^0.1.2

开发依赖项

#

Pub 支持两种依赖项:常规依赖项和 开发依赖项 。开发依赖项与常规依赖项的不同之处在于, 你依赖的包的开发依赖项会被忽略 。这是一个示例:

假设 transmogrify 包在其测试中以及仅在其测试中使用了 test 包。如果有人只想使用 transmogrify ——导入其库——实际上并不需要 test 。在这种情况下,它将 test 指定为开发依赖项。它的 pubspec 将包含类似以下内容:

yaml
dev_dependencies:
  test: ^1.25.0

Pub 获取你的包依赖的每个包,以及这些包传递依赖的 所有 包。它还会获取你的包的开发依赖项,但它会 忽略 任何依赖包的开发依赖项。Pub 只获取 你的 包的开发依赖项。因此,当你的包依赖于 transmogrify 时,它将获取 transmogrify ,但不会获取 test

决定使用常规依赖项还是开发依赖项的规则很简单:如果依赖项是从你的 libbin 目录中的某个内容导入的,则它需要是常规依赖项。如果它仅从 testexample 等导入,则它可以而且应该是开发依赖项。

使用开发依赖项可以使依赖关系图更小。这使得 pub 运行速度更快,并且更容易找到满足所有约束的包版本集。

依赖项覆盖

#

你可以使用 dependency_overrides 来临时覆盖对依赖项的所有引用。

例如,也许你正在更新已发布包 transmogrify 的本地副本。Transmogrify 被你依赖关系图中的其他包使用,但你不想在本地克隆每个包并更改每个 pubspec 来测试你的 transmogrify 本地副本。

在这种情况下,你可以使用 dependency_overrides 来覆盖依赖项,以指定保存包本地副本的目录。

pubspec 将如下所示:

yaml
name: my_app
dependencies:
  transmogrify: ^1.2.0
dependency_overrides:
  transmogrify:
    path: ../transmogrify_patch/

当你运行 dart pub getdart pub upgrade 时,pubspec 的 lockfile 会更新以反映你依赖项的新路径,并且无论在何处使用 transmogrify,pub 都使用本地版本。

你还可以使用 dependency_overrides 来指定包的特定版本:

yaml
name: my_app
dependencies:
  transmogrify: ^1.2.0
dependency_overrides:
  transmogrify: '3.2.1'

在包解析期间,只考虑 包自身 pubspec 中的依赖项覆盖。任何被依赖包内部的依赖项覆盖都会被忽略。

因此,如果你将包发布到 pub.dev,请记住你的包的依赖项覆盖会被你的包的所有用户忽略。

最佳实践

#

积极主动地管理你的依赖项。如果可能,确保你的包依赖于最新版本的包。如果你的包依赖于一个过时的包,那么这个过时的包可能在其依赖树中依赖于其他过时的包。过时的包版本会对你的应用程序的稳定性、性能和质量产生负面影响。

我们建议遵循以下包依赖项的最佳实践。

使用脱字符语法

#

使用 脱字符语法 指定依赖项。这允许 pub 工具在出现新版本时选择更新版本的包。此外,它还在允许的版本上设置了上限。

依赖于最新的稳定包版本

#

使用 dart pub upgrade 更新到你的 pubspec 允许的最新包版本。要识别你的应用程序或包中未处于最新稳定版本的依赖项,请使用 dart pub outdated

严格控制开发依赖项的版本约束

#

开发依赖项定义了仅在开发时才需要的包。完成的应用程序不需要这些包。这些包的示例包括测试或代码生成工具。将 dev_dependencies 中包的版本约束设置为你的包依赖的最新版本的较低界限。

严格控制开发依赖项的版本约束可能类似于以下内容:

yaml
dev_dependencies:
  build_runner: ^2.4.13
  lints: ^2.1.1
  test: ^1.25.8

此 YAML 将 dev_dependencies 设置为最新的补丁版本。

更新包依赖项后进行测试

#

如果你在不更新 pubspec 的情况下运行 dart pub upgrade ,则 API 应该保持不变,并且你的代码应该像以前一样运行——但要进行测试以确保。如果你修改了 pubspec 并更新到新的主要版本,那么你可能会遇到重大更改,因此你需要更彻底地进行测试。

使用降级的依赖项进行测试

#

在开发用于发布的包时,通常最好允许尽可能广泛的依赖约束。广泛的依赖约束会降低包使用者面临版本解析冲突的可能性。

例如,如果你依赖于 foo: ^1.2.3 并且发布了 foo 的版本 1.3.0 ,那么保留现有的依赖约束 (^1.2.3) 可能是合理的。但是,如果你的包开始使用在 1.3.0 中添加的功能,则你需要将你的约束提升到 ^1.3.0

但是,当依赖约束变得必要时,很容易忘记提升它。因此,最佳实践是在发布之前针对降级的依赖项测试你的包。

要针对降级的依赖项进行测试,请运行 dart pub downgrade 并验证你的包仍然可以进行分析而不会出错,并且所有测试都能通过:

dart pub downgrade
dart analyze
dart test

使用降级的依赖项进行测试应该与使用最新依赖项的常规测试一起进行。如果需要提升依赖约束,请自行更改它们,或者使用 dart pub upgrade --tighten 将依赖项更新到最新版本。

验证下载包的完整性

#

在检索新依赖项时,请使用 --enforce-lockfile 选项以确保提取的包内容与原始存档的内容匹配。在不修改 lockfile 的情况下,此标志仅在满足以下条件时才解析新依赖项:

  • pubspec.yaml 已满足
  • pubspec.lock 不丢失
  • 包的 内容哈希 匹配