• 欢迎访问搞代码网站,推荐使用最新版火狐浏览器和Chrome浏览器访问本网站!
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏搞代码吧

Android-编译优化

android 搞代码 3年前 (2022-03-30) 26次浏览 已收录 0个评论
文章目录[隐藏]

软件研发中,消耗最多的并不是编写代码,而是代码编译和代码一直调试的过程。对于咱们Android来说,随着我的项目的一直迭代,以及业务模块的一直减少,我的项目技术栈的减少,我的项目编译会越来越慢。随着业务的扩大,置信很多的公司都曾经做了模块化/组件化。

背景

创立一个 Project 后能够创立多个 Module,这个 Module 就是所谓的模块。一个简略的例子,可能在写代码的时候咱们会把首页、音讯、我的模块拆开,每个 tab 所蕴含的内容就是一个模块,这样能够缩小 module 的代码量,然而每个模块之间的必定是有页面的跳转,数据传递等,比方 A 模块须要 B 模块的数据,于是咱们会在 A 模块的 gradle 文件内通过 implementation project(':B')依赖 B 模块,然而 B 模块又须要跳转到 A 模块的某个页面,于是 B 模块又依赖了 A 模块。这样的开发模式仍然没有解耦,改一个bug仍然会改变很多模块,并不能解决大型项目的问题。于是就有了组件的概念,咱们日常业务需要开发的组件叫做业务组件,如果这个业务需要是能够被广泛复用的,那么叫做业务根底组件,譬如图片加载、网络申请等框架组件咱们称为根底组件。于是一个典型的组件化架构通常如下图所示。

实线示意间接依赖关系,虚线示意间接依赖。比方壳工程必定是要依赖业务根底组件、业务组件、module_common公共库的。业务组件依赖业务根底组件,但并不是间接依赖,而是通过”下沉接口“来实现间接调用。业务组件之间的依赖也是间接依赖。最初common组件依赖所有须要的根底组件,common也属于根底组件,它只是对立了根底组件的版本,同时也提供了给利用提供一些形象基类,比方BaseActivity、BaseFragment,根底组件初始化等。

编译优化

Android编译流程

Android apk的编译构建分为四个步骤:

  1. 代码编译:将源代码,R文件,AIDL生成的文件等 编译成.class文件;
  2. 代码合成:通过dex工具将.class文件和工程依赖的第三方库文件生成虚拟机可执行的.dex文件,如果应用了MultiDex会产生多个dex文件;
  3. 资源打包:apkbuilder工具将.dex文件,apt编译后的资源文件,三方库中的资源文件打包生成签名对齐的apk文件;
  4. 签名和对齐:应用Jarsigner和Zipalign对文件进行签名和对齐,生成最终的apk文件。

以下是gradle编译一个app module 的task链:

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编译实现

开启InstantRun

Android Studio 2.0 推出了InstantRun,意为霎时编译,在编译开发时缩小利用的部署及构建工夫。如果须要开启InstantRun,须要Gradle2.0和minSdkVersion15以上版本。

构建流程:代码变更–>编译–>利用构建–>利用部署–>app重启–>activity重启–>实现批改变更
实现即时运行的机制:批改代码后,增量构建(产生增量dex),而后通过判断更新资源的复杂度去抉择执行热更新,温更新或者冷更新;

  • 热部署:失效时不须要重启app,也不须要重启activity
  • 温部署:重启activity后能力看到更新
  • 冷部署:app须要重启,但不是重新安装

InstantRun次要干了两件事:

  1. 应用manifest-merger整合我的项目的manifest,通过aapt工具将合成的AndroidManifest.xml文件与res资源编译到增量apk中;
  2. 代码批改后,通过javac将java文件编译成class文件,而后打包成dex文件,同样搁置在增量apk中;

gradle编译优化

咱们晓得,Android工程是应用gradle进行构建的,所以,优化Android的编译工夫,在gradle方面有很多的措施。

properties配置优化

#开启并行编译,仅仅实用于模块化我的项目(存在多个 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

过滤gradle task

在执行构建工作时,选择性的去除并不需要运行的gradle task工作。

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
        }
    }
})

应用本地gradle

应用本地的gradle文件,防止从网络拉取的状况。

其余

将不须要频繁改变的module从setting.gradle中去掉,间接援用module对应的aar文件。工程中有多个module时,会先编译每一个module之后再编译主工程,尽量少的module依赖必定会放慢编译速度。另外,如果你应用的是Kotlin+JetPack形式来构建的Android我的项目,那么能够尝试应用KSP:辞别KAPT,应用KSP为Android编译提速


搞代码网(gaodaima.com)提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发送到邮箱[email protected],我们会在看到邮件的第一时间内为您处理,或直接联系QQ:872152909。本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:Android-编译优化

喜欢 (0)
[搞代码]
分享 (0)
发表我的评论
取消评论

表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址