Android项目构建Gradle专栏——build基础

目录:

    1. 构建体系
    1. Build流程
    1. 工具
    1. build文件分析
    1. gradle Task
    1. 依赖

公众号: https://mp.weixin.qq.com/s/WkwgKyAachnfCxKw3b1BMg
gradle专栏地址: https://gongshijier.github.io/2021/04/02/Android%E9%A1%B9%E7%9B%AE%E6%9E%84%E5%BB%BAGradle%E4%B8%93%E6%A0%8F%E2%80%94%E2%80%94build%E5%9F%BA%E7%A1%80/


1. 构建体系

Android 构建系统会编译应用资源和源代码,然后将它们打包成可供您测试、部署、签署和分发的 APK。
也就是说 构建: 从代码和应用资源到APK的过程
Android 采用的构建系统是 Gradle 工具, Android 项目架构中的一些和构建相关的文件就是供Gradle构建核心文件

  • build.gradle
  • settings.gradle
  • app/build.gradle
  • app/build.gradle

通过这些文件执行一系列的 Gradle Task 就完成从源代码和资源文件 ----> APK
参考下面的 project 目录, 项目中会有多个 module 每个module 内也都有 build.gradle 来负责构建事宜

2. Build流程

  • 从需要构建的模块开始, 确定依赖项
  • 编译
  • 打包
    编译器: 源代码 --> dex 文件
    打包: 将dex和编译后的资源 组合为 apk 文件 并且使用相应的密钥库来进行签名
    生成最终 APK 前, zipalign 会对APK进行一定优化, 减少内存占用

3. 工具

gradle 构建都是通过 gradle 构建工具包实现的
可以到 sdk目录: Library/Android/sdk/版本/build-tools 下找到对应的工具


构建过程就是通过gradle脚本使用这些工具, 完成前面说的 编译和打包和优化

图片引用

图片里面很清楚的说明了构建过程的各个核心流程


  • aapt (Android asset package tool) :负责将xml文件和其他一些资源文件res ... 编译打包应用资源形成供代码访问的一个索引表
  • aidl: 处理使用AIDL规范写的aidl文件, 编译为 java 源代码
  • javac: java --> class 文件
  • d8: class 文件 --> dex 文件
  • zipalign: 字节码对齐工具, 进行优化, 类似垃圾回收标记整理的过程
  • jarsigner: 使用密钥证书 为 apk 签名

对以上构建工具建议查阅官方资料: https://developer.android.com/studio/command-line?hl=zh-cn

里面都有详细权威介绍

4. build文件分析

settings.gradle

settings.gradle 文件位于项目的根目录下,用于指示 Gradle 在构建应用时应将哪些模块包含在内。
比如开源项目bytex settings.gradle 指明了哪些模块参与构建

//opensource
include ':shrink-r-plugin'
include ':access-inline-plugin'
include ':getter-setter-inline-plugin'
include ':refer-check-plugin'
include ':closeable-check-plugin'
include ':serialization-check-plugin'
include ':const-inline-plugin'
include ':field-assign-opt-plugin'
include ':method-call-opt-plugin'
include ':SourceFileKiller'
include ':butterknife-check-plugin'

include ':coverage-plugin'
project(':coverage-plugin').projectDir = new File('coverage/coverage-plugin')
include ':coverage-lib'
project(':coverage-lib').projectDir = new File('coverage/coverage-lib')

project/build.gradle

/**
 * The buildscript block is where you configure the repositories and
 * dependencies for Gradle itself—meaning, you should not include dependencies
 * for your modules here. For example, this block includes the Android plugin for
 * Gradle as a dependency because it provides the additional instructions Gradle
 * needs to build Android app modules.
 */

