================================================================================
下面我们从纯 Flutter 项目的 app 编译安卓端 apk 流程说起。
[](()settings.gradle
源码流程分析
既然是安卓的编译流程,那就先从android/settings.gradle
看起,如下:
// 当前 app module
include ‘:app’
/**
-
1、读取android/local.properties文件内容
-
2、获取flutter.sdk的值,也就是你本地flutter SDK安装目录
-
3、gradle 脚本常规操作 apply flutter SDK路径下/packages/flutter_tools/gradle/app_plugin_loader.gradle文件
*/
def localPropertiesFile = new File(rootProject.projectDir, “local.properties”)
def properties = new Properties()
assert localPropertiesFile.exists()
localPropertiesFile.withReader(“UTF-8”) { reader -> properties.load(reader) }
def flutterSdkPath = properties.getProperty(“flutter.sdk”)
assert flutterSdkPath != null, “flutter.sdk not set in local.properties”
apply from: “$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle”
通过上面步骤我们可以将目光转向你 Flutter SDK 安装目录下的/packages/flutter_tools/gradle/app_plugin_loader.gradle
文件,内容如下:
import groovy.json.JsonSlurper
//得到自己新建的 flutter 项目的根路径,因为已经被自己新建的 project apply,所以这里是项目根路径哦
def flutterProjectRoot = rootProject.projectDir.parentFile
//获取自己项目根路径下的.flutter-plugins-dependencies json配置文件
// Note: if this logic is changed, also change the logic in module_plugin_loader.gradle.
def pluginsFile = new File(flutterProjectRoot, ‘.flutter-plugins-dependencies’)
if (!pluginsFile.exists()) {
return
}
/**
-
1、通过groovy的JsonSlurper解析json文件内容。
-
2、简单校验json内容字段的类型合法性。
-
3、把安卓平台依赖的Flutter plugins全部自动include进来
*/
def object = new JsonSlurper().parseText(pluginsFile.text)
assert object instanceof Map
assert object.plugins instanceof Map
assert object.plugins.android instanceof List
// Includes the Flutter plugins that support the Android platform.
object.plugins.android.each { androidPlugin ->
assert androidPlugin.name instanceof String
assert androidPlugin.path instanceof String
def pluginDirectory = new File(androidPlugin.path, ‘android’)
assert pluginDirectory.exists()
include “😒{androidPlugin.name}”
project(“😒{androidPlugin.name}”).projectDir = pluginDirectory
}
上面的 gradle 脚本很简单,大家看注释即可。为了直观说明问题,这里新建了一个典型 demo 项目,然后其pubspec.yaml
文件依赖配置如下:
dependencies:
flutter:
sdk: flutter
dio: ^4.0.0 #来自pub.dev仓库的Flutter Package包
webview_flutter: ^2.0.10 #来自pub.dev仓库的Flutter Plugin包
f_package: #来自自己本地新建的Flutter Package包
path: ./…/f_package
f_plugin: #来自自己本地新建的Flutter Plugin包
path: ./…/f_plugin
接着我们看看这个项目根路径的.flutter-plugins-dependencies
文件,如下:
{
“info”:“This is a generated file; do not edit or check into version control.”,
“plugins”:{
“ios”:[
{“name”:“f_plugin”,“path”:“E:\\f_plugin\\”,“dependencies”:[]},
{“name”:“webview_flutter”,“path”:“D:\\software\\flutter\\flutter\\.pub-cache\\hosted\\pub.dartlang.org\\webview_flutter-2.0.10\\”,“dependencies”:[]}
],
“android”:[
{“name”:“f_plugin”,“path”:“E:\\f_plugin\\”,“dependencies”:[]},
{“name”:“webview_flutter”,“path”:“D:\\software\\flutter\\flutter\\.pub-cache\\hosted\\pub.dartlang.org\\webview_flutter-2.0.10\\”,“dependencies”:[]}
],
“macos”:[],
“linux”:[],
“windows”:[],
“web”:[
{“name”:“f_plugin”,“path”:“E:\\f_plugin\\”,“dependencies”:[]}
]
},
“dependencyGraph”:[
{“name”:“f_plugin”,“dependencies”:[]},
{“name”:“webview_flutter”,“dependencies”:[]}
],
“date_created”:“202x-0x-15 21:41:39.225336”,
“version”:“2.2.3”
}
这时候我们回过头去看自己项目android/settings.gradle
,在 Gradle 生命周期的初始化阶段(即解析settings.gradle
),我们项目的settings.gradle
经过apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle"
处理后自动变成如下伪代码:
include ‘:app’
// 自动通过匹配依赖然后app_plugin_loader.gradle解析生成
//include “😒{androidPlugin.name}”
//project(“😒{androidPlugin.name}”).projectDir = pluginDirectory
include “:f_plugin”
project(“:f_plugin”).projectDir = new File(“E:\\f_plugin\\”, ‘android’)
include “:webview_flutter”
project(“:webview_flutter”).projectDir = new File(“D:\\software\\flutter\\flutter\\.pub-cache\\hosted\\pub.dartlang.org\\webview_flutter-2.0.10\\”, ‘android’)
咋说!是不是一下就恍然大悟了,其实就是“约定大于配置”的软件工程原则,你只管按照规则摆放,本质最后都是我们平时标准 Android 项目那样。
[](()build.gradle
源码流程分析
先看项目 android 下根目录的build.gradle
,如下:
//…省略无关紧要的常见配置
// 看到了吧,他将所有 android 依赖的构建产物挪到了根目录下的 build 中,所以产物都在那儿
rootProject.buildDir = ‘…/build’
subprojects {
project.buildDir = “rootProject.buildDir/{rootProject.buildDir}/rootProject.buildDir/{project.name}”
project.evaluationDependsOn(‘:app’) //运行其他配置之前,先运行app依赖
}
接着我们看看 app 模块下的build.gradle
,如下:
/**
-
1、读取local.properties配置信息。
-
2、获取flutter.sdk路径。
-
3、获取flutter.versionCode值,此值在编译时自动从pubspec.yaml中读取赋值,所以修改版本号请修改yaml。
-
4、获取flutter.versionName值,此值在编译时自动从pubspec.yaml中读取赋值,所以修改版本号请修改yaml。
*/
def localProperties = new Properties()
def localPropertiesFile = rootProject.file(‘local.properties’)
if (localPropertiesFile.exists()) {
localPropertiesFile.withReader(‘UTF-8’) { reader -&g