本文翻譯于 google developer 官方教程
build.gradleandroid { ... buildTypes { release { minifyEnabled true PRoguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } }}首先應(yīng)該打開 (minifier)壓縮開關(guān),例如:minifyEnabled true ,這個開關(guān)會清除不使用的類以及類成員,同時會是用短名稱重命名類以及類成員,這都會是apk體積減小,但是重命名會是調(diào)試變得非常困難,所以建議只是用 下面的混淆配置(如果出現(xiàn)ClassNotFoundException 需要在混淆配置里加混淆保護)
shrinkResources true 會清除掉代碼不使用的資源引用
特別像這種字符串引用,也要加混淆保護:
<android.support.v7.widget.RecyclerView app:layoutManager=”android.support.v7.widget.GridLayoutManager” .../>如果你創(chuàng)建的aar庫需要使用在第三方項目里面,為了使用Proguard規(guī)則對AAR生效,你需要使用 comsumerProguardFiles 屬性,這樣,人和人使用你的AAR時,就不用擔(dān)心需要手動添加規(guī)則了
android { ... defaultConfig { consumerProguardFiles “proguard-rules.txt” }}step two:Tracking down dependencies
step three:removing unused resources:
android { ... buildTypes { release { '''shrinkResources true''' proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } }}它能分析所有已經(jīng)被引用的資源并清除那些沒有被Layout, Drawable , code 所使用的資源 it can also analyze which resources are actually being used and strip those that are never included in your layouts, drawables, code, etc.
就像刪除代碼一樣,有時候工具出現(xiàn)不知道使用哪個資源錯誤,有可能錯誤的刪掉資源,所以,你可以告訴系統(tǒng)一想要保留的資源,只需要使用 tools:keep 這樣的類似ProGuard keep的配置就可以做到,你可以在任何具有 resource 節(jié)點的文件或者新建一個帶resource節(jié)點的xml:
res/raw/keep.xml
<?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*"/>你也可以指定要刪除的資源:
<?xml version="1.0" encoding="utf-8"?><resources xmlns:tools="http://schemas.android.com/tools" tools:shrinkMode="safe" tools:discard="@layout/unused2"/>Removing unused configurations with ResConfigs:
android { defaultConfig { ... resConfigs "en", "fr" }}很多庫都會被翻譯成多種語言,如果你只想在特定的語言時長發(fā)布,則如上配置,系統(tǒng)會去掉所有不在配置列表里的其他語言資源
Sparse configurations in resources.arsc
這個問題通常只會發(fā)生在體積很大的App上,成百上千的字符資源,樣式,以及Id都會進入resources.arsc文件,如果你突然發(fā)現(xiàn)Apk占用的體積增大,可能表明,你有很多分散的配置,比如,你有五個字符串定義在默認的配置中(vlaues/string.xml),這些字符資源會被系統(tǒng)定義到字符資源池中,并且有另外配置文件會生成指向這些字符資源的地址(你可以認為是引用),像下面這樣:
String pool: "My App", "Hello", "Exit", "Settings", "Feature" Default config: string/myapp 0x00000001string/hello 0x00000002string/exit 0x00000003string/settings 0x00000004string/feature 0x00000005現(xiàn)在想象一下,你只需要在API21+上新增一個功能,這個功能需要顯示 feature 為不同的消息,所以你就在values-v21/strings.xml 上覆蓋這個字符串,并重新編譯,你可能會認為,只是在字符池中新增了一個字符串,并且只生成了一個指向地址(你可以認為是引用),但是很遺憾,這不是resources.arsc文件格式的工作原理,你可能會看到這樣的結(jié)果:
String pool: "My App", "Hello", "Exit", "Settings", "Feature", "New feature" Default config: -v21 config:string/myapp 0x00000001 NO_ENTRYstring/hello 0x00000002 NO_ENTRYstring/exit 0x00000003 NO_ENTRYstring/settings 0x00000004 NO_ENTRYstring/feature 0x00000005 0x00000006 ========== ==========Config size: 20 bytes 20 bytes!就像上面這樣,每個配置(-v21, -land, -en-land-v21)都額外保存了每一個資源的引用,實際上這些引用是空的(無效的),一個空的占用4bytes,就如我一開始說的,占用多大的控件,取決于你在app里定義了多少資源,例如上面在 -v21配置中有4*4byte,也就是16bytes浪費在空的引用上。 然而真實的場景是如果一個app定義了3500 個strings,并且有一個單獨的landscape配置并且只有一個字符資源被翻譯成50種語言(例如: values-en-land, -pl-land, -de-land, -fr-land…)將會失去: 4bytes*3500 null entryes*50 languages = 700 kilobytes 只需要刪除一個字符資源,就可以節(jié)約700kilobytes,刪除3個,就可以節(jié)約2.5M 話說回來,如果你把一個資源放在一個單獨的配置里,意味著你確實需要它并且它確實是合適的處理方式,但是如果能判斷這些資源能減少大量的體積,你可能會考慮把他們?nèi)サ粢怨?jié)約體積。 有一種在代碼中根據(jù)不同版本來使用不同字符資源的不太優(yōu)雅的方法,只針對特別的場景。例如,在你的values/strings.xml你可能由兩個字符串:string/my_feature and string/my_feature_land, 然后根據(jù)運行時當(dāng)前屏幕方向來動態(tài)選擇字符資源。 已經(jīng)有工具能幫你找到分散的資源配置并找到哪些資源導(dǎo)致resources.arsc增大: https://github.com/google/android-arscblamer
你需要 安裝Bazel來編譯ArscBlamer,你可以編譯可運行這個命令:
$ bazel run //java/com/google/devrel/gmscore/tools/apk/arsc:ArscDumper --apk=/FULL_PATH_TO_APK/bar.apk - keys > output.csv 可以看到所有的Null Entries,去掉是很可觀的
 可以看到所有的Null Entries,去掉是很可觀的
