Android构建06-Android应用构建基础

简介

Android构建流程是指将Android源代码转换成Apk(Android Application Package)这一过程,里面涉及到许多步骤和工具。构建流程由Gradle和Android Gradle Plugin插件来管理,既可以通过IDE方式,也可以通过命令行方式来进行。



构建流程

官网有一个简单的流程图,比较简略,图中主要展示了两步,且都是由Gradle和Andorid插件管理的:

  1. 编译。编译器将源代码编译成DEX文件和供前者直接使用的资源文件。
  2. 打包并签名。将上述DEX文件和资源文件合并成APK,之后进行签名生成最终可以用于安装、测试或发布的APK。

在许多博客中,都提到一个详细的流程图,说是来自官网,但我没有找到,可能以前存在,现在已经删除了,如下:

Android构建流程

上述流程分为七个步骤,涉及许多工具,如AAPT、AIDL等,有些工具现在已经升级或改变名称了,如AAPT现在升级为AAPT2。

AAPT等工具位于{Android SDK}/build-tools/{版本号}。

七个步骤具体如下:

1. 编译资源文件

利用aapt编译资源文件生成R.javaresources.arsc

# R.java
$ aapt p -f -m -J app/out/R \
-M app/src/main/AndroidManifest.xml \
-S app/src/main/res \
-I $SDK/platforms/android-28/android.jar 
# 生成包含resources.arsc的apk,之后添加dex文件
$ aapt p -f -F app/out/res/resource.apk \
-M app/src/main/AndroidManifest.xml \
-S app/src/main/res \
-I $SDK/platforms/android-28/android.jar 

说明:

  • 上面的示例工程是利用Android Studio生成的,并去掉了自动引入的第三方依赖。
  • 需要生成必要的文件夹$ mkdir -p app/out/R$ mkdir -p app/out/res
  • \表示命令行换行。
  • $SDK可用命令$ export SDK=~/Library/Android/sdk设置。
  • 命令的参数说明请见Android AAPT,或$ aapt查看输出信息。
  • 如果有第三方依赖,用-I继续添加, 可参考命令行编译Android。但我添加了com.android.support.constraint依赖,并用-I添加进命令行,执行命令后报错。

2. 编译AIDL文件

3. 编译Java文件

利用javac编译.java文件为.class文件