buildscript {

    /**
     * The repositories block configures the repositories Gradle uses to
     * search or download the dependencies. Gradle pre-configures support for remote
     * repositories such as JCenter, Maven Central, and Ivy. You can also use local
     * repositories or define your own remote repositories. The code below defines
     * JCenter as the repository Gradle should use to look for its dependencies.
     *
     * New projects created using Android Studio 3.0 and higher also include
     * Google's Maven repository.
     */

    repositories {
        google()
        jcenter()
    }

    /**
     * The dependencies block configures the dependencies Gradle needs to use
     * to build your project. The following line adds Android plugin for Gradle
     * version 4.1.0 as a classpath dependency.
     */

    dependencies {
        classpath 'com.android.tools.build:gradle:4.1.0'
    }
}

/**
 * The allprojects block is where you configure the repositories and
 * dependencies used by all modules in your project, such as third-party plugins
 * or libraries. However, you should configure module-specific dependencies in
 * each module-level build.gradle file. For new projects, Android Studio
 * includes JCenter and Google's Maven repository by default, but it does not
 * configure any dependencies (unless you select a template that requires some).
 */

allprojects {
   repositories {
       google()
       jcenter()
   }
}
  • repositories: 指明依赖项目从哪里来, 从哪个仓库导入进来
  • dependencies: 指明具体的 groupID 和 ArtifactID 用来找到具体依赖库
  • buildScript: 这里的依赖是 Gradle 构建时候需要用的, 比如依赖一些库,需要使用他们定义的Gradle插件
    重点注意 buildScript是 Gradle 需要的库, 比如一些 gradle plugin

比如:

buildscript {

    repositories {
        maven { url 'https://jitpack.io' }
        maven {
            url uri('../gradle_plugins')
        }
        google()
        jcenter()
        maven {
            url "https://plugins.gradle.org/m2/"
        }
    }
    dependencies {
        classpath "com.android.tools.build:gradle:$gradle_version"

        //依赖了 com.github.dcendents:android-maven-gradle-plugin 是因为gradle构建阶段需要使用到其内的插件
        classpath 'com.github.dcendents:android-maven-gradle-plugin:2.0'
    }
}
// 因为在 buildScript 中 , classpath 依赖了库, 所以可以在项目中可以使用 该 plugin
apply plugin: 'com.github.dcendents.android-maven'
buildscript {...}

allprojects {...}

// This block encapsulates custom properties and makes them available to all
// modules in the project.
ext {
    // The following are only a few examples of the types of properties you can define.
    compileSdkVersion = 28
    // You can also create properties to specify versions for dependencies.
    // Having consistent versions between modules can avoid conflicts with behavior.
    supportLibVersion = "28.0.0"
    ...
}
...

全局 build.gradle 中的 ext 里面定义的一些 变量是全局可用的, 可以在其他模块中访问如:

android {
  // Use the following syntax to access properties you defined at the project level:
  // rootProject.ext.property_name
  compileSdkVersion rootProject.ext.compileSdkVersion
  ...
}
...
dependencies {
    implementation "com.android.support:appcompat-v7:${rootProject.ext.supportLibVersion}"
    ...
}

module/build.gradle

模块下的 build.gradle 配置则是 对该模块生效的一些特性

/**
 * The first line in the build configuration applies the Android plugin for
 * Gradle to this build and makes the android block available to specify
 * Android-specific build options.
 */

apply plugin: 'com.android.application'

/**
 * The android block is where you configure all your Android-specific
 * build options.
 */

