所有的分析基于当前的 1.4.7 版本,flutter sdk 的版本更新可能会修改这个文件

Flutter 1.4.7 • channel dev • https://github.com/flutter/flutter.git
Framework • revision 1bfa2f2311 (3 days ago) • 2019-03-29 10:05:18 -0700
Engine • revision c4d14a0071
Tools • Dart 2.2.1 (build 2.2.1-dev.2.0 None)

这个文件是 sdk 中的 android 部分的配置文件文件,简单分析一下流程,以便于魔改或在项目中可以配置项目

gradle 使用的是 groovy 的语法,是一个 jvm 语言,在语法层级上兼容 Java 语法

换句话说 System.out.println("hello world"); 这样的方法是可用的

分析 flutter 项目

项目 android/app/build.gradle 文件中都有定义

def localProperties = new Properties()
def localPropertiesFile = rootProject.file('local.properties')
if (localPropertiesFile.exists()) {
    localPropertiesFile.withReader('UTF-8') { reader ->
        localProperties.load(reader)
    }
}

def flutterRoot = localProperties.getProperty('flutter.sdk')
if (flutterRoot == null) {
    throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
}

def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
if (flutterVersionCode == null) {
    flutterVersionCode = '1'
}

def flutterVersionName = localProperties.getProperty('flutter.versionName')
if (flutterVersionName == null) {
    flutterVersionName = '1.0'
}

apply plugin: 'com.android.application'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" // 这句代表了引入flutter.gradle到项目中,路径是

build.gradle 是 gradle 项目的主文件,关于 gradle 和相关说明可以自行搜索,这个体系很庞大,展开介绍不太现实

前面的基本都是 groovy 语法

def 是 groovy 中的关键字,可以简单理解为和 dart 中的 var 同义

读取 local.properties,然后在 properties 中查找 flutter 的 sdk 目录,如果没有就报错退出

然后是读取 properties 中定义的 versionCode 和 versionName

后面就是”引用” flutter.gradle 到项目中,通过这样的过程,flutter.gradle 的内容就被引入项目中了

flutter.gradle 的路径需要在 flutter sdk 目录下搜索 packages/flutter_tools/gradle/flutter.gradle

分析 flutter.gradle

开始是一些导包之类的相关代码

20190401132553.png

最后一行是一句关键的代码,引入插件FlutterPlugin,这个是告诉 gradle,我需要引入这个插件

这个插件就定义在这个文件内

20190401133009.png

