爲何APK要瘦身。APK越大,在下載安裝過程當中,他們耗費的流量會越多,安裝等待時間也會越長;對於產品自己,意味着下載轉化率會越低(由於競品中,用戶有更多機會選擇那個體驗最好,功能最多,性能最好,包最小的),因此apk的瘦身優化也很重要,本文將講述apk瘦身的相關內容。android
在Android Studio工具欄裏,打開build–>Analyze APK, 選擇要分析的APK包git
能夠看到佔用空間的主要是代碼、圖片、資源和lib和assert文件,主要方向精簡代碼、壓縮圖片、去除無用的庫、減小asserts裏面文件。github
對於絕大對數APP來講,只須要取一套設計圖就足夠了。鑑於如今分辨率的趨勢,建議取720p的資源,放到xhdpi目錄。 相對於多套資源,只使用720P的一套資源,在視覺上差異不大,不少大公司的產品也是如此,但卻能顯著的減小資源佔用大小,順便也能減輕設計師的出圖工做量了。 注意,這裏不是說把不是xhdpi的目錄都刪除,而是強調保留一套設計資源就夠了。web
在gradle使用minifyEnabled進行Proguard混淆的配置,可大大減少APP大小:bash
android {
buildTypes {
release {
minifyEnabled true
}
}
}
複製代碼
在proguard中,是否保留符號表對APP的大小是有顯著的影響的,可酌情不保留,可是建議儘可能保留用於調試。微信
參數:網絡
-include {filename} 從給定的文件中讀取配置參數
-basedirectory {directoryname} 指定基礎目錄爲之後相對的檔案名稱
-injars {class_path} 指定要處理的應用程序jar,war,ear和目錄
-outjars {class_path} 指定處理完後要輸出的jar,war,ear和目錄的名稱
-libraryjars {classpath} 指定要處理的應用程序jar,war,ear和目錄所須要的程序庫文件
-dontskipnonpubliclibraryclasses 指定不去忽略非公共的庫類。
-dontskipnonpubliclibraryclassmembers 指定不去忽略包可見的庫類的成員。
複製代碼
保留選項架構
-keep {Modifier} {class_specification} 保護指定的類文件和類的成員
-keepclassmembers {modifier} {class_specification} 保護指定類的成員,若是此類受到保護他們會保護的更好
-keepclasseswithmembers {class_specification} 保護指定的類和類的成員,但條件是全部指定的類和類成員是要存在。
-keepnames {class_specification} 保護指定的類和類的成員的名稱(若是他們不會壓縮步驟中刪除)
-keepclassmembernames {class_specification} 保護指定的類的成員的名稱(若是他們不會壓縮步驟中刪除)
-keepclasseswithmembernames {class_specification} 保護指定的類和類的成員的名稱,若是全部指定的類成員出席(在壓縮步驟以後)
-printseeds {filename} 列出類和類的成員-keep選項的清單,標準輸出到給定的文件
複製代碼
壓縮app
-dontshrink 不壓縮輸入的類文件
-printusage {filename}
-whyareyoukeeping {class_specification}
複製代碼
優化ide
-dontoptimize 不優化輸入的類文件
-assumenosideeffects {class_specification} 優化時假設指定的方法,沒有任何反作用
-allowaccessmodification 優化時容許訪問並修改有修飾符的類和類的成員
複製代碼
混淆
-dontobfuscate 不混淆輸入的類文件
-printmapping {filename}
-applymapping {filename} 重用映射增長混淆
-obfuscationdictionary {filename} 使用給定文件中的關鍵字做爲要混淆方法的名稱
-overloadaggressively 混淆時應用侵入式重載
-useuniqueclassmembernames 肯定統一的混淆類的成員名稱來增長混淆
-flattenpackagehierarchy {package_name} 從新包裝全部重命名的包並放在給定的單一包中
-repackageclass {package_name} 從新包裝全部重命名的類文件中放在給定的單一包中
-dontusemixedcaseclassnames 混淆時不會產生形形色色的類名
-keepattributes {attribute_name,...} 保護給定的可選屬性,例如LineNumberTable, LocalVariableTable, SourceFile, Deprecated, Synthetic, Signature, and InnerClasses.
-renamesourcefileattribute {string} 設置源文件中給定的字符串常量
複製代碼
在gradle使用shrinkResources去除無用資源,效果很是好。
android {
buildTypes {
release {
shrinkResources true
}
}
}
複製代碼
版本迭代過程當中,不但有廢棄代碼冗餘,確定會有無用的圖片存在。在build.gradle 裏面配置shrinkResources true,在打包的時候會自動清除掉無用的資源,但通過實驗發現打出的包並不會,而是會把部分無用資源用更小的東西代替掉。注意,這裏的「無用」是指調用圖片的全部父級函數最終是廢棄代碼,而shrinkResources true 只能去除沒有任何父函數調用的狀況,真正起效果只能經過Android Studio自帶的 「Remove Unused Resources」小插件來實現了,直接上圖。
更人性化是該查找結果能夠「一鍵刪除」。固然,可能圖片是通過反射或字符拼接等方式獲取,因此這個檢測列表也不是全對,刪除後很大機率編譯失敗或部分頁面掛死、無圖等問題,這個無解,工具還沒智能到這個地步,你只能一遍又一遍「編譯—解決部分問題—再編譯再」,別問我爲何知道。
大部分應用其實並不須要支持幾十種語言的國際化支持。還好強大的gradle支持語言的配置,好比國內應用只支持中文:
android {
defaultConfig {
resConfigs "zh"
}
}
複製代碼
TinyPNG工具只支持上傳PNG圖片到官網上壓縮,而後下載保存,在保持alpha通道的狀況下對PNG的壓縮能夠達到1/3以內,並且用肉眼基本上分辨不出壓縮的損失. Tinypng的官方網站:tinypng.com/
若是對於非透明的大圖,jpg將會比png的大小有顯著的優點,雖然不是絕對的,可是一般會減少到一半都不止。 在啓動頁,活動頁等之類的大圖展現區採用jpg將是很是明智的選擇。
webp支持透明度,壓縮比比jpg更高但顯示效果卻不輸於jpg,官方評測quality參數等於75均衡最佳。 相對於jpg、png,webp做爲一種新的圖片格式,限於android的支持狀況暫時還沒用在手機端普遍應用起來。從Android 4.0+開始原生支持,可是不支持包含透明度,直到Android 4.2.1+才支持顯示含透明度的webp,使用的時候要特別注意。 官方介紹:developers.google.com/speed/webp/…
若是通過上述步驟以後,你的工程裏面還有一些大圖,考慮是否有必要維持這樣的大尺寸,是否能適當的縮小。 事實上,因爲設計師出圖的緣由,咱們拿到的不少圖片徹底能夠適當的縮小而對視覺影響是極小的。
有些第三庫裏引用了一些大圖可是實際上並不會被咱們用到,就能夠考慮用1x1的透明圖片覆蓋。 你可能會有點不舒服,由於你的drawable下居然包含了一些莫名其妙的名稱的1x1圖片…
基本上armable的so也是兼容armable-v7的,armable-v7a的庫會對圖形渲染方面有很大的改進,若是沒有這方面的要求,能夠精簡。 這裏不排除有極少數設備會Crash,可能和不一樣的so有必定的關係,請你們務必測試周全後再發布。
與第十條不一樣的是,x86包下的so在x86型號的手機是須要的,若是產品沒用這方面的要求也能夠精簡。 建議實際工做的配置是隻保留armable、armable-x86下的so文件,算是一個折中的方案。
微信資源壓縮打包工具經過短資源名稱,採用7zip對APP進行極致壓縮實現減少APP的目標,效果很是的好,強烈推薦。
建議開啓7zip,注意白名單的配置,不然會致使有些資源找不到,官方已經發布AndResGuard到gradle中了,很是方便:
apply plugin: 'AndResGuard'
buildscript {
dependencies {
classpath 'com.tencent.mm:AndResGuard-gradle-plugin:1.1.7'
}
}
andResGuard {
mappingFile = null
use7zip = true
useSign = true
keepRoot = false
// add <your_application_id>.R.drawable.icon into whitelist.
// because the launcher will get thgge icon with his name
def packageName = <your_application_id>
whiteList = [
//for your icon
packageName + ".R.drawable.icon",
//for fabric
packageName + ".R.string.com.crashlytics.*",
//for umeng update
packageName + ".R.string.umeng*",
packageName + ".R.string.UM*",
packageName + ".R.string.tb_*",
packageName + ".R.layout.umeng*",
packageName + ".R.layout.tb_*",
packageName + ".R.drawable.umeng*",
packageName + ".R.drawable.tb_*",
packageName + ".R.anim.umeng*",
packageName + ".R.color.umeng*",
packageName + ".R.color.tb_*",
packageName + ".R.style.*UM*",
packageName + ".R.style.umeng*",
packageName + ".R.id.umeng*"
]
compressFilePattern = [
"*.png",
"*.jpg",
"*.jpeg",
"*.gif",
"resources.arsc"
]
sevenzip {
artifact = 'com.tencent.mm:SevenZip:1.1.7'
//path = "/usr/local/bin/7za"
}
}
複製代碼
會生成一個andresguard/resguard的Task,自動讀取release簽名進行從新混淆打包。
對於一些庫是按照須要動態的加載,可能在某些版本並不須要,可是代碼又不方便去除不然會編譯不過。 使用provided能夠保證代碼編譯經過,可是實際打包中並不引用此第三方庫,實現了控制APP大小的目標。 可是也同時就須要開發者本身判斷不引用這個第三方庫時就不要執行到相關的代碼,避免APP崩潰。
矢量圖是由點與線組成,和位圖不同,它再放大也能保持清晰度,並且使用矢量圖比位圖設計方案能節約30~40%的空間,如今谷歌一直在強調扁平化方式,矢量圖可很好的契合該設計理念。 —優點 1.佔用存儲空間小 2.無極拉伸不會出現鋸齒,能夠照顧不一樣尺寸的機型 3.Android Studio自帶不少資源,減少UI工做量 —劣勢 1.只支持5.0及以上系統 2.與位圖相比多了一層計算,需消耗更多性能 3.不支持.9圖 4.不適合表現真實照片和複雜圖形,通常使用在簡單的icon和動畫上
特別是在扁平化盛行的當下,不少純色的漸變的圓角的圖片均可以用shape實現,代碼靈活可控,省去了大量的背景圖片。
相信你的工程裏也有不少selector文件,也有不少類似的圖片只是顏色不一樣,經過着色方案咱們能大大減輕這樣的工做量,減小這樣的文件。 藉助於android support庫可實現一個全版本兼容的着色方案。
若是你的APP支持素材庫(好比聊天表情庫)的話,考慮在線加載模式,由於每每素材庫都有不小的體積。 這一步須要開發者實如今線加載,一方面增長代碼的複雜度,一方面提升了APP的流量消耗,建議酌情選擇。
避免重複庫看上去是理所固然的,可是祕密老是藏的很深,必定要小心你引用的第三方庫又引用了哪一個第三方庫,這就很容易出現功能重複的庫了,好比使用了兩個圖片加載庫:Glide和Picasso。 經過查看exploded-aar目錄和External Libraries或者反編譯生成的APK,儘可能避免重複庫的大小,減少APP大小。
版本迭代過程當中,由於刪減功能常常有冗餘代碼和第三方庫留下,這或多或少都會增長包體,這種狀況沒有捷徑,只能每一個文件查找,這是苦力活。還有要查看第三方庫有沒可能精簡,好比谷歌分基礎、廣告和分析包,網絡庫、supportv4等,這個就具體狀況具體分析,很少闡述。
插件化技術支持動態的加載代碼和動態的加載資源,把APP的一部分分離出來了,對於業務龐大的項目來講很是有用,極大的分解了APP大小。 由於插件化技術須要必定的技術保障和服務端系統支持,有必定的風險,如無必要(好比一些小型項目,也沒什麼擴展業務)就不須要了,建議酌情選擇。
redex是facebook發佈的一款android字節碼的優化工具,須要按照說明文檔自行配置一下。 ··· redex input.apk -o output.apk --sign -s -a -p ··· 下面咱們來看看它的效果,僅redex的話,減少了157k:
若是先進行微信混淆,再redex,減少了565k,redex只貢獻了10k:
若是先進行redex,在進行微信混淆,減少了711k,redex貢獻了157k:
最後一種的效果是最好的,這是很容易解釋的,若是最後是redex的從新打包則浪費了前面的7zip壓縮,因此爲了最優效果要注意順序。 另外,據反應redex後會有崩潰的現象,這個要留意一下,我這裏壓縮以後都是能夠正常運行的。 詳情參考:ReDex
若是你看到了這裏,以爲文章寫得不錯就給個贊唄?若是你以爲那裏值得改進的,請給我留言。必定會認真查詢,修正不足。謝謝。
但願讀到這的您能轉發分享和關注一下我,之後還會更新技術乾貨,謝謝您的支持!
轉發+點贊+關注,第一時間獲取最新知識點
Android架構師之路很漫長,一塊兒共勉吧!