Android性能优化 - apk包体优化
- 随着APP迭代,业务逻辑增加修改,没用的资源可能越来越多,导致包体越来越臃肿,消耗更多的手机资源。 应用的包体大小影响会很多,比如客户看了就不想安装,比如发包上传时等待时间久。
- 因此我们有必要学习怎么清除无用资源,不影响使用的情况下尽可能压缩资源。
1.了解apk包结构
-
我们以微信的apk包为例,看看有什么东西。
在这里插入图片描述 -
assets 包含应用的资源;应用可以使用 AssetManager 对象检索这些资源。
assets
-
lib 包含特定于处理器软件层的已编译代码。此目录包含每种平台类型的子目录,如 armeabi 、armeabi-v7a 、 arm64-v8a 、 x86 、 x86_64 和 mips。微信的只有arm64-v8a,那是因为目前Android机子大部分都是arm架构,没必要放什么x86。
lib
-
META-INF 包含 CERT.SF 和 CERT.RSA 签名文件,以及 MANIFEST.MF 清单文件。
META-INF
-
res 包含未编译到 resources.arsc 中的资源(图片、音视频等),微信这里是r。
res
-
AndroidManifest.xml 这里的Manifest打开是二进制文件,包含核心 Android 清单文件。此文件列出了应用的名称、版本、访问权限和引用的库文件。
AndroidManifest.xml
-
.dex文件非常多,包含以 Dalvik/ART 虚拟机可理解的 DEX 文件格式编译的类。Android的虚拟机就是用dex文件。
在这里插入图片描述
-
resources.arsc 包含已编译的资源。此文件包含 res/values/ 文件夹的所有配置中的 XML 内容。打包工具会提取此 XML 内容,将其编译为二进制文件形式,并压缩内容。此内容包括语言字符串和样式,以及未直包含在 resources.arsc 文件中的内容(例如布局文件和图片)的路径。
resources.arsc
-
以我自己项目apk为例,也可以分析各个资源占用包体大小的情况。
在这里插入图片描述 -
在自己工程里面,反编译好了,可以直接看类。
在这里插入图片描述 -
已编译的资源文件也能看到。
2.具体优化
2.1 图片优化
- 用 webp 替代jdp,png,用 Android Size Analyzer 插件可以帮你找到要替换的图片。
- 使用矢量图 SVG ,矢量图无论放大缩小都没有锯齿,非常适合做图标 。
- iconfont - 阿里矢量图图库
使用SVG
调节参数
- 使用 hint 可以修改颜色,这样就不需要再加入新的图片了。
<!-- android:tint 可以修改颜色 -->
<ImageView
android:layout_width="100dp"
android:layout_height="100dp"
android:src="@drawable/ic_home"
android:tint="#2196F3"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent" />
- 如果是点击变颜色,配置select就行。
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="#2196F3" android:state_pressed="true"/>
<item android:color="#E91E63" android:state_pressed="false"/>
</selector>
<!-- android:tint 可以修改颜色 -->
<ImageView
android:layout_width="100dp"
android:layout_height="100dp"
android:src="@drawable/ic_home"
android:tint="@color/click_color"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent" />
2.2 Android Size Analyzer插件
-
Android studio搜索不到这个插件,去网上下载,我这里有下载好的,直接安装重启就行。
Android Size Analyzer 下载地址
Android Size Analyzer 云盘链接下载,提取码:c777 -
Analyze -> Analyze App Size,就可以按照提示的优化,比如我这个demo,就提示图片建议转webp。
Android Size Analyzer
2.3 开启压缩
Google官方推荐 使用 R8 压缩您的应用
- 如果在应用的 build.gradle 文件中启用了资源缩减: shrinkResources ,则 Gradle 在打包APK时可以自动忽略使用资源。 资源缩减只有在与代码缩减: minifyEnabled 配合使用时才能发挥作用。在代码缩减器移除所有不使用的代码后,资源缩减器便可确定应用仍要使用的资源 。
android {
buildTypes {
release {
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
debug{
}
}
}
-
可以配置keep.xml 保留资源。 还可以将星号字符用作通配符。
在这里插入图片描述
<?xml version="1.0" encoding="utf-8"?>
<!-- keep:保留的资源,无论是否使用 -->
<!-- discard:要舍弃掉的资源 -->
<resources
xmlns:tools="http://schemas.android.com/tools"
tools:keep="@layout/BaoActivity.xml,@drawable/bao_*.jpg"
tools:discard="@layout/TestActivity.xml" />
2.4 使用Lint分析器
-
Analyze -> Run Inspection by Name
Analyze - 输入 Unused resource。
Analyze - 选择分析的范围。
-
分析结果再删除,这里建议还是一个个过,确保没地方使用再删除。
删除资源 -
lint 工具不会扫描 assets/ 文件夹、通过反射引用的资源或已链接至应用的库文件。此外,它也不会移除资源,只会提醒您它们的存在。
-
xml使用的 assets 资源
<com.airbnb.lottie.LottieAnimationView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:src="@drawable/playerdetail_detail_like_nor"
app:lottie_imageAssetsFolder="images"
app:lottie_scale="0.5" />
- 反射引用资源:
getResources().getIdentifier("layout_main","layout",getPackageName());
2.5 使用指定语言
- 其他语言可能有备用资源,加入配置,删除不需要的语言,一般国际化APP会重新开个工程,而不是替换语言那么简单。
android {
defaultConfig {
resConfigs "zh-rCN"
}
}
-
开启后可以打包对比效果。
没有移除备用资源
移除备用资源
2.6 动态库打包配置
- so文件是由ndk编译出来的动态库,是 c/c++ 写的,所以不是跨平台的。ABI 是应用程序二进制接口简称(Application Binary Interface),定义了二进制文件(尤其是.so文件)如何运行在相应的系统平台上,从使用的令集,内存对齐到可用的系统函数库。在Android 系统中,每一个CPU架构对应一个ABI,目前支持的有:armeabi-v7a,arm64- v8a,x86,x86_64。目前市面上手机设备基本上都是arm架构, armeabi-v7a 几乎能兼容所有设备,arm64-v8a 是比较新的手机使用,性能更好。
- 在 app的build.gradle 配置一下,像微信的包就只留了arm64-v8a 。
android {
defaultConfig {
ndk{
abiFilters "arm64-v8a"
}
}
}
-
比如我们接入地图或其他的SDK,他们里面自带比较全的动态库,就可以像上面这样配置,保留 armeabi-v7a 也是能基本满足,我们也可以打几种包,上架应用市场时,应用市场会根据手机下载合适的包。
-
在 app的build.gradle 配置一下,我们可以选arm32,arm64。
android {
flavorDimensions "default"
productFlavors{
arm32{
dimension "default"
ndk{
abiFilters "armeabi-v7a"
}
}
arm64{
dimension "default"
ndk{
abiFilters "arm64-v8a"
}
}
}
}
-
加入上面代码后我们可以选择架构。
arm - 还可以一次性打多个。
android {
splits {
abi {
enable true
reset()
include 'arm64-v8a','armeabi-v7a'
universalApk true //是否打包一个包含所有so的apk
}
}
-
打了3个,其中一个是包含所有动态库的包。
多个包
3. 总结
- 包体优化以后还有其他内容,学习了就更新,我个人是建议一段时间整理一下工程,这样找资源也方便;跟生活一样,除了定时整理,平时良好的习惯也能让你更舒服。