Android 包体积优化实战

了解APK结构

  • classes.dex: 代码文件

传统的Java程序,首先先把Java文件编译成class文件,字节码都保存在了class文件中,Java虚拟机可以通过解释执行这些class文件。而Dalvik虚拟机是在Java虚拟机进行了优化,执行的是Dalvik字节码,而这些Dalvik字节码是由Java字节码转换而来,一般情况下,Android应用在打包时通过AndroidSDK中的dx工具将Java字节码转换为Dalvik字节码。

  • assets目录:

用于存放需要打包到APK中的静态文件,这些资源不会被编译成二进制。

  • lib目录:

这里存放应用程序依赖的native库文件。

  • res目录:

这个目录存放资源文件,直接将项目的res目录打包进来。

  • resources.arsc:

用来记录资源文件和资源ID之间的映射关系,用来根据资源ID寻找资源。包括stirng,id,anim,style,mipmap,dimen等类型。

  • META-INF:(签名信息相关)

AndroidSDK在打包APK时会计算APK包中所有文件的完整性,并且把这些完整性保存到META-INF文件夹下,应用程序在安装的时候首先会根据META-INF文件夹校验APK的完整性,这样就可以保证APK中的每一个文件都不能被篡改。META-INF目录下包含的文件有CERT.RSA,CERT.DSA,CERT.SF和MANIFEST.MF,其中CERT.RSA是开发者利用私钥对APK进行签名的签名文件,CERT.SF,MANIFEST.MF记录了文件中文件的SHA-1哈希值。

  • Androidmenifest.xml:

清单配置文件自不必说。

包体分析

1.包体分析主要借助的是腾讯 AppChecker 完成的,AppChecker 分析包文件主要还是借助了 andoid build-tool 下面的 aapt 工具。关于 AppChecker 使用指南可以参考下面的链接:
https://github.com/Tencent/matrix#matrix_android_cn

2.利用应用市场发包情况可以绘制 iOS/Android 的安装包大小变化趋势图。

3.竞品对比

APK 文件大小排行榜可以参考下图,按照大小从上至下进行排序即可。


相似图片监测可能需要使用 AI 技术,重复资源分析用 AppChecker 即可完成目的。
当然无用资源分析也可以用 AppChecker 完成。

压缩Apk具体措施

  • 使用混淆、启动资源缩减

在gradle使用minifyEnabled进行Proguard混淆的配置,可大大减小APP大小。

