APK 编译打包 笔记

一图流


687474703a2f2f75706c6f61642d696d616765732e6a69616e7368752e696f2f75706c6f61645f696d616765732f333938353536332d636462613331396461623332643063372e706e673f696d6167654d6f6772322f6175746f2d6f7269656e742f737472697025.png

1.Java编译器对工程本身的java代码进行编译,这些java代码有三个来源:app的源代码,由资源文件生成的R文件(aapt工具),以及有aidl文件生成的java接口文件(aidl工具)。产出为.class文件。

①用AAPT编译R.java文件

②编译AIDL的java文件

③把java文件编译成class文件

2..class文件和依赖的三方库文件通过dex工具生成Delvik虚拟机可执行的.dex文件,包含了所有的class信息,包括项目自身的class和依赖的class。产出为.dex文件。

3.apkbuilder工具将.dex文件和编译后的资源文件生成未经签名对齐的apk文件。这里编译后的资源文件包括两部分,一是由aapt编译产生的编译后的资源文件,二是依赖的三方库里的资源文件。产出为未经签名的.apk文件。

4.分别由Jarsigner和zipalign对apk文件进行签名和对齐,生成最终的apk文件。

总结为:编译-->DEX-->打包-->签名和对齐

Desugaring脱糖

不同的Android版本支持的Jvm版本不同,当使用当前Abndroid版本不支持的高版本jdk语法时,需要在编译期转换为其支持的低版本jdk语法,这个过程成为desugaring脱糖。
我们分别在Android R (API 30)和 Android M (API 23)上分别调用Java8新引入的时间API

tv_month.text = LocalDate.now().month.name
image.png

AndroidR可以正常运行,但是AndroidM出现了NoClassDefFoundError

为解决此问题,我们需要开启Desuguring功能

  • 升级AGP到4.0或者更高
  • compileOptions设置1.8
  • 开启multidex
  • 添加Desugaring依赖
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.0.5'

Desuguring是如何实现的呢?是借助dex编译器D8与R8实现的。

Dex Compiler:D8与R8

早期,Android从源码到字节码再到dex的编译过程如下,中间使用Proguard进行字节码优化:


image.png

由于过程复杂,2015年左右Google退出了Jack&Jill编译器,减少了中间环节:


image.png

过与简化的编译过程,无法在过程中加入更多优化,因此Google在2017年废弃了Jack&Jill,重新回到了之前的编译流程,只是重写了最后一步dex编译器,称之为D8。一个完整的编译流程需要Proguard和D8同时参与其中


image.png

R8的出现整合了Proguard和DB,减少了一个编译步骤,同时保留了字节码优化的能力。


image.png

Desugaring的工作原理是 R8/D8在字节码编译成Dex文件时,通过三方库的引入支持了原本不支持的高版本JDK语法,并一同打进dex,使之可以正常工作

image.png

使用R8优化包体积

R8在D8的基础上又增加了Proguard的能力,通过开启Shrinking,可以对源码进行优化,以达到减小包体积的目的,具体包括但不限于:

  • 代码删除:通过语法树静态分析技术,发现并剔除未使用的代码,例如没有被实例化的Class等
  • 代码优化:对运行时代码进行优化,包括死代码删除、未使用的参数删除、选择性内联、类合并等。
  • 代码混淆:优化标识符名字,减少代码数量,例如MyAwesomeClass可能被优化成单一字母a

在build.gradle中开启添加一下配置开启Shrinking

android {
    ...
    buildTypes {
        release {
            minifyEnabled false
        }
    }
}

proguard-rule文件中定义优化规则,Android提供了默认的rule文件配置了Android组件类的优化

minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt')

例如针对如下代码

class JavaHelloWorld {

    //unreachable code
    private void iAmUnused() {
        System.out.println("I am of no use ");
    }

    //reachable code
    private static void reachableExample() {
        System.out.println("Hello, World ");
    }

    //main function
    public static void main(String[] args) {
        reachableExample();
    }
}

R8会进行如下优化

  • iAmUnused作为不可达代码进行删除
  • reachableExample被内联到main中
    优化后的代码变为
class JavaHelloWorld {
    
    //main function
    public static void main(String[] args) {
        System.out.println("Hello, World ");
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容