// 读取local.propertiesdef localProperties =newProperties()def localPropertiesFile = rootProject.file('local.properties')if(localPropertiesFile.exists()){
localPropertiesFile.withReader('UTF-8'){
reader ->
localProperties.load(reader)}}// 读取flutter sdk路径def flutterRoot = localProperties.getProperty('flutter.sdk')if(flutterRoot == null){
thrownewGradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")}// 读取flutter.versionCode,该值读取:pubspec.yaml 文件中:version 值// 比如:version: 1.0.0+11,versionCode为:11def flutterVersionCode = localProperties.getProperty('flutter.versionCode')if(flutterVersionCode == null){
flutterVersionCode ='1'}// 读取flutter.versionName,该值读取:pubspec.yaml 文件中:version 值// 比如:version: 1.0.0+11,versionName为:1.0.0def flutterVersionName = localProperties.getProperty('flutter.versionName')if(flutterVersionName == null){
flutterVersionName ='1.0'}//声明为 application
apply plugin:'com.android.application'
apply plugin:'kotlin-android'//应用flutter.gradle flutter编译的核心问题,主要作用是在android构建流程的task中加入flutter编译相关的task
apply from:"$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
android {
compileSdkVersion 30
sourceSets {
main.java.srcDirs +='src/main/kotlin'}
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "com.example.helloFlutter.hello_flutter"
minSdkVersion 16
targetSdkVersion 30//赋值为上面从pubspec.yaml读取到的相关值
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
}
buildTypes {
release {
// TODO: Add your own signing config for the release build.// Signing with the debug keys for now, so `flutter run --release` works.
signingConfig signingConfigs.debug
}}}//一个拓展配置,指定source路径为当前的两级父级,也就是项目根目录
flutter {
source '../..'}
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"}
5. flutter.gradle 核心源码(大意看注释)
......省略部分.....//应用 FLutterPlugin gradle插件
apply plugin: FlutterPlugin
//上面应用的FlutterPlugin插件实现源码classFlutterPluginimplementsPlugin<Project>{
......省略部分......//核心方法!!!!!!!!!!@Overridevoidapply(Project project){
this.project = project
// 配置maven仓库地址,环境变量有配置FLUTTER_STORAGE_BASE_URL就优先用,没就缺省值
String hostedRepository = System.env.FLUTTER_STORAGE_BASE_URL ?: DEFAULT_MAVEN_HOST
String repository =useLocalEngine()? project.property('local-engine-repo'):"$hostedRepository/download.flutter.io"
project.rootProject.allprojects {
repositories {
maven {
url repository
}}}// 创建app模块中配置的flutter{ source: '../../'}闭包extensions // source:用来配置当前Flutter工程的根路径,注意不是Android工程,如果没有配置抛出Must provide Flutter source directory异常// target:用来指定Flutter代码的启动入口,如果没有配置默认为lib/main.dart
project.extensions.create("flutter", FlutterExtension)//添加flutter构建相关的各种task//文章最开始提到的构建流程最后执行阶段添加的几个flutter相关的task就是在这里添加:eg,// app:compileFlutterBuildDebug// app:packLibsflutterBuildDebug// app:copyFlutterAssetsDebug// 后面单独分析this.addFlutterTasks(project)// By default, assembling APKs generates fat APKs if multiple platforms are passed.// Configuring split per ABI allows to generate separate APKs for each abi.// This is a noop when building a bundle.// 判断是否根据(abi)分包编译if(shouldSplitPerAbi()){
project.android {
splits {
abi {
// Enables building multiple APKs per ABI.
enable true// Resets the list of ABIs that Gradle should create APKs for to none.reset()// Specifies that we do not want to also generate a universal APK that includes all ABIs.
universalApk false}}}}//判断编译命令是否添加--target-platform=xxxABI参数,没有就用缺省,有就看这个ABI是否flutter支持的,支持就配置,否则抛出异常getTargetPlatforms().each {
targetArch ->
String abiValue = PLATFORM_ARCH_MAP[targetArch]
project.android {
if(shouldSplitPerAbi()){
splits {
abi {
include abiValue
}}}}}//通过属性配置获取flutter.sdk,或者通过环境变量FLUTTER_ROOT获取,都没有就抛出环境异常
String flutterRootPath =resolveProperty("flutter.sdk", System.env.FLUTTER_ROOT)if(flutterRootPath == null){
thrownewGradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file or with a FLUTTER_ROOT environment variable.")}
flutterRoot = project.file(flutterRootPath)if(!flutterRoot.isDirectory()){
thrownewGradleException("flutter.sdk must point to the Flutter SDK directory")}//获取Flutter Engine的版本号,如果通过local-engine-repo参数使用本地自己编译的Engine则版本为+,否则读取SDK目录下bin\internal\engine.version文件值,一串类似MD5的值
engineVersion =useLocalEngine()?"+"// Match any version since there's only one.:"1.0.0-"+ Paths.get(flutterRoot.absolutePath,"bin","internal","engine.version").toFile().text.trim()//依据平台获取对应flutter命令脚本,都位于SDK目录下bin\中,名字为flutter
String flutterExecutableName = Os.isFamily(Os.FAMILY_WINDOWS)?"flutter.bat":"flutter"
flutterExecutable = Paths.get(flutterRoot.absolutePath,"bin", flutterExecutableName).toFile();//获取flutter混淆配置清单,位于SDK路径下packages\flutter_tools\gradle\flutter_proguard_rules.pro//里面配置只有 -dontwarn io.flutter.plugin.** 和 -dontwarn android.**
String flutterProguardRules = Paths.get(flutterRoot.absolutePath,"packages","flutter_tools","gradle","flutter_proguard_rules.pro")//新增profile构建类型,在当前project下的android.buildTypes中进行配置
project.android.buildTypes {
// Add profile build type.
profile {
initWith debug
if(it.hasProperty("matchingFallbacks")){
matchingFallbacks =["debug","release"]}}
release {
// Enables code shrinking, obfuscation, and optimization for only// your project's release build type.
minifyEnabled true// Enables resource shrinking, which is performed by the// Android Gradle plugin.// NOTE: The resource shrinker can't be used for libraries.
shrinkResources isBuiltAsApp(project)// Fallback to `android/app/proguard-rules.pro`.// This way, custom Proguard rules can be configured as needed.
proguardFiles project.android.getDefaultProguardFile("proguard-android.txt"), flutterProguardRules,"proguard-rules.pro"}}if(useLocalEngine()){
// This is required to pass the local engine to flutter build aot.
String engineOutPath = project.property('local-engine-out')
File engineOut = project.file(engineOutPath)if(!engineOut.isDirectory()){
thrownewGradleException('local-engine-out must point to a local engine build')}
localEngine = engineOut.name
localEngineSrcPath = engineOut.parentFile.parent
}//给所有buildTypes添加依赖,addFlutterDependencies
project.android.buildTypes.all this.&addFlutterDependencies
}/**
* Adds the dependencies required by the Flutter project.
* This includes:
* 1. The embedding
* 2. libflutter.so
*/voidaddFlutterDependencies(buildType){
//获取flutter build类型,值为debug、profile、release
String flutterBuildMode =buildModeFor(buildType)if(!supportsBuildMode(flutterBuildMode)){
return}// The embedding is set as an API dependency in a Flutter plugin.// Therefore, don't make the app project depend on the embedding if there are Flutter// plugins.// This prevents duplicated classes when using custom build types. That is, a custom build// type like profile is used, and the plugin and app projects have API dependencies on the// embedding.// 如果插件不是applicationVariants类型,即android library,或者项目根目录下`.flutter-plugins`文件中安卓插件个数为空if(!isFlutterAppProject()||getPluginList().size()==0){
// 给Flutter Plugin的android插件添加编译依赖// 譬如io.flutter:flutter_embedding_debug:1.0.addApiDependencies(project, buildType.name,"io.flutter:flutter_embedding_$flutterBuildMode:$engineVersion")}// 给project添加对应编译依赖// 譬如io.flutter:arm64_v8a_debug:1.0.0,来自maven仓库
List<String> platforms =getTargetPlatforms().collect()// Debug mode includes x86 and x64, which are commonly used in emulators.if(flutterBuildMode =="debug"&&!useLocalEngine()){
platforms.add("android-x86")
platforms.add("android-x64")}
platforms.each {
platform ->
String arch = PLATFORM_ARCH_MAP[platform].replace("-","_")// Add the `libflutter.so` dependency.addApiDependencies(project, buildType.name,"io.flutter:${arch}_$flutterBuildMode:$engineVersion")}}......省略部分.....//接下来再单独分析核心部分:addFlutterTasks方法
6. 接下来我们再看看flutter.gradle的addFlutterTasks方法:
privatevoidaddFlutterTasks(Project project){
if(project.state.failure){
return}.....此处省略一堆属性获取与赋值操作......// 定义 addFlutterDeps 函数,参数variant为标准构建对应的构建类型def addFlutterDeps ={
variant ->if(shouldSplitPerAbi()){
//常规操作:如果是构建多个变体apk模式就处理vc问题
variant.outputs.each {
output ->//确保每个APK都有自己唯一的versionCode,这里就是做这个事情的//具体可以看官方文档 https://developer.android.com/studio/build/configure-apk-splitsdef abiVersionCode = ABI_VERSION.get(output.getFilter(OutputFile.ABI))if(abiVersionCode != null){
output.versionCodeOverride =
abiVersionCode *1000+ variant.versionCode
}}}//获取编译类型,variantBuildMode值为debug、profile、release之一
String variantBuildMode =buildModeFor(variant.buildType)//依据参数生成一个task名字,譬如这里的compileFlutterBuildDebug、compileFlutterBuildProfile、compileFlutterBuildRelease//参照文章开始最后执行阶段添加的flutter task名字就是在这里确认的
String taskName =toCammelCase(["compile", FLUTTER_BUILD_PREFIX, variant.name])// 给当前project创建compileFlutterBuildDebug、compileFlutterBuildProfile、compileFlutterBuildRelease Task// 实现为FlutterTask,主要用来编译Flutter代码,这个task稍后单独分析
FlutterTask compileTask = project.tasks.create(name: taskName, type: FlutterTask){
// 各种task属性赋值操作,基本都来自上面的属性获取或者匹配分析
flutterRoot this.flutterRoot
flutterExecutable this.flutterExecutable
buildMode variantBuildMode
localEngine this.localEngine
localEngineSrcPath this.localEngineSrcPath
// 默认dart入口lib/main.dart、可以通过target属性自定义指向
targetPath getFlutterTarget()
verbose isVerbose()
fastStart isFastStart()
fileSystemRoots fileSystemRootsValue
fileSystemScheme fileSystemSchemeValue
trackWidgetCreation trackWidgetCreationValue
targetPlatformValues = targetPlatforms
sourceDir getFlutterSourceDirectory()// flutter中间产物目录
intermediateDir project.file("${project.buildDir}/${AndroidProject.FD_INTERMEDIATES}/flutter/${variant.name}/")
extraFrontEndOptions extraFrontEndOptionsValue
extraGenSnapshotOptions extraGenSnapshotOptionsValue
splitDebugInfo splitDebugInfoValue
treeShakeIcons treeShakeIconsOptionsValue
dartObfuscation dartObfuscationValue
dartDefines dartDefinesValue
bundleSkSLPath bundleSkSLPathValue
performanceMeasurementFile performanceMeasurementFileValue
codeSizeDirectory codeSizeDirectoryValue
// 权限相关处理
doLast {
project.exec {
if(Os.isFamily(Os.FAMILY_WINDOWS)){
commandLine('cmd','/c',"attrib -r ${assetsDirectory}/* /s")}else{
commandLine('chmod','-R','u+w', assetsDirectory)}}}}// 项目构建中间产物的文件,也就是根目录下build/intermediates/flutter/debug/libs.jar文件
File libJar = project.file("${project.buildDir}/${AndroidProject.FD_INTERMEDIATES}/flutter/${variant.name}/libs.jar")// 创建packLibsFlutterBuildProfile、packLibsFlutterBuildDebug、packLibsFlutterBuildRelease任务,主要是产物的复制挪位置操作,作用就是把build/intermediates/flutter/debug/下依据abi生成的app.so通过jar命令打包成build/intermediates/flutter/debug/libs.jar
Task packFlutterAppAotTask = project.tasks.create(name:"packLibs${FLUTTER_BUILD_PREFIX}${variant.name.capitalize()}", type: Jar){
// 目标路径为build/intermediates/flutter/debug目录
destinationDir libJar.parentFile
// 文件名为libs.jar
archiveName libJar.name
// 依赖前面定义的compileTask,也就是说,这个task基本作用是产物处理
dependsOn compileTask
// targetPlatforms取值为android-arm、android-arm64、android-x86、android-x64
targetPlatforms.each {
targetPlatform ->// abi取值为armeabi-v7a、arm64-v8a、x86、x86_64
String abi = PLATFORM_ARCH_MAP[targetPlatform]// 数据来源来自compileTask任务中间产物目录// 即把build/intermediates/flutter/debug/下依据abi生成的app.so通过jar命令打包成一个build/intermediates/flutter/debug/libs.jar文件from("${compileTask.intermediateDir}/${abi}"){
include "*.so"// Move `app.so` to `lib//libapp.so`
rename {
String filename ->return"lib/${abi}/lib${filename}"}}}}// 前面有介绍过addApiDependencies作用,把 packFlutterAppAotTask 产物加到依赖项里面参与编译// 类似implementation files('libs.jar'),然后里面的so会在项目执行标准mergeDebugNativeLibs task时打包进标准lib目录addApiDependencies(project, variant.name, project.files {
packFlutterAppAotTask
})// We build an AAR when this property is defined.// 当构建有is-plugin属性时则编译aarboolean isBuildingAar = project.hasProperty('is-plugin')// In add to app scenarios, a Gradle project contains a `:flutter` and `:app` project.// We know that `:flutter` is used as a subproject when these tasks exists and we aren't building an AAR.// 当是Flutter Module方式,即Flutter以aar作为已存在native安卓项目依赖时才有这些:flutter:模块依赖,否则没有这些task// 可以参见新建的FlutterModule中.android/include_flutter.groovy中gradle.project(":flutter").projectDir实现
Task packageAssets = project.tasks.findByPath(":flutter:package${variant.name.capitalize()}Assets")
Task cleanPackageAssets = project.tasks.findByPath(":flutter:cleanPackage${variant.name.capitalize()}Assets")// 判断是否为FlutterModule依赖boolean isUsedAsSubproject = packageAssets && cleanPackageAssets &&!isBuildingAar
// 新建copyFlutterAssetsDebug task,目的就是copy产物,也就是assets归档// 常规merge中间产物类似,compileTask产物的assets目录在mergeAssets时复制到主包中间产物目录
Task copyFlutterAssetsTask = project.tasks.create(
name:"copyFlutterAssets${variant.name.capitalize()}",
type: Copy,){
dependsOn compileTask
with compileTask.assets
if(isUsedAsSubproject){
dependsOn packageAssets
dependsOn cleanPackageAssets
into packageAssets.outputDir
return}// `variant.mergeAssets` will be removed at the end of 2019.def mergeAssets = variant.hasProperty("mergeAssetsProvider")?
variant.mergeAssetsProvider.get(): variant.mergeAssets
dependsOn mergeAssets
dependsOn "clean${mergeAssets.name.capitalize()}"
mergeAssets.mustRunAfter("clean${mergeAssets.name.capitalize()}")
into mergeAssets.outputDir
}if(!isUsedAsSubproject){
def variantOutput = variant.outputs.first()def processResources = variantOutput.hasProperty("processResourcesProvider")?
variantOutput.processResourcesProvider.get(): variantOutput.processResources
processResources.dependsOn(copyFlutterAssetsTask)}return copyFlutterAssetsTask
}// 判断是否是applicationVariantsif(isFlutterAppProject()){
project.android.applicationVariants.all {
variant ->// 获取是assemble task咯
Task assembleTask =getAssembleTask(variant)if(!shouldConfigureFlutterTask(assembleTask)){
return}//把前面定义的addFlutterDeps函数调用返回的copyFlutterAssetsTask任务拿到作为依赖项
Task copyFlutterAssetsTask =addFlutterDeps(variant)def variantOutput = variant.outputs.first()def processResources = variantOutput.hasProperty("processResourcesProvider")?
variantOutput.processResourcesProvider.get(): variantOutput.processResources
processResources.dependsOn(copyFlutterAssetsTask)// Copy the output APKs into a known location, so `flutter run` or `flutter build apk`// can discover them. By default, this is `/build/app/outputs/flutter-apk/.apk`.//// The filename consists of `app<-abi>?<-flavor-name>?-.apk`.// Where:// * `abi` can be `armeabi-v7a|arm64-v8a|x86|x86_64` only if the flag `split-per-abi` is set.// * `flavor-name` is the flavor used to build the app in lower case if the assemble task is called.// * `build-mode` can be `release|debug|profile`.// 执行flutter run或者flutter build apk的产物apk归档处理
variant.outputs.all {
output ->
assembleTask.doLast {
// `packageApplication` became `packageApplicationProvider` in AGP 3.3.0.def outputDirectory = variant.hasProperty("packageApplicationProvider")? variant.packageApplicationProvider.get().outputDirectory
: variant.packageApplication.outputDirectory
// `outputDirectory` is a `DirectoryProperty` in AGP 4.1.
String outputDirectoryStr = outputDirectory.metaClass.respondsTo(outputDirectory,"get")? outputDirectory.get(): outputDirectory
String filename ="app"
String abi = output.getFilter(OutputFile.ABI)if(abi != null &&!abi.isEmpty()){
filename +="-${abi}"}if(variant.flavorName != null &&!variant.flavorName.isEmpty()){
filename +="-${variant.flavorName.toLowerCase()}"}
filename +="-${buildModeFor(variant.buildType)}"
project.copy {
from newFile("$outputDirectoryStr/${output.outputFileName}")
into newFile("${project.buildDir}/outputs/flutter-apk");
rename {
return"${filename}.apk"}}}}}configurePlugins()return}// Flutter host module project (Add-to-app).// 是不是模块源码依赖方式集成到现有项目,参见 https://flutter.cn/docs/development/add-to-app/android/project-setup// 是的话对模块也做类似一堆处理即可,不再重复分析了,也是 assets 合并
String hostAppProjectName = project.rootProject.hasProperty('flutter.hostAppProjectName')? project.rootProject.property('flutter.hostAppProjectName'):"app"
Project appProject = project.rootProject.findProject(":${hostAppProjectName}")assert appProject != null :"Project :${hostAppProjectName} doesn't exist. To custom the host app project name, set `org.gradle.project.flutter.hostAppProjectName=` in gradle.properties."// Wait for the host app project configuration.
appProject.afterEvaluate {
assert appProject.android != null
project.android.libraryVariants.all {
libraryVariant ->
Task copyFlutterAssetsTask
appProject.android.applicationVariants.all {
appProjectVariant ->
Task appAssembleTask =getAssembleTask(appProjectVariant)if(!shouldConfigureFlutterTask(appAssembleTask)){
return}// Find a compatible application variant in the host app.//// For example, consider a host app that defines the following variants:// | ----------------- | ----------------------------- |// | Build Variant | Flutter Equivalent Variant |// | ----------------- | ----------------------------- |// | freeRelease | relese |// | freeDebug | debug |// | freeDevelop | debug |// | profile | profile |// | ----------------- | ----------------------------- |//// This mapping is based on the following rules:// 1. If the host app build variant name is `profile` then the equivalent// Flutter variant is `profile`.// 2. If the host app build variant is debuggable// (e.g. `buildType.debuggable = true`), then the equivalent Flutter// variant is `debug`.// 3. Otherwise, the equivalent Flutter variant is `release`.
String variantBuildMode =buildModeFor(libraryVariant.buildType)if(buildModeFor(appProjectVariant.buildType)!= variantBuildMode){
return}if(copyFlutterAssetsTask == null){
copyFlutterAssetsTask =addFlutterDeps(libraryVariant)}
Task mergeAssets = project
.tasks
.findByPath(":${hostAppProjectName}:merge${appProjectVariant.name.capitalize()}Assets")assert mergeAssets
mergeAssets.dependsOn(copyFlutterAssetsTask)}}}configurePlugins()}
/*
*开发触发器
*/
--得到日期是周几
select to_char(sysdate+4,'DY','nls_date_language=AMERICAN') from dual;
select to_char(sysdate,'DY','nls_date_language=AMERICAN') from dual;
--建立BEFORE语句触发器
CREATE O
下面给大家整理了一些vim NERDTree的常用快捷键了,这里几乎包括了所有的快捷键了,希望文章对各位会带来帮助。
切换工作台和目录
ctrl + w + h 光标 focus 左侧树形目录ctrl + w + l 光标 focus 右侧文件显示窗口ctrl + w + w 光标自动在左右侧窗口切换ctrl + w + r 移动当前窗口的布局位置
o 在已有窗口中打开文件、目录或书签,并跳