当前位置: 首页 > Web前端 > HTML

Android编译优化常见问题

时间:2023-03-28 17:36:02 HTML

CompilationCommonProblems在开发过程中,我们遇到过一些编译优化导致的代码修改没有达到我们预期的情况。这就是为什么我经常说编出来的产品其实不太值得信赖。方法签名改了,底层仓库的方法改了,但是上层模块没有跟着重新编译,导致这个问题。常量优化,直接将一些常量调用点替换为常量值。删除空的引导包,一些无用的引导包会被一次性淘汰。我们最近运气不好。我们最近遇到了一个与管道相关的非常可怕的问题。我们的一个pipeline会检查apk产品中是否有异常的方法调用,也就是在前面介绍的R8基础上开发的A8。但是最近删除了一个类之后,代码中还有一个调用点。但是这个测试通过了,然后这部分代码就合并到master里面了。引用的文件,如上图所示,是一个debugbuildType,所以并不是所有的apks都会有这部分代码。然后,这个MergeRequest被合并到master分支,因为那天是我们发布下一个版本包的时间,然后把编译好的debug和release包交付给test。其他开发同学rebasemaster后,发现pipeline无法运行,导致他们当天的代码无法合并。这就是事件的大概原因和过程,但是大家有没有想过为什么会出现这个问题呢?是不是因为我们的pipeline有bug,导致这种问题无法识别?前面说过,如果简单的说我们的快速编译系统就是把module替换成对应的aar,从而加快编译速度。所以因为我们使用的是这个模块对应的aar产品,所以这个问题很大概率是因为这个模块的编译产品和源码不一样导致的。其实这个问题一出现,我就知道很有可能是空引导包的优化导致的,因为在流水线检测的时候,检测到的apk产品中是不存在这个引导包的。因为我们使用的是历史版本的aar,无效导入包的部分已经被编译器优化,删除了空导入包。接下来我们看一下我写的一个demo中的invalidimportpackage。图1是源代码java文件,图2是jar包中的代码。很容易看出,行号可以对应,但是AppCompatActivity的无效导入包在产品中已经优化。这里也给出了编译过程中会保留行号的答案,但是一些不必要的代码也会进行优化,这样编译出来的产物会更小。所以也导致了我们的产品和我们的源码不一样。另外一个角度是我们apk里面确实没有这个类的import包。但是当我们将这部分代码重新编译成aar的时候,就会缺少源码,导致语法树无法生成,进而导致编译失败。这就是为什么我一直告诉大家,编译出来的产品不可信任。我以前运气不好。这是以前的故事。我们之前在模块中定义了一些静态常量,然后用它们来标识当前的SDK版本,然后在其他模块中引用这个值。有一次我们因为需求的变化改变了这个静态变量的值,然后我测试了这个需求。后来测试反馈给了我为什么这里的值没有变化。天哪,我就是这样,发生了什么事。然后我把所有的包都打包了,我以为只是编译的一个bug。然后后来查了资料,发现这是java编译时不断优化的问题。过了一段时间,我面试了字节跳动,然后和面试官聊了聊这个话题,然后在更改方法签名的问题上,我当时有点自卑,哈哈哈哈。接下来我们看下一个demo。图一也是java代码,图二是aar中的编译产物。其中,我们可以看到这个静态常量在编译成产品后会被编译成this。所以这就解释了我一开始遇到的问题,是因为我们的编译器把aar中的这部分静态常量直接编译成了一个值,然后如果我们源码发生变化,如果不重新编译相应的模块,就会导致该值无法更新为最新值。