$ javac -target 1.8 -source 1.8 \
-bootclasspath $SDK/platforms/android-28/android.jar \
-d app/out/class \
app/out/R/com/liang/clidemo/R.java app/src/main/java/com/liang/clidemo/*.java 

生成class文件夹$ mkdir app/out/class

4. 生成Dex文件

$ dx --dex --output=app/out/dex app/out/class

需要生成dex文件夹$ mkdir app/out/dex

5. 打包生成apk

$ java -classpath $SDK/tools/lib/sdklib-26.0.0-dev.jar com.android.sdklib.build.ApkBuilderMain app/out/demo.apk \
-v -u -z app/out/res/resource.apk \
-f app/out/dex/classes.dex

6. 签名

签名debug版本的秘钥

$ jarsigner -verbose -keystore ~/.android/debug.keystore \
-storepass android \
-keypass android \
app/out/demo.apk androiddebugkey

7. 对齐

以上七个命令可以用来手动打包,但比较繁琐,而Gradle将这些命令封装起来作为任务,只需要执行$ ./gradlew assemleDebug等即可,提高了工作效率。当然了,Gradle的功能不止如此。

执行./gradlew assembleDebug --console=plain,可以看Gradle的任务执行顺序与用命令行打包顺序基本是一致的:

:app:checkDebugClasspath UP-TO-DATE
:app:preBuild UP-TO-DATE
:app:preDebugBuild UP-TO-DATE
# 编译aidl
:app:compileDebugAidl NO-SOURCE
:app:compileDebugRenderscript UP-TO-DATE
:app:checkDebugManifest UP-TO-DATE
# 编译BuildConfig.java
:app:generateDebugBuildConfig UP-TO-DATE
:app:prepareLintJar UP-TO-DATE
:app:mainApkListPersistenceDebug UP-TO-DATE
# 生成R.java和res资源文件
:app:generateDebugResValues UP-TO-DATE
:app:generateDebugResources UP-TO-DATE
:app:mergeDebugResources UP-TO-DATE
:app:createDebugCompatibleScreenManifests UP-TO-DATE
:app:processDebugManifest UP-TO-DATE
:app:splitsDiscoveryTaskDebug UP-TO-DATE
:app:processDebugResources UP-TO-DATE
:app:generateDebugSources UP-TO-DATE
:app:javaPreCompileDebug UP-TO-DATE
# javac编译java文件为class文件
:app:compileDebugJavaWithJavac UP-TO-DATE
:app:compileDebugNdk NO-SOURCE
:app:compileDebugSources UP-TO-DATE
:app:mergeDebugShaders UP-TO-DATE
:app:compileDebugShaders UP-TO-DATE
:app:generateDebugAssets UP-TO-DATE
:app:mergeDebugAssets UP-TO-DATE
# 生成dex文件
:app:transformClassesWithDexBuilderForDebug UP-TO-DATE
:app:transformDexArchiveWithExternalLibsDexMergerForDebug UP-TO-DATE
:app:transformDexArchiveWithDexMergerForDebug UP-TO-DATE
:app:mergeDebugJniLibFolders UP-TO-DATE
:app:transformNativeLibsWithMergeJniLibsForDebug UP-TO-DATE
:app:transformNativeLibsWithStripDebugSymbolForDebug UP-TO-DATE
:app:checkDebugLibraries UP-TO-DATE
:app:processDebugJavaRes NO-SOURCE
:app:transformResourcesWithMergeJavaResForDebug UP-TO-DATE
:app:validateSigningDebug UP-TO-DATE
# 打包
:app:packageDebug UP-TO-DATE
:app:assembleDebug UP-TO-DATE


Android Plugin DSL Reference

Android Plugin DSL Reference详细描述了Android module构建脚本build.gradle所用到的参数。

包括四个扩展内容,下面以应用型项目的build.gradle为例,说下AppExtension的语法。

简单的应用型项目的build.gradle脚本:

apply plugin: 'com.android.application'

android {
    compileSdkVersion 28
    defaultConfig {
        applicationId "com.liang.clidemo"
        minSdkVersion 21
        targetSdkVersion 28
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.android.support.constraint:constraint-layout:1.1.3'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.2'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}

解释如下:

  • Project实例的三个方法。最外层的applyandroiddependencies都是Project实例的方法。
  • apply方法。全称为void apply(Map<String, ?> options),位于接口PluginAware.java中(Project实现了PluginAware),用于增加插件。示例中表示当前项目为应用型项目。
  • android方法。原始的Project中并没有这个方法,应该位于Android插件的Project的实例中,可以看源码。闭包里的参数设置详细说明位于Reference的AppExtension
    • ompileSdkVersion。编译版本。很奇怪的是AppExtension中说它是String类型的,但如果赋值为字符串,则又报错。
    • defaultConfig。接收DefaultConfig作为参数,其闭包里的参数说明见Reference的DefaultConfig
    • buildTypes。闭包里的参数设置请见BuildType
  • dependencies方法。位于Projectvoid dependencies(Closure configureClosure);,参数说明详见闭包的代理DependencyHandler

:p,还是看源码比较直接。



待研究

  • aapt命令中添加第三方依赖问题
  • aapt2命令
  • Android构建脚本配置。官网-Configure your build写的比较详细,目前不准备写。
  • Android构建最佳实践。官网-Configure your build上写了许多,以后可以做些补充。
  • Gradle和Android Plugin源码阅读和分析。非常值得研究,但需要花费很多时间,以后有时间加上。


参考

  1. 官网-Configure your build
  2. Android APK 编译打包流程
  3. APK打包安装过程
  4. 详细打包流程图
  5. 命令行编译Android
  6. How to make Android apps without IDE from command line
  7. Android AAPT
  8. AAPT2官方文档
  9. aapt2 资源 compile 过程
  10. 官网-Android Plugin DSL Reference
  11. Android Gradle Plugin 源码阅读与编译
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,390评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,821评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,632评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,170评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,033评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,098评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,511评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,204评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,479评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,572评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,341评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,893评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,171评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,486评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,676评论 2 335

推荐阅读更多精彩内容