In software development, the most expensive part is not writing code, but the process of code compilation and code debugging. For our Android, with the continuous iteration of the project, the continuous increase of business modules, and the increase of the project technology stack, the project compilation will become slower and slower. With the expansion of business, I believe that many companies have already done modularization/componentization.
background
After creating a Project, you can create multiple Modules, which are so-called modules. A simple example, maybe when writing code, we will separate the home page, news, and my modules, and the content contained in each tab is a module, which can reduce the amount of code in the module, but the difference between each module is There must be page jumps, data transfer, etc. For example, module A needs the data of module B, so we will rely on module B through implementation project(':B')
in the gradle file of module A, but module B needs to jump to a certain part of module A. page, so the B module depends on the A module. Such a development model is still not decoupled, and changing a bug will still change many modules, which cannot solve the problem of large-scale projects. So there is the concept of components. The components developed by our daily business requirements are called business components. If this business requirement can be widely reused, it is called business basic components. For example, frame components such as image loading and network requests are called basic components. components. So a typical componentized architecture is usually shown in the following figure.
Solid lines indicate direct dependencies, dashed lines indicate indirect dependencies. For example, the shell project must depend on the business basic components, business components, and module_common public library. Business components depend on business basic components, but not directly, but indirectly through "sinking interfaces". Dependencies between business components are also indirect dependencies. Finally, the common component depends on all the required basic components. Common is also a basic component. It only unifies the versions of the basic components, and also provides some abstract base classes for applications, such as BaseActivity, BaseFragment, and basic component initialization.
Compile optimization
Android compilation process
The compilation and construction of Android apk is divided into four steps:
- code compilation : Compile source code, R files, AIDL generated files, etc. into .class files;
- code synthesis : Use the dex tool to generate a virtual machine executable .dex file from the .class file and the third-party library file that the project depends on. If MultiDex is used, multiple dex files will be generated;
- Resource packaging : The apkbuilder tool packages the .dex file, the apt-compiled resource file, and the resource file in the tripartite library to generate a signature-aligned apk file;
- Sign and Align : Use Jarsigner and Zipalign to sign and align the file, producing the final apk file.
The following is the task chain for gradle to compile an app module:
gradle clean assembleDebug -x lint check –stacktrace
:app:clean //清理上次编译的遗留,删除module下的build文件夹
:app:preDebugBuild //debug版本预编译
:app:checkDebugManifest //AndroidManifest检查
:app:prepareDebugDependencies //检查debug版本的依赖
:app:compileDebugAidl // 编译debug版本的aidl文件
:app:compileDebugRenderscript //编译Renderscript文件
:app:generateDebugBuildConfig //generated/source文件夹下,生成buildConfig文件夹
:app:generateDebugAssets //生成Assets文件到generated下的asset文件夹
:app:mergeDebugAssets //在intermediates下生成assets文件夹,将其他module/aar中的assets文件拷贝过来
:app:generateDebugResValues //生成res value文件
:app:generateDebugResources //生成Resources文件
:app:mergeDebugResources //merge(合并)资源文件
:app:processDebugManifest //将merge后的Manifest文件放在intermediates/manifests文件夹下
:app:processDebugResources //处理资源文件,生成R.txt文件,同时也生成对应的multidex文件夹
:app:generateDebugSources //合成资源文件在generated文件夹下生成对应的R.java文件
:app:compileDebugJavaWithJavac //使用javac生成java文件
:app:compileDebugNdk //ndk编译
:app:compileDebugSources //编译资源文件
:app:transformClassesWithDexForDebug //将.class文件转换成.dex文件
:app:mergeDebugJniLibFolders //合并jni(.so)文件
:app:transformNative_libsWithMergeJniLibsForDebug //转换jni文件
:app:processDebugJavaRes //处理java资源
:app:transformResourcesWithMergeJavaResForDebug //转换java资源文件
:app:validateSigningDebug //验证签名
:app:packageDebug //打包
:app:assembleDebug //apk编译完成
Open InstantRun
Android Studio 2.0 launched InstantRun, which means instant compilation, which reduces the deployment and build time of applications during compilation and development. If you need to enable InstantRun, you need Gradle2.0 and minSdkVersion15 or later.
Build Process : Code Change-->Compile-->App Build-->App Deployment-->App Restart-->Activity Restart-->Complete Modification and Change
realizes the mechanism of instant operation : After modifying the code, incrementally build (generate incremental dex), and then choose to perform hot update, warm update or cold update by judging the complexity of updating resources;
- Hot deployment : No need to restart the app or activity when it takes effect
- Warm deployment : Updates can only be seen after restarting the activity
- cold deploy : app needs to be restarted, but not reinstalled
InstantRun mainly does two things:
- Use manifest-merger to integrate the manifest of the project, and compile the synthesized AndroidManifest.xml file and res resources into the incremental apk through the aapt tool;
- After the code is modified, the java file is compiled into a class file through javac, and then packaged into a dex file, which is also placed in the incremental apk;
gradle compilation optimization
We know that Android projects are built using gradle, so to optimize the compilation time of Android, there are many measures in gradle.
properties configuration optimization
#开启并行编译,仅仅适用于模块化项目(存在多个 Library 库工程依赖主工程)
org.gradle.parallel=true
# 使用编译缓存
android.emableBuildCache=true
# 开启构建缓存,Gradle 3.5新的缓存机制,可以缓存所有任务的输出,
# 不同于buildCache仅仅缓存dex的外部libs,它可以复用任何时候的构建缓存,设置包括其它分支的构建缓存
org.gradle.caching=true
# 构建初始化需要执行许多任务,例如java虚拟机的启动,加载虚拟机环境,加载class文件等等,
# 配置此项可以开启线程守护,并且仅仅第一次编译时会开启线程(Gradle 3.0版本以后默认支持)
# 保证jvm编译命令在守护进程中编译apk,daemon可以大大减少加载jvm和classes的时间
org.gradle.daemon=true
# 最大的优势在于帮助多 Moudle 的工程提速,在编译多个 Module 相互依赖的项目时,
# Gradle 会按需选择进行编译,即仅仅编译相关的 Module
org.gradle.configureondemand=true
# 配置编译时的虚拟机大小,加大编译时AndroidStudio使用的内存空间
# -Xmx2048m:指定 JVM 最大允许分配的堆内存为 2048MB,它会采用按需分配的方式。
#-XX:MaxPermSize=512m:指定 JVM 最大允许分配的非堆内存为 512MB,同上堆内存一样也是按需分配的。
org.gradle.jvmargs=-Xmx3072m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
filter gradle tasks
Optionally remove gradle tasks that do not need to be run when executing build tasks.
tasks.whenTaskAdded(new Action<Task>() {
@Override
void execute(Task task) {
if (task.name.contains("lint") //不扫描潜在bug可以使用该项
|| task.name == "clean"
|| task.name.contains("Aidl") //项目中用到Aidl则不可以舍弃这个任务
|| task.name.contains("mockableAndroidJar")//用不到测试时可以先关闭
|| task.name.contains("UnitTest")//用不到测试时可以先关闭
|| task.name.contains("AndroidTest")//用不到测试时可以先关闭
|| task.name.contains("Ndk") || task.name.contains("Jni")//用不到NDK和jni时关闭
) {
task.enabled = false
}
}
})
Use local gradle
Use local gradle files to avoid pulling from the network.
other
Remove the modules that do not need to be changed frequently from setting.gradle, and directly refer to the aar file corresponding to the module. When there are multiple modules in the project, each module will be compiled first, and then the main project will be compiled. As few module dependencies as possible will definitely speed up the compilation. In addition, if you are using Kotlin+JetPack to build Android projects, then you can try to use KSP: Say goodbye to KAPT, use KSP to speed up compiling for Android
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。