Android性能优化系列之APK瘦身(二)

96
鱼__鱼
2017.12.08 15:28* 字数 2874
jianshu_0019.jpg

学习目标
1.学习了解ABI,.so文件,ABI和CPU的关系
2.多分辨率适配
3.图片处理

ABI

API管理
不同Android手机使用不同的CPU,因此支持不同的指令集。CPU与指令集的每种组合都有其自己的应用二进制界面(或ABI)。ABI 可以非常精确地定义应用的机器代码在运行时如何与系统交互。 您必须为应用要使用的每个 CPU 架构指定 ABI。

jianshu_0020.png

.so文件

.so文件是unix的动态连接库,是二进制文件,在Android中调用动态库文件(*.so)都是通过JNI的方式,这里我们要说说NDK,Android NDK是一个工具集,它让我们能够在Android应用程序中使用由本地代码(native code)编写的代码模块,NDK 提供的编译系统让我们可以高效的编译源码,不需要去处理工具链、平台等细节。我们只需要创建很短的编译文件,描述哪些源文件要编译以及哪些应用程序会使用它们,编译系统就会编译源代码并且将编译生成的共享库(shared libraries)直接放到我们的应用程序中。如果项目中使用到了NDK,它将会生成.so文件,因此显然你已经在关注它了。如果只是使用Java语言进行编码,你可能在想不需要关注.so文 件了吧,因为Java是跨平台的。但事实上,即使你在项目中只是使用Java语言,很多情况下,你可能并没有意识到项目中依赖的函数库或者引擎库里面已经嵌入了.so文件,并依赖于不同的ABI,Android应用支持的ABI取决于APK中位于lib/ABI目录中的.so文件。

通过上文我们可以使用Android Studio工具查看一下淘宝、微信、京东的.so文件如下图
Android性能优化系列之APK瘦身(一)

淘宝.png
微信.png
京东.png

可以看出上述APP都只使用了armeabi,是不是发现了什么,我们也可以只支持armeabi,来达到APK瘦身
为什么可以只支持一种呢?
用一种的好处和缺点呢?
请接着往下看

ABI和CPU的关系

很多设备都支持多于一种的ABI。例如ARM64和x86设备也可以同时运行armeabi-v7a和armeabi的二进制包。但最好是针对特定平台提供相应平台的二进制包,这种情况下运行时就少了一个模拟层(例如x86设备上模拟arm的虚拟层),从而得到更好的性能(归功于最近的架构更新, 例如硬件fpu,更多的寄存器,更好的向量化等)。

我们可以通过Build.SUPPORTED_ABIS得到根据偏好排序的设备支持的ABI列表。但你不应该从你的应用程序中读取它,因为 Android包管理器安装APK时,会自动选择APK包中为对应系统ABI预编译好的.so文件,如果在对应的lib/ABI目录中存在.so文件的话。

配置.so文件

1.在app文件夹build.gradle下选择添加的.so库,然后gradle.properties文件中添加如下代码即可,重新编译工程即可。

       ndk {
            //选择要添加的对应cpu类型的.so库。
            abiFilters 'armeabi-v7a'
            // 还可以添加 'armeabi','armeabi-v8a', 'x86_64', 'mips', 'mips64', 'x86'
        }
android.useDeprecatedNdk=true
jianshu_0024.png

不同CPU架构的Android手机加载时会在libs下找自己对应的目录,从对应的目录下寻找需要的.so文件;如果没有对应的目录,就会去armeabi下去寻找,如果已经有对应的目录,但是如果没有找到对应的.so文件,也不会去armeabi下去寻找了。 所以,这里需要注意工程配置哪几个so文件目录,需要加载对应的so文件,不然会报错。

如何适配各个目录,例如有一些第三方的类库只提供了armeabi下的.so文件,而工程配置不止armeabi一个目录,这就需要将armeabi下的.so文件复制到其他对应的目录下。如果第三方提供了不同平台的.so文件,则复制不同平台的.so文件到项目中对应的文件夹下即可。

目前市面上的安卓手机,绝大多数的CPU都是基于ARM架构的,所以如果不是必要的话,可以考虑不支持x86和mips架构,但这并不意味着CPU是x86或mips架构的手机就不能正常安装使用APK了,因为放在arm目录下的so库是可以兼容到其它架构的。

另外armeabi架构中的armeabi-v7a相比于armeabi只是在图形渲染方面有了很大的改进,所以如果so库对图形渲染没有很高的要求的话,完全可以把so库只存放在armeabi目录中,这样可以大大减小APK的体积。

