Android性能优化-减小APK大小

   2016-10-17 0
核心提示:原文链接: Reduce APK Size 前言用户通常会避免下载比较大的应用,特别是连接到2G和3G网络,或者按流量收费的设备。这篇文章描述了如何减小apk的大小,帮助你让更多的用户下载你的app。一 理解APK的结构在讨论如何减小apk大小之前,理解apk的结构很有必要。

原文链接: Reduce APK Size

前言

用户通常会避免下载比较大的应用,特别是连接到2G和3G网络,或者按流量收费的设备。这篇文章描述了如何减小apk的大小,帮助你让更多的用户下载你的app。

一 理解APK的结构

在讨论如何减小apk大小之前,理解apk的结构很有必要。一个APK文件包括一个ZIP 文件,该ZIP包含app的所有文件。包括java 字节码文件,资源文件和一个包含了编译后的资源文件。APK包含以下目录:

  • META-INF/ :包含了 CERT.SFCERT.RSA 签名文件, 以及 MANIFEST.MF manifest 文件.
  • assets/ : 包含了app的assets,app可以通过 AssetManager 对象获取到这些资源
  • res/ : 包含了那些没有被编译到 resources.arsc 的资源
  • lib/ : 包含了用于软件处理器的编译代码,该目录包含一个子目录,针对不同平台: armeabi , armeabi-v7a , arm64-v8a , x86 , x86_64 , and mips .

一个APK也包含了下面的文件,但只有 AndroidManifest.xml 是强制性的

  • resources.arsc :

    包含了编译后的资源。该文件包含了 res/values/ 文件夹下的所有XML内容。打包工具抽取了XML内容,将它编译成二进制格式,并且进行了压缩。该内容包括language strings和styles,以及未直接包含在 resources.arsc 文件中的内容路径。比如layout文件和图片。

  • classes.dex :

    包含可以被Dalvik/ART 识别,以dex文件格式编译后的代码

  • AndroidManifest.xml :

    包含了Android核心mainfest文件。该文件罗列了app名字,版本,访问权限,和引用的library文件。该文件采用二进制XML格式。

    ?

二 减少资源的数量和大小

APK的大小对app的加载速度以及内存的使用和电量消耗都有影响。一种减小APK大小的最简单方法就是减少APK的资源文件数量和大小。也可以移除那些app不再使用的资源,或者使用可扩展的 Drawable 对象替代图片文件。这部分讨论了这些方法,以及其它几种减小app资源以便最终达到减小APK总体大小的其它方法。

移除无用资源

使用 lint 工具,AndroidStudio中的一个静态的代码分析工具。可以检测 res/ 目录下那些没有被引用的资源. 当 lint 工具发现了项目中潜在的无用资源,就会打印类似如下的信息:

res/layout/preferences.xml: Warning: The resource R.layout.preferences appears
to be unused [UnusedResources]

注意: lint 工具不能够扫描 assets/ 目录, assets 资源是通过反射的方式引用的,或者app中引用的其它library 文件。但lint并不会移除资源,它只会提示它们的存在。

你引入的Libraries有可能引入了无用的资源。Gradle可以通过在 build.gradle 文件中开启 shrinkResources 来帮你自动的移除这些资源:

android {
// Other settings

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

为了使用 shrinkResources ,你应该开启code shrinking,在build处理期间, ProGuard 首先会移除无用的代码但是会保留无用的资源。之后Gradle会移除无用的资源。

关于ProGuard和使用Android Studio帮助你减小APK大小的更多信息,可以参考 Shrink Your Code and Resources .

在Android Gradle Plugin 0.7以及更高的版本中,你可以声明app支持的配置。Gradle通过 resConfigresConfigs flavors 和 defaultConfig 选项把这些信息传递给构建系统。构建系统会阻止来自其它不受支持的资源出现在APK中,从而减少APK的大小。更多信息可以参考 Remove unused alternative resources

最小化使用Libraries中的资源

在开发App的时候,通常会使用外部libraries去提升app的可用性和功能扩展。比如,你可能会引用 Android Support Library 去提升老设备的用户体验。或者使用 Google Play Services 为app提供自动翻译。

如果一个library被设计用于桌面服务,那么就可能包含很多app不需要的对象和方法。为了只保留library中app需要的代码,如果license许可的话,你需要编辑library文件。你也可以使用一个移动端友好的替代库。

注意: ProGuard 可以清除一些从library中导入的不需要的代码。但是不会移除一个 library的内部依赖。

只支持特定的分辨率

Android支持非常大的设备集,包括各种屏幕密度。 在Android 4.4(API级别19)及更高版本中,框架支持各种分辨率:ldpi,mdpi,tvdpi,hdpi,xhdpi,xxhdpi和xxxhdpi。 虽然Android支持所有这些分辨率,但你不需要导出光栅化资源到每种分辨率。

如果你知道只有一小部分用户使用特定分辨率的设备,请考虑是否需要支持这些分辨率。 如果你不包括特定屏幕密度的资源,Android会自动缩放最初为其他屏幕密度设计的现有资源。

如果您的应用只需要缩放的图片,您可以通过在drawable-nodpi /中使用图片的单个版本来节省更多空间。 我们建议每个应用至少包含一个xxhdpi图片版本。

更多屏幕分辨率的信息,可以参考 Screen Sizes and Densities .

减少动画帧数

逐帧动画可能会大幅增加APK的大小。 图1中展示了一个帧动画被分成多个PNG文件的情况。 每个图像是动画中的一帧。

对于添加到动画中的每一帧,都会增加APK中存储的图片数量。 在图1中,图像在应用程序中以30 FPS动画。 如果图像仅以15FPS动画化,则动画将仅需要所需帧的数目的一半。

Android性能优化-减小APK大小

Use Drawable Objects

一些图像不需要静态图像资源; 框架可以在运行时动态地绘制图像。 相反,Drawable对象(XML中的)可能只会占用APK中的一小部分空间。 此外,XML形式的Drawable对象可以生成符合MaterialDesign指南的单色图像。

减少资源

你可能为同一种图像的不同形式都提供了独立的资源,例如同一图像的有色,阴影或旋转版本。 但是,我们建议你重复使用相同的资源,在运行时根据需要进行自定义。

Android提供了几个工具来更改资源的颜色,可以在Android 5.0(API级别21)以及更高版本上使用android:tint和tintMode属性。 对于较低版本的平台,请使用ColorFilter类。

您还可以节约那些只是某一种资源做了旋转的资源。 以下代码段提供了一个例子,通过简单地将原始图像旋转180度,将“展开”箭头转换为“折叠”箭头图标:

<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/ic_arrow_expand"
android:fromDegrees="180"
android:pivotX="50%"
android:pivotY="50%"
android:toDegrees="180" />

从代码中渲染

You can also reduce your APK size by procedurally rendering your images. Procedural rendering frees up space because you no longer store an image file in your APK.

你也可以通过程序对图像渲染来减少APK大小。 通过程序渲染可以节约空间是因为不需要在APK中存储图像文件。

压缩PNG文件

aapt工具可以在构建过程期间优化放置在res / drawable /中的图像资源,以及无损压缩。 例如,aapt工具可以将不需要多于256种颜色的真彩色PNG转换为具有调色板的8位PNG。 这样做会产生质量相同但占用内存较小的映像。

但请记得aapt有以下限制:

  • aapt工具不会收缩asset/文件夹中包含的PNG文件。
  • 图像文件需要使用256个或更少的颜色的aapt工具来优化它们。
  • aapt工具可能会填充已压缩的PNG文件。 为了防止这种情况,您可以在Gradle中使用cruncherEnabled标志为PNG文件禁用此过程:
aaptOptions {
cruncherEnabled = false
}

压缩PNG和JPG文件

你可以使用像 pngcrush , pngquant , 或 zopflipng 等工具来减少PNG文件大小,而不会损失图像质量。 所有这些工具都可以减少PNG文件大小,同时保持图像质量。

pngcrush工具特别有效:此工具在PNG过滤器和zlib(Deflate)参数上迭代,使用每个过滤器和参数的组合来压缩图像。 然后选择产生最小压缩输出的配置。

对于JPEG文件,您可以使用 packJPG 等工具将JPEG文件压缩为更紧凑的形式。

使用WebP 文件格式

除了使用PNG或JPEG文件,你还可以使用WebP的图像文件。 WebP格式提供有损压缩(如JPEG)和透明度(如PNG),但可以提供比JPEG或PNG更好的压缩。

但是,使用WebP文件格式有一些显着的缺点。 首先,在低于Android 3.2(API级别13)的平台版本中不支持WebP。 第二,系统解码WebP比PNG文件需要更长的时间。

注意:Google Play只接受使用PNG格式的图标。 如果你打算通过Google Play发布应用,图标就不能使用其他文件格式(如JPEG或WebP)。

使用矢量图形

你可以使用矢量图形创建分辨率独立的图标和其他可伸缩媒体。 使用这些图形可以大大减少APK体积。 矢量图像在Android中表示为VectorDrawable对象。 使用VectorDrawable对象,100字节的文件可以生成屏幕大小的清晰图像。

然而,系统渲染每个VectorDrawable对象需要大量的时间,较大的图像则需要更长的时间才能出现在屏幕上。 因此,只有在显示小图像时才考虑使用这些矢量图形。

有关使用VectorDrawable对象的更多信息,请参考 Working with Drawables .

三 减少Native和Java代码

删除不必要的生成代码

确保你能够理解那些任何自动生成的代码部分。 例如,许多协议缓冲工具生成过多的方法和类,可以使应用程序的大小增加一倍或两倍。

删除枚举

单个枚举可能为应用程序的classes.dex文件添加大小为1.0到1.4 KB的大小。 对于复杂的系统或者共享库,这种增加可能比较快迅速。 如果可能,请考虑使用@IntDef注解和 ProGuard 来除去枚举并将它们转换为整数。 这种类型转换保留了枚举的所有类型安全的好处。

减少本地二进制文件的大小

如果你的应用使用本地代码和Android NDK,你还可以通过优化这些代码来减小应用的大小。 两个有用的方式是删除debug标记,不提取本地库。

删除Debug符号

如果你的应用程序正在开发中并仍需要调试,那么使用debug标记很有意义。 使用Android NDK中提供的 arm-eabi-strip 工具从本地库中删除不必要的调试标记。 之后,再编译release版本。

避免提取本地库

将.so文件存储在APK中未压缩的文件中,并在应用清单的``元素中将android:extractNativeLibs标记设置为false。 这将防止PackageManager在安装过程中将.so文件从APK复制到文件系统,并且有一个额外的好处,会让app的差分更新变得更小。

四 维护多个精简版APK

你的APK可能包含用户下载但从不使用的内容,例如区域或语言信息。 为了让用户提供最小化的下载,你可以将应用细分为多个APK,并根据屏幕尺寸或GPU纹理支持等因素进行区分。

当用户下载您的应用时,其设备会根据设备的功能和设置接收正确的APK。 这样,设备不会接收设备没有的功能的资源。 例如,如果用户拥有的是hdpi设备,那么他们不需要你为更高分辨率设备提供的xxxhdpi资源。

更多信息请参考 Configure APK Splits and Maintaining Multiple APKs .

 
反对 0举报 0 评论 0
 

免责声明:本文仅代表作者个人观点,与乐学笔记(本网)无关。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
    本网站有部分内容均转载自其它媒体,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责,若因作品内容、知识产权、版权和其他问题,请及时提供相关证明等材料并与我们留言联系,本网站将在规定时间内给予删除等相关处理.

  • Android开发艺术探索学习笔记(三)—Android性能优化之Bitmap导致的内存溢出
    Android开发艺术探索学习笔记(三)—Android性能
    原本计划是按照章节顺序学习《Android开发艺术探索》这本书的,Android性能优化这部分也是本书的最后一章。但是周末的时候,友盟线下反馈的公司项目的一个错误让我不得不提前学习这一块的知识。先看看线下反馈的错误吧:java.lang.OutOfMemoryError:应用程序
  • Android 性能优化之内存泄漏分析工具 LeakCanary
    Android 性能优化之内存泄漏分析工具 LeakCanar
    前言Android内存泄漏的分析与解决是每个Android程序员进阶路上的必备技能。今天就和大家分享一下我的一点点学习心得。开始使用首先在module的build.gradle添加依赖,不同的版本需要添加不同的依赖dependencies {compile fileTree(dir: 'libs', include: ['*.j
  • 携程移动端 UI 界面性能优化实践
    携程移动端 UI 界面性能优化实践
    人类大脑与眼睛对一个画面的连贯性感知其实是有一个界限的,譬如我们看电影会觉得画面很自然连贯,其帧率通常为 24fps;那么,用手机当然也需要感知屏幕操作的连贯性(尤其是动画过渡),所以在手机领域 Android/iOS 索性就把达到这种流畅的帧率规定为 60fps。基
  • Android 性能优化:多线程系列开篇
    Android 性能优化:多线程系列开篇
    前言 Android Performance Patterns Season 5 主要介绍了 Android 多线程环境下的性能问题。通过介绍 Android 提供的多种多线程工具类 (AsyncTask, HandlerThread, IntentService, ThreadPool),让我们熟悉各个组件的适用场景,从而在特定场景下选择性能最好
  • Android性能优化-App后台优化
    原文链接Background Optimizations前言后台进程是内存和电池敏感的。一个隐式的broadcast可能会启动很多监听它的后台进程,即使这些进程可能做得工作不多。这可能丢设备性能和用户体验都有比较大的影响。为了缓解这种问题,7.0(API 24)做了以下限制:Target
  • Android应用性能优化系列视图篇——ListView自适应导致的严重性能问题
    Android应用性能优化系列视图篇——ListView自
    ListView是Android中最常用的视图之一,使用的频率仅仅次于三大基础布局,虽然由于使用性和扩展性等原因备受争议,且尽管后来出现了RecyclerView的替代方案,但是ListView仍然广泛地使用在我们的项目中。自从ListView出道至今,已经不知道衍生出了多少问题,
  • Android性能优化-内存优化
    前言在任何软件开发环境中,RAM都是比较珍贵的资源。在移动操作系统上更是这样,因为它们的物理内存通常受限。尽管在ART和Dalvik虚拟机都会进行垃圾回收的巡航,但这并不意味着你可以忽略何时,何地分配和释放内存。你应该避免内存泄露,通常此后又一些静态成
  • Android性能优化之UI渲染优化
    Android性能优化之UI渲染优化
    原文转自:http://www.cnblogs.com/yezhennan/p/5442031.htmlUI性能测试性能优化都需要有一个目标,UI的性能优化也是一样。你可能会觉得“我的app加载很快”很重要,但我们还需要了解终端用户的期望,是否可以去量化这些期望呢?我们可以从人机交互心理学的角
  • Google官方Android性能优化典范第1季
    Google官方Android性能优化典范第1季
    原文转自:http://www.cnblogs.com/yezhennan/p/5431738.html大多数用户感知到的卡顿等性能问题的最主要根源都是因为渲染性能。从设计师的角度,他们希望App能够有更多的动画,图片等时尚元素来实现流畅的用户体验。但是Android系统很有可能无法及时完成那些
  • Google官方Android性能优化典范第3季
    Google官方Android性能优化典范第3季
    原文转自:http://www.cnblogs.com/yezhennan/p/5443580.html (1)Fun with ArrayMaps 程序内存的管理是否合理高效对应用的性能有着很大的影响,有的时候对容器的使用不当也会导致内存管理效率低下。Android为移动操作系统特意编写了一些更加高效的容器,例如
点击排行