buildTypes {
        release { 
            minifyEnabled true
            shrinkResources true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
  • 删除无用资源

从Code->Analyze code ——> Run Inspection by Name进入,输入unused resources。


对整个项目或者某个模块进行未使用资源扫描。

可以看到扫描结果下,没用到的资源,会标明warning,可以选择单个删除还是统一删除。


  • so文件缩减

如果一个app,用c、c++来写功能,打包到so库中使用,性能会比在java层写的代码更高。比如微信的so库的代码比重比价大,微信对性能要求很高。

如果项目中使用到so库,只需要打armeabi-v7a、armeabi-v8a架构,就可以兼容绝大多数cpu类型,这样可以减少apk中lib大小。 现在你可以只打armeabi-v7a,或者只打armeabi-v8a一个文件就可以了,比如微信都只用v8a了。

android {
    defaultConfig {
        ndk {
            abiFilters 'armeabi-v8a'
        }
    }
}
  • 使用体积更小图片——使用wepb、SVG、iconfont图片

使用Webp来代替JPG和PNG图片,它保留了JPG和PNG优点的同时,能提供更好的压缩,达到更小的体积。

WebP的优势在于它具有更优的图像数据压缩算法,在拥有肉眼无法识别差异的图像质量前提下,带来更小的图片体积,同时具备了无损和有损的压缩模式、Alpha 透明以及动画的特性,在 JPEG 和 PNG 上的转化效果都非常优秀、稳定和统一。会比转为png和jpg的图片小25%-35%。

你可以使用矢量图形来绘制分辨率无关图标及其他可伸缩媒体文件。整个屏幕那么大的清晰图片,如果使用矢量图可能只需要100-byte大小。

  • webp和png的区别

PNG 转 WebP 的压缩率要高于 PNG 原图压缩率,同样支持有损与无损压缩
转换后的 WebP 体积大幅减少,无损压缩后的 WebP 比 PNG文件少了 45% 的文件大小,图片质量也得到保障(同时肉眼几乎无法看出差异),
转换后的 WebP 支持 Alpha 透明和 24-bit 颜色数。

可见除了 WebP 在解码时间与 PNG 有较明显差异(毫秒级别)之外,总体使用体验和 PNG 基本无差异。

解码耗时:WebP 的解码时间是 PNG 格式的 4-5 倍(24.8ms)
流畅程度:两种格式下,AIO 滑动流畅度无明显差异
CPU使用:两种格式下,连续发送 15 个表情,CPU 使用均在 10%—26% 之间波动,两者无明显差异
内存占用:两者格式下,连续发送 15 个表情,PSS 内存占用跨度均为 11M,无明显差异

使用矢量图

最佳方式,是使用矢量图。只需要一套图片,就能在不失真的方式前提下,将图片资源做到最小。从UI设计图上下载SVG格式图片资源,然后在AS中,将SVG转成Vector矢量图来使用。

  • 减小classes.dex包大小

减少代码量,这个就需要看自己团队的实力了,搭建复用性更高的框架,选择更合理的开发模式来减少代码量,能不必要引入的库可以团队完成。

  • 缩减资源——shrinkResources true

假如有一些资源文件不确定还用不用,也不敢删,或者不确定需求是否会变更,所以先留着,那这种情况怎么办呢? 可以使用shrinkResources来缩减资源。

  buildTypes {
        debug {
            minifyEnabled false
        }
        release {
            shrinkResources true
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }

要配合混淆minifyEnabled一起使用才行,原理也很简单,代码移除之后,引用的资源也就变成无用资源了,才可以进一步缩减。

  • 功能重复的三方库整合

比如glide和picasso,都是图片库,保留其一即可。

  • 原生改用H5或小程序等方案

有些功能可能原生做就显得太重,比如各种促销活动,需要加载各种大图,原生既重又不够动态化,这个时候H5是一种很好的替代方案。

  • 资源混淆——AndResGuard

微信混淆方案(AndResGuard)是通过修改aapt在处理资源文件相关的源码达到资源文件的替换。它会将原本冗长的资源路径变短,例如将res/drawable/wechat变为r/d/a。

混淆后的资源文件夹:


1.在项目根目录的gradle文件下加入资源混淆插件:

 dependencies {
        classpath 'com.tencent.mm:AndResGuard-gradle-plugin:1.2.10'
    }

2.在app的gradle下加入配置:

plugins {
    id 'AndResGuard'
}

andResGuard {
    // mappingFile = file("./resource_mapping.txt")
    mappingFile = null
    use7zip = false
    useSign = true
    // It will keep the origin path of your resources when it's true
    keepRoot = false
    // If set, name column in arsc those need to proguard will be kept to this value
    fixedResName = "arg"
    // It will merge the duplicated resources, but don't rely on this feature too much.
    // it's always better to remove duplicated resource from repo
    mergeDuplicatedRes = true
    whiteList = [
            // your icon
            "R.drawable.ic_launcher*",
            "R.anim.umeng*",
            "R.string.umeng*",
    ]
    compressFilePattern = [
            "*.png",
            "*.jpg",
            "*.jpeg",
            "*.gif",
            "*.webp",
    ]
    sevenzip {
        artifact = 'com.tencent.mm:SevenZip:1.2.20'
        //path = "/usr/local/bin/7za"
    }
}

whiteList(白名单)中指定不需要进行混淆的资源路径规则,主要是针对第三方SDK,因为有些SDK的代码中通过getIdentifier()的方式引用到对应的资源文件,如果对其进行混淆,会导致找不到对应资源文件,出现crash。

使用转成aab格式的包

Google Play就是基于对aab文件处理,将App Bundle在多个维度进行拆分,在资源维度,ABI维度和Language维度进行了拆分,你只要按需组装你的Apk然后安装即可。如果你的手机是一个x86,xhdpi的手机,你在google play应用市场下载apk时,gogle play会获取手机的信息,然后根据App Bundle会帮你拼装好一个apk,这个apk的资源只有xhdpi的,而且so库只有x86,其他无关的都会剔除。从而减少了apk的大小。

避免依赖重复库

有的库依赖里面的功能看起来是重复的,那就要考虑将重复、覆盖度高的库进行选择性删除,一种功能用一个库。比如数据库操作,图片加载的,可能有些库隐藏得较深,隐藏在一些库里面,可以gradle命令 ./gradlew dependencies 打印依赖树查看有没有重复依赖库的问题。
找到之后直接移除,或者exclude移除。

本地图片转网图

我们可以手动把本地图片上传到oss-browser[17]进行预加载,然后删除本地图片,修改代码加载网络图片。

插件化技术

插件化,商业收益非常明显,基本上各个大厂都有做插件化,方便生成轻量级 Android 应用,通过插件化去加载非核心模块,大家可以看一下市面上常见的八种插件化工具对比图,再选择更适合自己企业的插件化工具。

SO动态加载

动态加载 So 库其实是一些边缘功能的 So 库或者使用时机比较晚的 So 库可以考虑动态加载;不使用时so库不再jniLibs目录下,不打进apk中。需要使用时,去网络地址下载So库,然后再loadLibrary进行加载使用。

步骤一: 下载so
步骤二:拷贝so至私有data目录
步骤三:通过绝对路径加载so

R8优化

Android构建中,在AGP3.4.0之前也是使用的ProGuard 进行代码优化混淆,但是在3.4.0之后,谷歌将这一工作赋予给了性能更佳的R8编译器。
虽然摒弃了ProGuard,但是R8编译器还是兼容ProGuard的配置规则。

使用R8编译器可以做以下优化:

1.代码缩减:
代码缩减指的是:R8编译期智能检测代码中未使用到的类、字段、方法和属性等,并移除。

2.资源缩减
资源缩减是在代码缩减之后进行的,只有去除了不需要的代码后, 才可以知道哪些代码里面的资源也是不被引入,可以移除的。
资源缩减只要在模块gradle下面添加shrinkResources属性即可。

3.代码混淆
混淆指的是将类名,方法名,属性名使用无意义的字符来表示

4.代码优化
为了进一步缩减应用,R8 会在更深的层次上检查代码,以移除更多不使用的代码,或者在可能的情况下重写代码,以使其更简洁。

R8参考:https://juejin.cn/post/7225511164120891453

实战压缩apk

当前这个demo apk压缩之前大小是25.6M,然后接下来进行瘦身。


可以看到,这个apk包体积占用大户就是res资源文件,第二大户就是代码文件,如果有so文件,会将so文件作为第三大户进行瘦身。


第一步:

开启混淆压缩代码资源:

    buildTypes {
        debug {
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
        release {
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }

打出新包,包体积缩小到21M,效果比较明显:


第二步:

通过unused resource删除无用资源:


并且开启shrinkResources:

 debug {
            minifyEnabled true
            shrinkResources true //强力删除无用资源,不打包进apk,需配合minifyEnabled一起使用
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }

做完压缩到20.8M,效果不明显


第三步

将apk中占用体积大比重的图片资源删除,或者用webp、矢量图来替换。
修改之前各个大图片,从几百k到1M多不等:


删除和修改为webp之后的:


做完压缩成了4.9M,压缩效果最明显:


参考:
https://mp.weixin.qq.com/s/g2j-V4Rqn4Zrb1x1Ilev2A
https://mp.weixin.qq.com/s/NiV51jOeCnTRgo-TLFsw7g
https://blog.csdn.net/Android_machong/article/details/53258924

压缩实战demo地址:

https://github.com/running-libo/Tiktok

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容