Multi-APK through ABI and density splits: Android 生態(tài)系統(tǒng)豐富多樣,手機到平板,再到電視,每種設(shè)備都有自己的硬件特性,比如屏幕尺寸,屏幕密度,以及cpu架構(gòu),盡管在規(guī)范文檔中,我們鼓勵大家去創(chuàng)建支持所有設(shè)備的app,但是有時候把apk“分割”開,卻能最大限度的節(jié)省空間。比如,如果用戶的手機是ARM架構(gòu)的處理器,則我們就可以不必為用戶提供X86架構(gòu)的本地代碼庫,或者如果用戶的手機的分辨率為mdpi的,則我們不必為用戶提供xxhdpi密度的資源也為用戶節(jié)約了帶寬。
你可以找到詳細的資料,關(guān)于Multi_APK是怎樣工作的,以及Play Store支持什么樣的過濾條件以及一些版本號管理的重要規(guī)則,理解Multi-APK 的工作原理至關(guān)重要(http://developer.android.com/google/play/publishing/multiple-apks.html#HowItWorks),作為開發(fā)者你應(yīng)該要判斷使用如此法則的版本管理和處理流程會給用戶帶來怎樣的好處。最簡單的Multi-APK方式是通過Android Studio配置選項來分割,splits 就是你在build.gradle添加的能為不同密度或者不同ABIS(CPU 架構(gòu))創(chuàng)建單獨的APK的一段配置區(qū)域。
在你開始準(zhǔn)備分割你的apk之前,如果你需要一個樣例來驗證分割的效果,我建議你看看Topeka on Github,這個樣例已經(jīng)對包括圖片在內(nèi)的資源針對不同密度的設(shè)備做了處理,是splits的完美例證。 打開 app/build.gradle文件,并添在build.gradle中添加如下代碼:
android { ... splits { density { enable true exclude 'ldpi', 'tvdpi', 'xxxhdpi'//alternatively use the following two lines to only include:// reset()// include 'mdpi', 'hdpi', 'xhdpi', 'xxhdpi' compatibleScreens 'small', 'normal', 'large', 'xlarge' } }}配置非常簡單: 1. 打開密度分割的開關(guān) 2. 然后包括或者去除特定密度配置 3. 最后指定屏幕兼容性,必須從小到達(small,normal, large, xlarge)
……待完成
待完成
新聞熱點
疑難解答