2.5 包管理
📚 核心知识点
- 包(Package)的概念
- pubspec.yaml 配置文件
- Pub 仓库(pub.dev)
- 添加和使用第三方包
- 不同的依赖方式
💡 核心概念
什么是包(Package)?
包(Package) 是一个可复用的代码模块,类似于:
- Java 的 jar 包
- Android 的 aar 包
- Web 的 npm 包
- iOS 的 CocoaPods
为什么需要包管理?
flowchart LR
A["开发者A<br/>写了日期处理工具"] --> B["发布到 pub.dev"]
C["开发者B"] --> D["在 pubspec.yaml<br/>添加依赖"]
D --> E["flutter pub get<br/>下载包"]
E --> F["在代码中使用"]
B -.-> D
style B fill:#C8E6C9
style F fill:#BBDEFB
好处:
- ✅ 代码复用,避免重复造轮子
- ✅ 统一管理版本
- ✅ 提高开发效率
- ✅ 社区共享
📝 pubspec.yaml 配置文件
文件结构
name: flutter_application_1 # 应用名称
description: A Flutter project # 应用描述
version: 1.0.0 # 版本号
environment:
sdk: '>=3.0.0 <4.0.0' # Dart SDK 版本
dependencies: # 应用依赖的包
flutter:
sdk: flutter
cupertino_icons: ^1.0.0 # iOS 风格图标
english_words: ^4.0.0 # 英文单词包
dev_dependencies: # 开发工具依赖
flutter_test:
sdk: flutter
flutter_lints: ^2.0.0 # 代码检查工具
flutter: # Flutter 相关配置
uses-material-design: true # 使用 Material Design
字段说明
| 字段 | 说明 | 示例 |
|---|---|---|
name | 包/应用名称 | my_app |
description | 描述信息 | A new Flutter project |
version | 版本号 | 1.0.0+1 |
dependencies | 应用依赖的包 | english_words: ^4.0.0 |
dev_dependencies | 开发工具依赖 | flutter_test: ... |
flutter | Flutter 配置 | uses-material-design: true |
dependencies vs dev_dependencies
flowchart TB
subgraph "dependencies(生产依赖)"
A1["参与编译"]
A2["打包到APK/IPA"]
A3["用户设备上运行"]
end
subgraph "dev_dependencies(开发依赖)"
B1["仅开发时使用"]
B2["不打包到APK/IPA"]
B3["测试工具、代码生成等"]
end
style A2 fill:#FFCDD2
style B2 fill:#C8E6C9
🌐 Pub 仓库
什么是 Pub?
Pub (pub.dev) 是 Google 官方的 Dart/Flutter 包仓库。
如何查找包?
- 访问 pub.dev
- 搜索包名(如:
english_words) - 查看包信息:
- 版本号
- 是否支持 Flutter
- 文档和示例
- 评分和流行度
包的评分指标
| 指标 | 说明 |
|---|---|
| Likes | 点赞数(受欢迎程度) |
| Pub Points | 质量评分(最高130分) |
| Popularity | 使用率 |
| ✓ Flutter Favorite | Flutter 官方推荐 |
🎯 使用第三方包:english_words
步骤1:添加依赖
编辑 pubspec.yaml:
dependencies:
flutter:
sdk: flutter
english_words: ^4.0.0 # 添加这一行
版本约束说明:
^4.0.0- 兼容 4.0.0 到 5.0.0 之前的版本>=4.0.0 <5.0.0- 显式指定范围4.0.0- 精确版本
步骤2:下载包
方法1: 点击 Android Studio/VS Code 右上角的 "Pub get" 按钮
方法2: 命令行执行
flutter pub get
输出:
Running "flutter pub get" in flutter_application_1...
Process finished with exit code 0
步骤3:导入包
import 'package:english_words/english_words.dart';
步骤4:使用包
class RandomWordsWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
// 生成随机英文单词对
final wordPair = WordPair.random();
return Text(
wordPair.asPascalCase, // 帕斯卡命名:HelloWorld
style: TextStyle(fontSize: 24),
);
}
}
english_words 功能展示
final word = WordPair.random();
print(word.asPascalCase); // HelloWorld
print(word.asCamelCase); // helloWorld
print(word.asSnakeCase); // hello_world
print(word.asLowerCase); // hello world
print(word.asUpperCase); // HELLO WORLD
📦 不同的依赖方式
1. 依赖 Pub 仓库(推荐)
dependencies:
http: ^1.0.0
provider: ^6.0.0
优点: 版本管理方便,自动处理依赖冲突
2. 依赖本地包
场景: 正在开发自己的包,还未发布
dependencies:
my_package:
path: ../my_package # 相对路径
或
dependencies:
my_package:
path: /Users/username/projects/my_package # 绝对路径
目录结构:
workspace/
├── my_app/ # 主应用
│ └── pubspec.yaml # 依赖 my_package
└── my_package/ # 本地包
└── pubspec.yaml
3. 依赖 Git 仓库
场景: 使用未发布到 pub.dev 的包,或使用特定分支
基本用法(包在仓库根目录)
dependencies:
my_package:
git:
url: https://github.com/username/my_package.git
指定分支
dependencies:
my_package:
git:
url: https://github.com/username/my_package.git
ref: develop # 分支名
指定路径(包在子目录)
dependencies:
package1:
git:
url: https://github.com/flutter/packages.git
path: packages/package1 # 子目录路径
指定 Tag 或 Commit
dependencies:
my_package:
git:
url: https://github.com/username/my_package.git
ref: v1.0.0 # Tag
# 或
ref: abc1234 # Commit SHA
🔄 包管理命令
常用命令
| 命令 | 说明 |
|---|---|
flutter pub get | 下载依赖包 |
flutter pub upgrade | 升级所有依赖包到最新版本 |
flutter pub outdated | 检查过期的依赖 |
flutter pub deps | 查看依赖树 |
flutter pub cache repair | 修复包缓存 |
命令详解
1. flutter pub get
flutter pub get
作用: 根据 pubspec.yaml 下载依赖
生成: pubspec.lock 文件(锁定具体版本)
2. flutter pub upgrade
flutter pub upgrade
作用: 升级所有包到最新兼容版本
示例:
english_words: ^4.0.0 → 升级到 4.0.5(最新)
3. flutter pub outdated
flutter pub outdated
输出:
Package Name Current Upgradable Resolvable Latest
english_words 4.0.0 4.0.5 4.0.5 4.1.0
http 0.13.5 0.13.6 1.0.0 1.0.0
📊 依赖方式对比
flowchart TB
Start["选择依赖方式"]
Q1{"包是否在<br/>pub.dev?"}
Q2{"是否正在<br/>开发这个包?"}
Q3{"包是否在<br/>GitHub等?"}
A1["✅ pub.dev 依赖<br/>dependencies:<br/> pkg: ^1.0.0"]
A2["✅ 本地依赖<br/>dependencies:<br/> pkg:<br/> path: ../pkg"]
A3["✅ Git 依赖<br/>dependencies:<br/> pkg:<br/> git:<br/> url: ..."]
Start --> Q1
Q1 -->|"是"| A1
Q1 -->|"否"| Q2
Q2 -->|"是"| A2
Q2 -->|"否"| Q3
Q3 -->|"是"| A3
style A1 fill:#C8E6C9
style A2 fill:#FFF9C4
style A3 fill:#BBDEFB
🎯 最佳实践
1. 版本管理
✅ 推荐: 使用版本约束
dependencies:
http: ^1.0.0 # ✅ 允许小版本更新
provider: '>=6.0.0 <7.0.0' # ✅ 显式范围
❌ 不推荐: 使用 any 或不指定版本
dependencies:
http: any # ❌ 可能导致版本冲突
2. 定期更新依赖
# 检查过期的包
flutter pub outdated
# 升级包
flutter pub upgrade
3. 提交 pubspec.lock
✅ 提交到版本控制
原因: 确保团队成员使用相同版本的依赖
4. 清理无用依赖
定期检查 pubspec.yaml,删除不再使用的包。
📝 常见问题
Q1: 为什么要有 pubspec.lock 文件?
A: pubspec.lock 锁定了具体版本,确保:
- 团队成员使用相同版本
- CI/CD 构建一致性
- 避免意外升级导致的问题
对比:
# pubspec.yaml (约束)
dependencies:
http: ^1.0.0 # 允许 1.0.0 到 2.0.0
# pubspec.lock (具体版本)
packages:
http:
version: "1.0.5" # 锁定具体版本
Q2: pub get 和 pub upgrade 的区别?
| 命令 | 行为 |
|---|---|
pub get | 根据 pubspec.lock 下载,没有则解析 pubspec.yaml |
pub upgrade | 忽略 pubspec.lock,下载最新兼容版本 |
Q3: 如何解决版本冲突?
场景: 两个包依赖同一个包的不同版本
你的应用 → package_a: ^1.0.0 → http: ^0.13.0
→ package_b: ^2.0.0 → http: ^1.0.0
❌ 冲突!
解决方案:
- 升级冲突的包
dependency_overrides:
http: ^1.0.0 # 强制使用指定版本
-
联系包作者更新依赖
-
等待包更新或切换到其他包
Q4: 本地依赖的路径找不到?
错误:
Could not find a file named "pubspec.yaml" in ...
解决:
- 检查路径是否正确
- 使用绝对路径测试
- 确保目标目录有
pubspec.yaml
Q5: Git 依赖下载很慢?
解决方案:
- 使用国内镜像
# 设置环境变量
export PUB_HOSTED_URL=https://pub.flutter-io.cn
export FLUTTER_STORAGE_BASE_URL=https://storage.flutter-io.cn
- 使用 SSH 代替 HTTPS
dependencies:
my_package:
git:
url: git@github.com:username/my_package.git # SSH
🎓 跟着做练习
练习1:添加并使用 intl 包 ⭐⭐
目标: 学习日期格式化
步骤:
- 添加依赖到
pubspec.yaml
dependencies:
intl: ^0.18.0
- 下载包
flutter pub get
- 使用 intl 格式化日期
import 'package:intl/intl.dart';
class DateFormatExample extends StatelessWidget {
@override
Widget build(BuildContext context) {
final now = DateTime.now();
// 格式化日期
final formatter1 = DateFormat('yyyy-MM-dd HH:mm:ss');
final formatter2 = DateFormat('yyyy年MM月dd日');
final formatter3 = DateFormat.yMMMd('zh_CN');
return Column(
children: [
Text('格式1: ${formatter1.format(now)}'),
Text('格式2: ${formatter2.format(now)}'),
Text('格式3: ${formatter3.format(now)}'),
],
);
}
}
预期输出:
格式1: 2024-01-15 14:30:25
格式2: 2024年01月15日
格式3: 2024年1月15日
练习2:添加并使用 uuid 包 ⭐⭐
目标: 生成唯一ID
步骤:
- 添加依赖
dependencies:
uuid: ^4.0.0
- 生成 UUID
import 'package:uuid/uuid.dart';
class UuidExample extends StatelessWidget {
@override
Widget build(BuildContext context) {
var uuid = const Uuid();
return Column(
children: [
Text('UUID v1: ${uuid.v1()}'),
Text('UUID v4: ${uuid.v4()}'),
Text('UUID v5: ${uuid.v5(Uuid.NAMESPACE_URL, 'flutter.dev')}'),
],
);
}
}
预期输出:
UUID v1: 550e8400-e29b-41d4-a716-446655440000
UUID v4: 6ba7b810-9dad-11d1-80b4-00c04fd430c8
UUID v5: 3d813cbb-47fb-32ba-91df-831e1593ac29