Android应用的构建过程

编译构建分为4个步骤

代码编译 -> 代码合成 -> 资源打包 -> 签名和对齐

  1. 代码编译 Java编译器对工程的代码文件进行编译,包括App源代码,编译生成的R文件和AIDL接口生成的Java接口文件

  2. 代码合成 通过dex工具将class文件和第三方库文件生成虚拟机可执行的dex文件。如果使用了MultiDex,会生成多个dex文件

  3. 资源打包 apkbuilder工具将dex文件,apt编译后的资源文件,第三方库打包生成apk文件

4.签名对齐 使用预定的key对apk包进行签名。对齐可以使得在运行时Android与应用程序间的交互更加有效率

首先所有的资源文件会被编译,并且在一个R文件中被引用。然后Java文件编译,通过dex工具转换成dalvik字节码。最后这些文件会被打包成一个APK文件,这个应用最终安装在设备中前,APK文件会被一个debug或者release的key文件签名。


Gradle文件

在项目的根目录有build.gradle,Settings.gradle,每个模块都有一个build.gradle

setttings.gradle

这个文件定义了哪些模块会参与构建,创建模块后需要在这里添加到项目

include ':app', ':base'

根目录的build.gradle

buildscript {
    //定义依赖仓库
    repositories {
        google()
        jcenter()   //整个构建过程中的依赖仓库
    }
    
    //构建过程中的依赖包
    dependencies {
        classpath 'com.android.tools.build:gradle:3.2.1'
        classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }

}

//声明那些被用于所有模块的属性,可以在allprojects中创建任务,这些任务最终会被运用到所有模块
allprojects {
    repositories {
        google()
        jcenter()
    }
}

每个模块的build.gradle

apply plugin: 'com.android.application' //导入Android应用插件

//包含了全部的Android特有配置
android {
    compileSdkVersion 27    //用来编译应用的Android API版本
    buildToolsVersion '27.0.2'  //构建工具和编译器使用的版本号
    defaultConfig {
        applicationId "com.viator42.ugo"    //applicationId覆盖了AndroidManifest.xml中的package name属性,跟package name不同。同样的package name可以有不同的id,这样设计可以为一个应用制作不同的版本,而且可以安装到同一个手机上
        minSdkVersion 19
        targetSdkVersion 27
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        vectorDrawables.useSupportLibrary = true
    }
    //用来打包不同构建类型的应用
    buildTypes {
        debug {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
        release {
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

    flavorDimensions "default"
    productFlavors {
        productFlavors.all {
            flavor -> flavor.manifestPlaceholders =[channel: name]
        }
    }
}

dependencies {
    implementation fileTree(include: ['*.jar'], dir: 'libs')
    。。。
}

定义依赖

一个依赖由 group:name:version构成

implementation 'com.android.support:appcompat-v7:27.1.1'

添加本地依赖

implementation files('libs/AMap_Location_V3.3.0_20170118.jar')

aar文件依赖


创建Variant

buildType构建类型用来定义如何构建一个应用,debug标识是否包含,application是什么,是否进行代码压缩 默认的有debug和release

android {
    。。。
    buildTypes {
        debug {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            debuggable = true
        }
        staging.initWith(buildTypes.debug)  //可以从现有的构建类型继承属性
        staging {
            applicationIdSuffix "-staging"  //applicatinId当前类型的app id添加后缀,这样测试版和正式版能装在同一台手机上
            versionNameSuffix "-staging"    //为当前类型的versionName添加后缀

        }
        release {
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            debuggable = false
        }
    }
}

productFlavors

productFlavors用于创建不同的版本,比如构建免费版和付费版,内部试用版版和外部版,同一类别不同客户使用的版本,唯一不同的是颜色图标和后台url,对应不同市场发布的渠道包

android {
    。。。
    productFlavors {
        qihu360 {
            manifestPlaceholders = [
                    channel_id: "1000",
                    app_name  : "UGou_360定制版",
            ]

        }
        wandoujia {
            manifestPlaceholders = [
                    channel_id: "1001",
                    app_name  : "UGou_豌豆荚定制版",
            ]
        }
//        productFlavors.all {
//            flavor -> flavor.manifestPlaceholders =[channel: name]
//        }
    }
}

dependencies {
    qihu360Implementation project(':base')  //为渠道包引入特定的module
}

Gradle参数

修改根目录下的gradle.properties文件,以下是可以提供提高构建效率的选项

  • org.gradle.jvmargs=-Xms512m -Xmx2048m //设置Java虚拟机的内存分配 Xms:初始内存 Xmx最大内存
  • org.gradle.daemon=true //第一次构建的时候开启一个守护进程,在以后的构建过程中都会复用这个进程
  • org.dradle.configureondemand=true //只编译有变化的模块,当有多个模块的时候构建时间会大为加快
  • org.gradle.parallel=true //开启多模块并行构建

Gradle使用Groovy语言定义构建任务

Groovy语言

定义变量

行尾没有括号

def name =  'Viator42'  //单引号是单纯的字符串
def msg = "Your name is ${name}"    //双引号可以包含表达式

类和成员变量

class GroovyClass {
    String param1

    String func1() {
        return 'aaa'
    }
}

集合

List

//  定义
List list = [1, 2, 3]
//  循环遍历
list.each() {element ->
    print element
}

Map

//  定义
Map map = {param1: 1, param2: 2}
//  获取map中的项目
map.get('param1')
map['param2']

在Gradle中的使用

build.gradle中定义一个任务

android {
    task hello {
        println 'Task hello'
    }

    //普通的任务在配置阶段运行
    task task During Config {
        println 'Task hello'
    }

    // 加了 << 标识符的会在构建阶段运行
    task taskDuringBuild << {
        println 'task During Build'
    }

    //设置Task执行的先后顺序
    task task1 {
        println 'Task 1'
    }

    task task2 {
        println 'Task 2'
    }

    task2.mustRunAfter task1

}

通过操控构建过程来重命名APK文件,添加版本号信息

android.applicationVariants.all { variant ->
    variant.outputs.all { output ->
        def file = output.outputFile
        println "apk file name is: ${output.outputFile.name}"
        outputFileName = "${variant.name}-${variant.versionName}.apk"
    }
}

Gradle 3.0以上的变化

compile指令改成了api,两者使用没有区别

增加了implementation指令作为默认的依赖方式,代替了compile。跟compile的区别在于不能跨模块依赖。模块中的依赖包不会被外部访问到,这样可以隐藏内部接口的实现而且不会产生依赖冲突。