android {

  /**
   * compileSdkVersion specifies the Android API level Gradle should use to
   * compile your app. This means your app can use the API features included in
   * this API level and lower.
   */

  compileSdkVersion 28

  /**
   * buildToolsVersion specifies the version of the SDK build tools, command-line
   * utilities, and compiler that Gradle should use to build your app. You need to
   * download the build tools using the SDK Manager.
   *
   * This property is optional because the plugin uses a recommended version of
   * the build tools by default.
   */

  buildToolsVersion "29.0.2"

  /**
   * The defaultConfig block encapsulates default settings and entries for all
   * build variants, and can override some attributes in main/AndroidManifest.xml
   * dynamically from the build system. You can configure product flavors to override
   * these values for different versions of your app.
   */

  defaultConfig {

    /**
     * applicationId uniquely identifies the package for publishing.
     * However, your source code should still reference the package name
     * defined by the package attribute in the main/AndroidManifest.xml file.
     */

    applicationId 'com.example.myapp'

    // Defines the minimum API level required to run the app.
    minSdkVersion 15

    // Specifies the API level used to test the app.
    targetSdkVersion 28

    // Defines the version number of your app.
    versionCode 1

    // Defines a user-friendly version name for your app.
    versionName "1.0"
  }

  /**
   * The buildTypes block is where you can configure multiple build types.
   * By default, the build system defines two build types: debug and release. The
   * debug build type is not explicitly shown in the default build configuration,
   * but it includes debugging tools and is signed with the debug key. The release
   * build type applies Proguard settings and is not signed by default.
   */

  buildTypes {

    /**
     * By default, Android Studio configures the release build type to enable code
     * shrinking, using minifyEnabled, and specifies the default Proguard rules file.
     */

    release {
        minifyEnabled true // Enables code shrinking for the release build type.
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    }
  }

  /**
   * The productFlavors block is where you can configure multiple product flavors.
   * This allows you to create different versions of your app that can
   * override the defaultConfig block with their own settings. Product flavors
   * are optional, and the build system does not create them by default.
   *
   * This example creates a free and paid product flavor. Each product flavor
   * then specifies its own application ID, so that they can exist on the Google
   * Play Store, or an Android device, simultaneously.
   *
   * If you declare product flavors, you must also declare flavor dimensions
   * and assign each flavor to a flavor dimension.
   */

  flavorDimensions "tier"
  productFlavors {
    free {
      dimension "tier"
      applicationId 'com.example.myapp.free'
    }

    paid {
      dimension "tier"
      applicationId 'com.example.myapp.paid'
    }
  }

  /**
   * The splits block is where you can configure different APK builds that
   * each contain only code and resources for a supported screen density or
   * ABI. You'll also need to configure your build so that each APK has a
   * different versionCode.
   */

  splits {
    // Settings to build multiple APKs based on screen density.
    density {

      // Enable or disable building multiple APKs.
      enable false

      // Exclude these densities when building multiple APKs.
      exclude "ldpi", "tvdpi", "xxxhdpi", "400dpi", "560dpi"
    }
  }
}

/**
 * The dependencies block in the module-level build configuration file
 * specifies dependencies required to build only the module itself.
 * To learn more, go to Add build dependencies.
 */

dependencies {
    implementation project(":lib")
    implementation 'com.android.support:appcompat-v7:28.0.0'
    implementation fileTree(dir: 'libs', include: ['*.jar'])
}
  • compileSdkVersion 28 用来编译的 Android API 版本
  • buildToolsVersion "29.0.2" 用来 build 构建的 build-tools 版本

local.properties

系统本地环境属性

gradle.properties

配置一些全局的配置, 和 ext 闭包一样 可以在其他gradle文件中获得其中配置

5. gradle Task

gradle 执行的是一个个 task
gradle 开发的自定义plugin 也就是重写 apply 方法部分

每一次 Android 项目构建执行会执行一系列的gradle task 来完成整个构建过程比如:

可以参考该文章: https://mp.weixin.qq.com/s/6Cb6MqV9GQG60hBltss61A :