注意
1.你应该尽可能的提供专为每个ABI优化过的.so文件,你不应该混合着使用(不能就装对不同cpu架构的so文件,放在同一个ABI目录下)。你应该为每个ABI目录提供对应的.so文件。
2.当只有一个.so文件时,静态编译C++运行时是没问题的,
3.当存在多个.so文件时,应该让所有的.so文件都动态链接相同的C++运行时。
4.这意味着当引入一个新的预编译.so文件,而且项目中还存在其他的.so文件时,我们需要首先确认新引入的.so文件使用的C++运行时是否和已经存在的.so文件一致。

矛盾
1.为了保险起见,最好支持armeabi和armeabi-v7a
2.但是有代码洁癖或强迫症纠结于只支持其一,到底是支持arm还是arm-v7a呢?
最后看大家场景,可以参考大厂的做法,也可以保险使用

多分辨率适配

能否用一套图适配?
☺一套图?没听错吧,大家都说我们Android适配挺难的,早期要四套图,近两年两套图,现在只要一套图就可以了?匪夷所思,尴尬~~~开发人员简直不要太爽...
这里简单说一下Android屏幕适配问题

在我们学习如何进行屏幕适配之前,我们需要先了解下为什么Android需要进行屏幕适配。
由于Android系统的开放性,任何用户、开发者、OEM厂商、运营商都可以对Android进行定制,修改成他们想要的样子。
但是这种 "碎片化" 到底到达什么程度呢?

OpenSignalMaps 统计数据表明

  • 2012年,支持Android的设备共有3997种。
  • 2013年,支持Android的设备共有11868种。
  • 2014年,支持Android的设备共有18796种。
  • 2015年, 支持Android的设备共有24093种。

下面两张图所显示的内容足以充分说明当今Android系统碎片化问题的严重性,因为该图片中的每一个矩形都代表着一种Android设备。

@2014

jianshu_0025.png

@2015

jianshu_0026.png

而随着支持Android系统的设备(手机、平板、点事、手表)的增多,设备碎片化、品牌碎片化、系统碎片化、传感器碎片化和屏幕碎片化的程度也在不断地加深。而我们今天要探讨的,则是对我们开发影响比较大的---屏幕的碎片化。

下面这张图是Android屏幕尺寸的示意图,在这张图里面,蓝色矩形的大小代表不同尺寸,颜色深浅则代表所占百分比的大小。

jianshu_0027.png

而与之相对应的,则是下面这张图。这张图显示了iOS设备所需要进行适配的屏幕尺寸和占比。

jianshu_0028.png

上面数据看的是不是很抓狂,很抓狂,很抓狂,简而言之,就是Android碎片化太严重了。
但是呢,总是有办法解决的嘛,我们只做主流智能手机的适配。
下面看友盟数据分析

jianshu_0029.png

从上图我们通过计算得出,目前的设备前四个占据大份额(77.6%)的分辨率的手机屏幕长宽都是按照比例缩放的。

  1. Android系统的图片寻找机制对放在xhdpi,xxhdpi等不同密度的图片会根据手机的密度寻找最合适的文件夹下的图片,然后进行根据密度的比率进行放大,缩小处理。
  2. 意味着一张背景图如果是1280 × 720大小的话,放在上述分辨率手机上都是可以无变形缩放的。目前我们的设计师大多情况都是按照iOS手机来设计界面的,主流是按照iphone6(1334 × 750),一计算,你也会发现,这个也是和上述主流分辨率长宽有对应的比率关系。

结论:我们设计师如果按照iphone6设计屏幕的话,Android是可以一套图片就可以达到界面的适配,只不过放在xhdpi或者xxhdpi下面,Android SDK会自动屏幕尺寸选择对应的资源文件进行渲染,如SDK检测到你手机dpi是320的话会优先到drawable-xhdpi文件夹下找对应的图片资源,注意只是优先,假设你手机dpi是320,但是你只在xxhdpi文件夹下有对应的图片资源文件,程序一样可以正常运行。
所以理论上来说只需要提供一种规格的图片资源就ok了,如果只提供hdpi规格的图片,对于大分辨率的手机如果把图片放大就会不清晰,所以需要提供一套需要支持的最大dpi的图片,这样即使用户的手机分辨率很小,这样图片缩小依然很清晰。

图片存放

既然一套图可以达到界面的适配,那应该采取哪一套图,又应该放在Android下面的drawable还是mipmap下面,如果是放在drawable下面,又应该放在xhdpi、xxhdpi、xxxhdpi还是别的密度下呢?

图片处理

经过@多分辨率适配,我们去除了最少一半的图片资源,重新分析下APK是不是感觉小了很多,这次我们来对图片进行处理,会发现,小的更多。
怎么处理呢?

  1. 压缩
  2. WEBP
  3. SVG

总结

参考链接

  1. Android官方ABI详解
  2. Android ABI想到的
  3. Android屏幕适配(基于实战考虑...)
  4. Android 屏幕适配:最全面的解决方案
  5. 【友盟+】2017年1月手机分析报告
Android 性能优化
Web note ad 1