查看主要的方法也就是 apply 方法,可以简单的理解为回调方法,处理整个项目

    @Override
    void apply(Project project) {
        // Add custom build types
        // 定义一些buildType
        project.android.buildTypes {
            profile {
                initWith debug //初始化参数来自于debug
                if (it.hasProperty('matchingFallbacks')) {
                    matchingFallbacks = ['debug', 'release']
                }
            }
            dynamicProfile {
                initWith debug
                if (it.hasProperty('matchingFallbacks')) {
                    matchingFallbacks = ['debug', 'release']
                }
            }
            dynamicRelease {
                initWith debug
                if (it.hasProperty('matchingFallbacks')) {
                    matchingFallbacks = ['debug', 'release']
                }
            }
        }

        String flutterRootPath = resolveProperty(project, "flutter.sdk", System.env.FLUTTER_ROOT)
        // 查询flutter sdk的地址,如果没有定义,就查看FLUTTER_ROOT的环境变量,都没有就报错
        if (flutterRootPath == null) {
            throw new GradleException("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()) { //不是文件夹说明sdk地址不对,也报错
            throw new GradleException("flutter.sdk must point to the Flutter SDK directory")
        }

        // flutter的执行文件,windows执行bat,其他的执行flutter
        String flutterExecutableName = Os.isFamily(Os.FAMILY_WINDOWS) ? "flutter.bat" : "flutter"
        flutterExecutable = Paths.get(flutterRoot.absolutePath, "bin", flutterExecutableName).toFile();


        if (project.hasProperty('localEngineOut')) { // 这里可以理解为自定义engine,应该是用于engine开发或深度定制engine的情况, 普通的flutter使用者直接看else
            String engineOutPath = project.property('localEngineOut')
            File engineOut = project.file(engineOutPath)
            if (!engineOut.isDirectory()) {
                throw new GradleException('localEngineOut must point to a local engine build')
            }
            flutterJar = Paths.get(engineOut.absolutePath, "flutter.jar").toFile()
            if (!flutterJar.isFile()) {
                throw new GradleException('Local engine build does not contain flutter.jar')
            }

            localEngine = engineOut.name
            localEngineSrcPath = engineOut.parentFile.parent

            project.dependencies {
                if (project.getConfigurations().findByName("api")) {
                    api project.files(flutterJar)
                } else {
                    compile project.files(flutterJar)
                }
            }
        } else { //普通使用者
            Path baseEnginePath = Paths.get(flutterRoot.absolutePath, "bin", "cache", "artifacts", "engine")
            String targetArch = 'arm'
            if (project.hasProperty('target-platform') &&
                project.property('target-platform') == 'android-arm64') {
                    // 这里是判断类型,如果有target-platform属性,且属性是arm64,则认为目标类型是arm64,否则默认是arm
              targetArch = 'arm64'
            }
            debugFlutterJar = baseEnginePath.resolve("android-${targetArch}").resolve("flutter.jar").toFile()
            profileFlutterJar = baseEnginePath.resolve("android-${targetArch}-profile").resolve("flutter.jar").toFile()
            releaseFlutterJar = baseEnginePath.resolve("android-${targetArch}-release").resolve("flutter.jar").toFile()
            dynamicProfileFlutterJar = baseEnginePath.resolve("android-${targetArch}-dynamic-profile").resolve("flutter.jar").toFile()
            dynamicReleaseFlutterJar = baseEnginePath.resolve("android-${targetArch}-dynamic-release").resolve("flutter.jar").toFile()

            // 这些就是指定flutter.jar的类型

            if (!debugFlutterJar.isFile()) {
                project.exec {
                    executable flutterExecutable.absolutePath
                    args "--suppress-analytics"
                    args "precache"
                }
                if (!debugFlutterJar.isFile()) { //类型不对就报错
                    throw new GradleException("Unable to find flutter.jar in SDK: ${debugFlutterJar}")
                }
            }

            // Add x86/x86_64 native library. Debug mode only, for now.
            // 如果是debug的情况下,添加一个task用于copy x86/x86_64的so库到apk内
            flutterX86Jar = project.file("${project.buildDir}/${AndroidProject.FD_INTERMEDIATES}/flutter/flutter-x86.jar")
            Task flutterX86JarTask = project.tasks.create("${flutterBuildPrefix}X86Jar", Jar) {
                destinationDir flutterX86Jar.parentFile
                archiveName flutterX86Jar.name
                from("${flutterRoot}/bin/cache/artifacts/engine/android-x86/libflutter.so") {
                    into "lib/x86"
                }
                from("${flutterRoot}/bin/cache/artifacts/engine/android-x64/libflutter.so") {
                    into "lib/x86_64"
                }
            }
            // Add flutter.jar dependencies to all <buildType>Api configurations, including custom ones
            // added after applying the Flutter plugin.
            project.android.buildTypes.each { addFlutterJarApiDependency(project, it, flutterX86JarTask) }
            project.android.buildTypes.whenObjectAdded { addFlutterJarApiDependency(project, it, flutterX86JarTask) }
        }

        project.extensions.create("flutter", FlutterExtension)
        project.afterEvaluate this.&addFlutterTask

        // 这里是处理flutter插件, .flutter-plugins这个文件由flutter维护,来源于flutter项目中的pubspec.yaml
        File pluginsFile = new File(project.projectDir.parentFile.parentFile, '.flutter-plugins')
        Properties plugins = readPropertiesIfExist(pluginsFile)

        plugins.each { name, _ ->
            def pluginProject = project.rootProject.findProject(":$name")
            if (pluginProject != null) {
                // 这里两个循环就是将依赖需要的库引入当前项目内
                project.dependencies {
                    if (project.getConfigurations().findByName("implementation")) {
                        implementation pluginProject
                    } else {
                        compile pluginProject
                    }
                }
                pluginProject.afterEvaluate {
                            pluginProject.android.buildTypes {
                                profile {
                                    initWith debug
                                }
                            }
                }
                pluginProject.afterEvaluate this.&addFlutterJarCompileOnlyDependency
            } else {
                project.logger.error("Plugin project :$name not found. Please update settings.gradle.")
            }
        }
    }

我简单对于 apply 方法进行了分析加了一些注释

后记

很多东西需要对于 groovy 语法和 gradle 构建体系有所了解才能看懂,当然我也是萌新一枚,有错误或需要讨论可以留言

以上