Starting Gradle Daemon...
Gradle Daemon started in 902 ms
> Task :app:preBuild UP-TO-DATE
> Task :app:preDebugBuild UP-TO-DATE
> Task :app:compileDebugAidl NO-SOURCE
> Task :app:compileDebugRenderscript NO-SOURCE
> Task :app:generateDebugBuildConfig UP-TO-DATE
> Task :app:checkDebugAarMetadata UP-TO-DATE
> Task :app:generateDebugResValues UP-TO-DATE
> Task :app:generateDebugResources UP-TO-DATE
> Task :app:mergeDebugResources UP-TO-DATE
> Task :app:createDebugCompatibleScreenManifests UP-TO-DATE
> Task :app:extractDeepLinksDebug UP-TO-DATE
> Task :app:processDebugMainManifest
> Task :app:processDebugManifest
> Task :app:javaPreCompileDebug UP-TO-DATE
> Task :app:mergeDebugNativeDebugMetadata NO-SOURCE
> Task :app:mergeDebugShaders UP-TO-DATE
> Task :app:compileDebugShaders NO-SOURCE
> Task :app:generateDebugAssets UP-TO-DATE
> Task :app:mergeDebugAssets UP-TO-DATE
> Task :app:compressDebugAssets UP-TO-DATE
> Task :app:processDebugJavaRes NO-SOURCE
> Task :app:mergeDebugJniLibFolders UP-TO-DATE
> Task :app:mergeDebugNativeLibs UP-TO-DATE
> Task :app:stripDebugDebugSymbols NO-SOURCE
> Task :app:validateSigningDebug UP-TO-DATE
> Task :app:mergeLibDexDebug
> Task :app:processDebugManifestForPackage
> Task :app:processDebugResources
> Task :app:compileDebugKotlin UP-TO-DATE
> Task :app:compileDebugJavaWithJavac UP-TO-DATE
> Task :app:compileDebugSources UP-TO-DATE
> Task :app:mergeDebugJavaResource UP-TO-DATE
> Task :app:dexBuilderDebug
> Task :app:mergeExtDexDebug
> Task :app:mergeProjectDexDebug
> Task :app:packageDebug
> Task :app:assembleDebug

BUILD SUCCESSFUL in 22s
27 actionable tasks: 10 executed, 17 up-to-date

//aidl 转换aidl文件为java文件
> Task :app:compileDebugAidl

//生成BuildConfig文件
> Task :app:generateDebugBuildConfig

//获取gradle中配置的资源文件
> Task :app:generateDebugResValues

// merge资源文件
> Task :app:mergeDebugResources

// merge assets文件
> Task :app:mergeDebugAssets
> Task :app:compressDebugAssets

// merge所有的manifest文件
> Task :app:processDebugManifest

//AAPT 生成R文件
> Task :app:processDebugResources

//编译kotlin文件
> Task :app:compileDebugKotlin

//javac 编译java文件
> Task :app:compileDebugJavaWithJavac

//转换class文件为dex文件
> Task :app:dexBuilderDebug

//打包成apk并签名
> Task :app:packageDebug

可以自己run apk 的时候看一下build 窗口中的一系列 gradle task执行过程

gradle task 是 gradle 流水线执行的节点

开发中 会针对一些 特定位置运行gradle task

比如很多 task 是有依赖关系的, 比如 你可以让 taskA , 依赖 taskB
也可以在buid结束时候添加一些 task
可以参考: https://blog.csdn.net/ccpat/article/details/89342198简单介绍了一些task

6. 依赖

开发中经常接触到就是处理库之间的依赖关系

常见的依赖方式:

apply plugin: 'com.android.application'

android { ... }

dependencies {
    // Dependency on a local library module
    implementation project(":mylibrary")

    // Dependency on local binaries
    implementation fileTree(dir: 'libs', include: ['*.jar'])

    // Dependency on a remote binary
    implementation 'com.example.android:app-magic:12.3'
}

里面代表了三种依赖源
本地模块、 jar包、 远程maven仓库


除了依赖源头, 依赖的方式也很多:

  • implementation
  • api
  • compileOnly
  • runtimeOnly
  • annotationProcessor

Android项目构建gradle专栏系列持续更新中......

参考:
https://developer.android.google.cn/studio/build/index.html
https://mp.weixin.qq.com/s/6Cb6MqV9GQG60hBltss61A
https://cloud.tencent.com/developer/article/1392511
https://www.jianshu.com/p/e73510605c56
https://developer.android.com/studio/build?hl=zh-cn

你可能感兴趣的:(Android项目构建Gradle专栏——build基础)