初めに書かれました。
ビジネス、コードの複雑化によって、リソースは常に、あなたはまた、APPのサイズを大きくしている、増加しています。ユーザーの観点からは、APPのメガバイトのすべてのターン数十の顔が非WIFIの例では、ダウンロードにはまだ躊躇している、何のダウンロードは、あなたは、ユーザーを失うことがあります。企業レベルが関係しているから、トラフィックはお金である、APPのサイズを小さく、特に重要です。開発者の観点からは、このクラフトは若干グリッド完全な力となりますマスターしています。
ADOは、トピックを起動します。
それらのもの1.APK構造
自分自身を知っている、唯一の自分を知ることができます。私たちのために役立つアプリケーションのAPKの構造を理解します。APKファイルには、アプリケーションを構成するすべてのファイルを含むZIPアーカイブの組成、構成されています。これらのファイルは、Javaクラスファイル、リソースファイルとコンパイル済みのリソースを含むファイルが含まれます。
APKは、次のディレクトリが含まれています。
- META-INFは、/:CERT.SFとCERT.RSA署名ファイルとMANIFEST.MFマニフェストファイルが含まれています。
- 資産/:アプリケーション・リソースAssetManager検索対象を使用することができるアプリケーションが含まれています。
- RES /:リソースresources.arscにコンパイルされません含まれています。
- LIB /:コンパイルされたコードを含むプロセッサ固有のソフトウェア層。このディレクトリはarmeabi、armeabi-v7a、arm64-v8a、x86の、x86_64版、およびMIPSのように、各プラットフォーム用のサブディレクトリが含まれています。
- resources.arsc:コンパイルされたリソースを含みます。このファイルには、すべてのXML構成のRES /値/フォルダの内容が含まれています。XMLコンテンツを抽出するパッケージングツールは、バイナリフォーマットとコンテンツアーカイブにコンパイルされます。これは、言語文字列とスタイル、およびダイレクト・パス・resources.arscファイルに含まれるコンテンツ、例えば、画像のレイアウトファイルが含まれています。
- classes.dex:のDalvik / ART仮想マシンのファイル形式に理解DEXコンパイルされたクラスが含まれています。
- AndroidManifest.xml:Androidのマニフェストファイルには、コアが含まれています。文書には、アプリケーション名、バージョン、およびリファレンスライブラリへのアクセスを示しています。AndroidのXMLフォーマットを使用してバイナリファイル。
- 淘宝網の解凍後のAPPのファイルディレクトリを見てみましょう
一般的には、APK構造は、一般的なclasses.dex、LIB、解像度、資産そのようなファイルやディレクトリの比較的大きな部分です。だから、次は、これらの4つのケースについて説明します。
また、当社は、APK APKアナライザで分析することができます
classes.dexを削減2.
classes.dexは、すべてのJavaコードが含まれています。アプリケーションをコンパイルすると、Gradleのは、一つのファイルclasses.dexに.dexファイルとそれらのファイルへの.classファイルにあなたのすべてのモジュールを変換します。
Classes.dex単一のファイルには、64Kの方法について、保持することができます。あなたはこの制限に達した場合、あなたのプロジェクトにmultidexing有効にする必要があります。これは、メソッドの残りの部分を格納するための別のclasses1.dexファイルが作成されます。classes.dexは、ファイルの数によって決まりますので、メソッドを数えます。
第三のライブラリの使用を削減
頻繁な変更や事業の複雑化により、我々は時々我々は唯一の機能のごく一部を使用することができ、サードパーティLibarayを使用する傾向があり、この時の必要性を慎重に完全なリファレンスと見なされます。開発の面で私の経験から、達成するために自分自身を参照することを好むが、また、我々は、サードパーティのライブラリを導入する必要はありません。
Enumerationを避けます
列挙は、アプリケーションを提出classes.dexサイズは1.4キロバイトに1.0程度追加することができます。これらの追加はすぐに複雑なシステムまたは共有ライブラリに蓄積することができます。可能であれば、@IntDefノートの使用を検討して、変換のこのタイプは、タイプセーフな列挙のすべての利点を保持します。
使用ProGuardの
コード圧縮のためのbuild.gradleファイルから次のコードは、リリースビルドのために有効になります。
android {
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'),
'proguard-rules.pro'
}
}
...
}
またminifyEnabled特性、ならびにProGuardのproguardFilesプロパティを定義するための規則で:
getDefaultProguardFile( 'ProGuardの-android.txt')メソッドは、ProGuardのAndroidのSDKツール/ ProGuardの/フォルダをデフォルト設定から取得することができます。
提示:要想做进一步的代码压缩,请尝试使用位于同一位置的 proguard-android-optimize.txt 文件。它包括相同的 ProGuard 规则,但还包括其他在字节码一级(方法内和方法间)执行分析的优化,以进一步减小 APK 大小和帮助提高其运行速度。
proguard-rules.pro 文件用于添加自定义 ProGuard 规则。默认情况下,该文件位于模块根目录(build.gradle 文件旁)。
3.优化assets和res中的资源文件
题外话
res/raw和assets的相同点:
两者目录下的文件在打包后会原封不动的保存在apk包中,不会被编译成二进制。
res/raw和assets的不同点:
- res/raw中的文件会被映射到R.java文件中,访问的时候直接使用资源ID即R.id.filename;assets文件夹下的文件不会被映射到R.java中,访问的时候需要AssetManager类。
- res/raw不可以有目录结构,而assets则可以有目录结构,也就是assets目录下可以再建立文件夹。
- 针对不同的情况,对于资源文件有不同的优化策略。一般来讲,对于res/drawable-**ddpi中的png资源可以进行压缩。
3.1 图片资源优化策略
格式压缩
使用TinyPng或者Guetzli进行压缩。
使用WebP文件格式
定位Android 3.2(API级别13)或更高级别时 ,您也可以使用WebP文件格式来制作图像,而不是使用PNG或JPEG文件。WebP格式提供有损压缩(如JPEG)以及透明度(如PNG),但可以提供比JPEG或PNG更好的压缩。
Android 4.0 (API level 14) 支持有损压缩的WebP格式,Android 4.3 (API level 18) 开始支持无损透明WebP图像。
看下图:
压缩效率极高,仅为PNG格式的12%。惊喜不惊喜。。。
使用矢量图形
您可以使用矢量图形来创建与分辨率无关的图标和其他可伸缩媒体。使用这些图形可以大大减少您的APK足迹。矢量图像在Android中表示为VectorDrawable对象。通过一个VectorDrawable对象,一个100字节的文件可以生成一个与屏幕尺寸一致的清晰图像。
但是,系统渲染每个 VectorDrawable对象需要很长时间,而较大的图像需要更长的时间才能显示在屏幕上。因此,只有在显示小图像时才考虑使用这些矢量图形。
其它策略
有时候我们可能对一张图片进行重复利用,比如一张图片仅仅是整体颜色的变换可以使用setColorFilter或者tint。尽量减少使用帧动画,那可是一堆图片呀。
3.2 压缩资源
要启用资源压缩,请在 build.gradle 文件中将 shrinkResources 属性设置为 true。
android {
...
buildTypes {
release {
shrinkResources true
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'),
'proguard-rules.pro'
}
}
}
资源压缩器目前不会移除 values/ 文件夹中定义的资源(例如字符串、尺寸、样式和颜色)。这是因为 Android 资源打包工具 (AAPT) 不允许 Gradle 插件为资源指定预定义版本。
同时,我们也可以指定哪些资源可以保留下来。
例如,将下边的代码保存在 res/raw/keep.xml。构建不会将该文件打包到 APK 之中。
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools"
tools:keep="@layout/l_used*_c,@layout/l_used_a,@layout/l_used_b*"
tools:discard="@layout/unused2" />
resources有以下属性:
- tools:keep 指出哪些资源会保留
- tools:discard 指定哪些资源需要剔除
- tools:shrinkMode 资源压缩模式,有两种取值strict和safe,默认为safe
safe和strict的优化策略:
safe可以简单理解为安全模式,它会尽最大努力检查代码中可能会使用到的资源进行保留,避免运行时错误。
如果你的代码调用 Resources.getIdentifier(),这就表示你的代码将根据动态生成的字符串查询资源名称。当你执行这一调用时,默认情况下资源压缩器会采取防御性行为,将所有具有匹配名称格式的资源标记为可能已使用,无法移除。
String name = String.format("img_%1d", angle + 1);
res = getResources().getIdentifier(name, "drawable", getPackageName());
img_ 前缀的资源标记为已使用。
在strict模式下,img_前缀的资源会做未使用的处理,因此你需要使用tools:keep手动进行已使用标识。
移除未使用的备用资源
我们知道google给我们的apk提供了国际化支持,如适应不同的屏幕分辨率的drawable资源,还有适应不同语言的字符串资源等等,但是在很多情况下我们只需要一些指定分辨率和语言的资源就可以了,这个时候我们可以使用resConfigs方法来配置。
defaultConfig {
// 对于国际化支持只打包中文资源,
resConfigs "zh-rCN"
}
4.lib中资源优化
这里我们主要讲一下lib中动态链接库的优化策略,也就是SO文件。如果你有NDK的开发经验可能会更容易理解一些。
为了支持不同指令集的情况,应用可能会包含armeabi、armeabi-v7a、x86的SO文件等。
目前主流的机型都是支持armeabi-v7a的,并且armeabi-v7a兼容armeabi。所以在一般的开发中我们只需要使用armeabi-v7a 进行ABI支持。
有些SO库可以采用网络下载,把负担放到用户安装完应用之后。对于哪些SO文件可以放到网络中加载,还需要看具体业务情况。
题外话,如果运行时找不到SO的话,会导致应用崩溃。
java.lang.UnsatisfiedLinkError: Couldn't load stlport_shared
from loader dalvik.system.PathClassLoader: findLibrary returned null
at java.lang.Runtime.loadLibrary(Runtime.java:365)
at java.lang.System.loadLibrary(System.java:535)
at com.your.app.NativeClass.<clinit>(Native.java:16)
... 63 more
Caused by: java.lang.UnsatisfiedLinkError: Library stlport_shared not found
at java.lang.Runtime.loadLibrary(Runtime.java:461)
at java.lang.System.loadLibrary(System.java:557)
at com.your.app.NativeClass.<clinit>(Native.java:16)
... 5 more
我们也是有办法应对的,可以参见这个开源项目ReLinker
本文的Android安装包大小优化知识到此结束
写在最后;
作者目前在深圳,13年java转Android开发,在小厂待过,也去过华为,OPPO等,去年四月份进了阿里一直到现在。后面转管理后也面试过很多人。深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,不成体系的学习效果低效,原理源码确实容易头疼,造成很多开发者工作几年后就陷入瓶颈难以往上突破。
我去年开始,整理了一份阿里P7级别的Android架构师全套学习资料,特别适合有3-5年以上经验的小伙伴深入学习提升。
主要包括腾讯,以及字节跳动,华为,小米,等一线互联网公司主流架构技术。
【阿里P7级】Android高级进阶技术脑图
(大家如果有想往上提升技术,建议先搭建一个全面的技术框架,然后再深挖)
也可以关注我的;Android高级进阶专栏。里面有很多在BAT等一线大厂待过,或者在职的技术大佬。哪怕只关注看看不学,也能一定程度上提升思维和格局。
欢迎关注和学习交流~