Flutter开发包和插件

介绍一下包

使用package可以创建共享的模块化代码。一个最小的package包括:

  • 一个pubspeck.yaml文件:声明了package的名称、版本、和作者等的元数据文件。
  • 一个lib文件夹:包括公开的pubulic代码,最少应该有一个<package-name>.dart文件。

Flutter Packages分为两类:

  • Dart包:其中一些可能包含Flutter的特定功能,因此对Flutter框架具有依赖性,这种包仅用于Flutter。
  • 插件包:一种专用的Dart包,其中包含Dart编写的API,以及针对安卓和iOS平台的特定实现,就是说插件包括原生代码。

开发Dart Packages

第一步创建Dart包

你可以使用如下命令创建DartPackages

1
flutter create -template=package charles_package

这将在charles_package/文件夹下创建一个具有以下专用内容的package工程:

  • lib/mypackage.dart: Package的Dart代码
  • test/charles_package_test.dart: Package的单元测试代码。
实现Package

对于纯Dart包,只需要在lib/.dart文件内或lib目录中的文件中添加功能即可。要测试软件包,请在test目录中添加unit tests。

下面我们看看如何组织package包的代码,以shelf package为例,它的目录结构如下:

image

在lib根目录下的shelf.dart中导出了多个lib/src目录下的dart文件:

1
2
3
4
5
6
7
8
9
10
export 'src/cascade.dart';
export 'src/handler.dart';
export 'src/handles/logger.dart';
export 'src/hijack_exception.dart';
export 'src/middleware.dart';
export 'src/pipleline.dart';
export 'src/request.dart';
export 'src/response.dart';
export 'src/server.dart';
export 'src/server_handler.dart';

而package中主要的功能源码都在src下。shelf package也导出了一个mini库:shelf_io,它主要是处理HttpRequest的。

导入包,当需要使用这个package时,我们可以通过package:指令来指定包的入口文件:

1
import 'pakcage:utilities/utilities.dart';

同一个包中的源码文件之间也可以使用相对路径来导入。

生成文档

可以使用dartdoc工具来为package生成文档,开发者需要做的就是遵守文档注释语法在代码中添加文档注释,最后使用dartdoc可以直接生成API文档(一个静态网站)。文档注释是使用三斜线’///‘开始,如:

1
2
3
4
/// The event handler responseible for updating the badge in the UI.
void updateBadge(){
...
}
处理包的相互依赖

如果我们正在开发一个charles_package包,它依赖于另一个包,则需要将该依赖包添加到pubspec.yaml文件的dependencies部分。这与在Flutter 应用程序或任何其他Dart项目中引用软件包没有什么不同。但是,如果charles_package包碰巧是一个插件包,其平台特定的代码需要访问url_launcher公开的特定于平台的API,那么我们还需要为特定于平台的构建文件添加合适的依赖声明,如下所示:

Android

charles_package/android/build.gradle:

1
2
3
4
5
android{
dependencies{
provided rootProject.findProject(":url_launcher")
}
}

您现在就可以在charles_package/android/src源码中import io.flutter.plugins.urllauncher.UrlLauncherPlugin访问UrlLauncherPlugin类

iOS

charles_package/ios/charles_package.podspec:

1
2
Pod::Spec.new do |s|
s.dependency 'url_launcher'

你现在就可以在charles_package/ios/classes源码中 #import "UrlLauncherPlugin.h" 然后访问UrlLauncherPlugin类。

解决依赖冲突

假设我们想在charles_package包中使用some_packageother_package,并且这两个包都依赖url_launcher,但是依赖的是url_launcher的不同版本。那我们就有潜在冲突。避免这种情况的最好方法是在指定依赖关系时,使用版本范围而不是特定版本。

1
2
3
dependencies:
url_launcher:'^0.4.2'
image_picker:'0.1.1'

如果some_package声明了上面的依赖关系,other_package声明了url_launcher版本像’0.4.5’或’^0.4.0’时,pub将能够自动解决问题。

即使some_packageother_package声明了不兼容的url_lancher版本,它仍然可能会和url_launcher以兼容的方式正常工作。你可以通过向charles_package包的pubspeck.yaml文件中添加依赖性覆盖声明来处理冲突,从而强制使用特定版本:

强制使用0.4.3版本的url_lancher,在charles_package/pubspec.yaml中:

1
2
3
4
5
dependencies:
some_package:
other_package:
dependency_overrides:
url_launcher:'0.4.3'

如果冲突依赖不是一个包,而是一个特定于Android的库,比如guava,那么必须将依赖重写声明添加到Gradle构建逻辑中。

强制使用23.0版本的guava库,在charles_package/android/build.gradle中:

1
2
3
4
5
configurations.all{
resolutionStrategy{
force 'com.google.guava:guava:23.0-android'
}
}

Cocoapods目前不提供依赖覆盖功能。

发布Package

一旦实现了一个包,我们可以在Pub上发布它,这样其他开发者可以轻松使用它。

在发布前,检查pubspec.yamlREADME.md以及CHANGELOG.md文件,以确保其内容的完整性和正确性。然后运行dry-run命令以查看是否都准备好了。

1
flutter packages pub publish --dry-run

验证无误后,我们就可以运行发布命令了:

1
flutter pakcages pub publish
谢谢您的支持!