Android中APK瘦身优化

285 阅读5分钟

1,APK的组成

APK文件就是一个Zip格式的文件,其中包含构成应用的所有文件,这些文件包括Java类文件、资源文件和包含已编译的文件

APK包含一下目录

META-INF:包含CERT.SF和CERT.RSA签名文件,以及MANIFEST.MF清单文件

assets/:包含应用的资源;应用可以使用AssetManager对象检索这些资源

res/:包含未编译到resources.arsc中的资源(图片、音视频等)

lib/:包含特定于处理器软件层的已编译代码,此目录包含每种平台类型的子目录,如armeabi、armeabi-v7a、arm64-v8a、x86、x86_64和mips。

APK还包含一下文件,在这些文件中,只有AndroidManifest.xml是必须的

resources.arsc:包含已编译的资源,此文件包含res/values/文件夹的所以配置中的xml内容,打包工具会提取此xml内容,将其编译为二进制文件形式,并压缩内容,此内容包括语言字符串和样式,以及未直接包含在resource.arsc文件中的内容(例如布局文件和图片),此内容语言字符串和样式,以及未直接包含在resources.arsc文件中的内容(例如布局文件和图片)的路径

Classes.dex: 包含以Dalvik/ART虚拟机可理解的DEX文件格式编译的类

AndroidManifest.xml:包含核心Android清单文件,此文件列出了应用的名称、版本、访问权限和引用的库文件,该文件使用Android的二进制XML格式

2,Android Size Analyzer

从菜单栏中一次选择Analyze>Analyze App Size,对当前项目运行应用大小分析,分析了项目后,系统会显示一个工具窗口,其中包含有关如何缩减应用大小的建议

3,启用资源缩减

如果在应用的build.gradle文件中启用了资源缩减: shrinkResources,则Gradle在打包APK时可以自动忽略未使用资源,资源缩减只有与代码缩减,minifyEnabled配合缩减器移除所以不使用的代码后,资源缩减其便可确定应用仍要使用的资源,从而在打包时优化这些资源

Android {
    BuildTypes{
        Release {
            MinffyEnabled true
            ShrinkResources true
            ProguardFiles getDefaultProguardFile(‘proguard-android.txt’), ‘proguard-reles.pro’
        }
    }
}

4,使用Link分析器

Lint工具是android studio中附带的静态代码分析器,可检测到res/文件中未被代码引用的资源,lint工具不会扫描assets/文件夹、通过反射引用的资源或已连接至应用的库文件,此外,它也不会移除资源,只会提醒有未使用的资源

从菜单栏中一次选择analyze > Run Inspection By Name > 输入“unused resources”回车执行

image.png

5,自定义要保留的资源

如果有想要特别声明需要保留或舍弃的特定资源,创建res/raw/keep.xml, tools:keep属性中指定每个要保留的资源,在tools:discard属性中指定每个要舍弃的资源,这两个属性都接受以都好分割的资源名称列表,还可以将星号字符用作通配符

<?xml version=”1.0” encoding= “utf-8” ?>
<resources xmlns: tools = “http://schemas.android.com/tools”
Tools:keep= “@layout/1_used*_c, @layout/1_used_a, @layout/1_used_bTools:discard = “@layout/unused2”/>

6,移除未使用的备用资源

一般开发我们都会引入各种依赖,这些依赖可能包含各种备用资源,如中文,英文、日韩文等等。如果我们不需要这些语言可以让他们不打包进入Apk android { .... resConfig "zh_rCN" } 如上设置打出来的包,会包含英语、zh和zh_rCN语言的apk

7,动态库打包配置

目前Android打包可以支持如下CPU架构

armeabi-v7a 第七代 ARM v7,使用硬件浮点运算,具有高级扩展功能(支持armeabi和armeabi-v7a,目前大部分手机都是这个架构) arm64-v8a 第8代,64位,包含AARch32、AA 64两个执行状态对应32、64bit(支持armeabi-v7a、armeabi和arm64-v8a) x86 intel 少数的平板应用此架构,支持armeabi(性能有所损耗)和x86 x86_64 intel 64位,少数的平板应用此架构(支持x86和x86_64)

目前市面上手机设备绝大多数都是arm架构,因此armv7a几乎兼容所有设备,大多数应用只会打包armv7a的so在Apk中,对于第三方服务,如百度地图、Bugly等会提供全平台的CPU架构,因此我们可以进行如下配置,指定直达armv7a到apk,从而减少apk大小

android {
    defaultConfig {
        ndk{
            abifilters "armeabi-v7a"
        }
    }
}

对于arm64架构的设备,如果使用armv7a也能够兼容,但是不使用arm64的so性能,随着现在arm64架构设备渐渐称为主导,因此现在部分应用时长会根据设备提供不同架构的Apk安装,此时我们需要打包出针对arm64的apk与armv7a的apk,可以使用productFlavor也可以使用APK分包:splits

flavorDimensions “default”
productFlavors{
    arm32{
        dimension "default"
        ndk{
            abiFilters "armeabi-v7a"
        }
    }
    arm64{
        dimension "default"
        ndk{
            abiFilters "armeabi-v7a"
        }
    }
}

splits {
    abi {
        enable true
        reset()
        inclue 'arm64-v8a','armeabi-v7a'
        universalApk true
    }
}

8,使用矢量图

矢量图可以创建与分辨率无关的图标和其他可伸缩媒体,使用这些图形可以极大地减少APK占用的空间,矢量图在android中以VectorDrawable对象的形式表示,借助VectorDrawable对象,100字节的文件可以生成与屏幕大小相同的清晰图片

不股票,系统渲染每个VectorDrawable对象需要花费大量时间,而较大的图片则需要更长的时间才能显示在屏幕上,因此,建议仅在显示小图片时使用这些矢量图

image.png

其他 使用精简版本的依赖:如protobuf-lite版本,对于分模块的库按需引入,如netty分模块引入 主动移除无用代码(开启R8/Progurad自动移除) 避免使用枚举,使用@IntDef代替 不常用功能模块使用插件化加载 开启资源混淆:github.com/shwenzhang/… 支付宝删除Dex debugItem juejin.im/post/684490… 对于发布Google play的应用选择使用: AAB developer.android.google.cn/guide/app-b…