开篇:Flutter 生态的力量
Flutter 的繁荣很大程度上归功于其包生态系统。pub.dev 上有超过 3 万个包,覆盖了从 UI 组件到原生能力扩展的方方面面。作为 Flutter 开发者,你不仅要学会使用这些包,更要掌握如何创建和发布自己的包——这既能解决重复代码的问题,也是回馈社区的方式。
本章将介绍两种包类型:纯 Dart 的 Package(可跨所有平台)和包含原生代码的 Plugin(Android/iOS/macOS/Linux/Windows/Web),并涵盖发布流程、版本管理和最佳实践。
一、Package 与 Plugin 的区别
| 类型 | 组成 | 平台支持 | 典型例子 |
|---|---|---|---|
| Dart Package | 纯 Dart 代码 | 所有平台 | dio, intlx, animations |
| Flutter Package | Dart + 资源文件 | 所有平台 | flutter_svg, lottie |
| Plugin Package | Dart + 原生代码 + 多平台实现 | 支持的平台 | path_provider, shared_preferences |
一句话总结:纯逻辑用 Package,需要原生能力用 Plugin,优先 Dart 实现以降低维护成本。
二、创建 Dart Package
# 创建纯 Dart 包
flutter create --template=package my_utils
cd my_utils
// lib/my_utils.dart
library my_utils;
export 'src/validators.dart';
export 'src/formatters.dart';
export 'src/extensions.dart';
// lib/src/validators.dart
class Validators {
static bool isValidEmail(String email) {
return RegExp(r'^[\w.-]+@[\w.-]+\.\w+$').hasMatch(email);
}
static bool isValidPhone(String phone) {
return RegExp(r'^1[3-9]\d{9}$').hasMatch(phone);
}
static bool isEmpty(String? value) => value?.trim().isEmpty ?? true;
}
// lib/src/extensions.dart
extension StringUtils on String {
String truncate(int length, {String suffix = '...'}) {
if (this.length <= length) return this;
return '${substring(0, length - suffix.length)}$suffix';
}
String capitalize() {
if (isEmpty) return this;
return '${this[0].toUpperCase()}${substring(1)}';
}
}
// test/my_utils_test.dart
import 'package:test/test.dart';
import 'package:my_utils/my_utils.dart';
void main() {
group('Validators', () {
test('validates email correctly', () {
expect(Validators.isValidEmail('test@example.com'), isTrue);
expect(Validators.isValidEmail('invalid'), isFalse);
});
});
group('String extensions', () {
test('truncates long strings', () {
expect('Hello World'.truncate(8), equals('Hello...'));
});
});
}
一句话总结:Dart Package 的 src/ 目录下文件默认私有,通过 lib/ 根级的 export 暴露公共 API,是最清晰的模块边界设计。
三、创建 Plugin
# 创建多平台插件
flutter create --template=plugin \
--platforms=android,ios,macos,windows,linux \
flutter_my_sensor
// lib/flutter_my_sensor.dart
import 'flutter_my_sensor_platform_interface.dart';
class FlutterMySensor {
Future<SensorData> readAccelerometer() async {
return FlutterMySensorPlatform.instance.readAccelerometer();
}
}
// lib/flutter_my_sensor_platform_interface.dart
abstract class FlutterMySensorPlatform extends PlatformInterface {
// ...
Future<SensorData> readAccelerometer();
}
一句话总结:Flutter Plugin 遵循"Dart API + Platform Interface + 各平台实现"的分层架构,确保多平台的一致性和可测试性。
四、pub.dev 发布流程
# pubspec.yaml
name: my_awesome_package
version: 1.0.0
description: A brief description of my package
homepage: https://github.com/username/package
repository: https://github.com/username/package
issue_tracker: https://github.com/username/package/issues
dependencies:
flutter:
sdk: flutter
dev_dependencies:
flutter_test:
sdk: flutter
flutter:
# 如果有资源文件
# 1. 登录 pub.dev(仅首次)
flutter pub login
# 2. 检查包质量
flutter pub publish --dry-run
# 3. 正式发布
flutter pub publish
# 4. 版本遵循 SemVer
# 1.0.0 -> 1.0.1 (patch) -> 1.1.0 (minor) -> 2.0.0 (major)
五、代码生成(build_runner)
# pubspec.yaml
dependencies:
json_annotation: ^4.8.0
freezed_annotation: ^2.4.0
dev_dependencies:
build_runner: ^2.4.0
json_serializable: ^6.7.0
freezed: ^2.4.0
// lib/models/user.dart
import 'package:freezed_annotation/freezed_annotation.dart';
part 'user.freezed.dart';
part 'user.g.dart';
@freezed
class User with _$User {
const factory User({
required String id,
required String name,
String? email,
@Default([]) List<String> roles,
}) = _User;
factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
}
// 生成代码
// dart run build_runner build --delete-conflicting-outputs
一句话总结:build_runner 配合注解消除了 Dart 中的样板代码,代码生成已成为 Flutter 生态的标准实践。
FAQ
Q1: Package 命名有什么规范?
- 小写 + 下划线分隔(snake_case)
- 前缀避免与他人冲突(如
companyname_feature) - 描述性:一看就知道用途
Q2: 如何管理本地依赖?
dependencies:
my_local_package:
path: ../my_local_package
git_package:
git:
url: https://github.com/user/repo.git
ref: main
Q3: 发布后发现 bug 怎么办?
- 紧急修复:发布 patch 版本(1.0.1)
- 回退版本:
flutter pub downgrade my_package(用户侧) - 撤回包:pub.dev 不支持撤回,只能发布新版本修复
相关阅读
- https://plumephp.com/flutter-platform-channels/ — 平台通道与原生交互
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。