標籤:線上 .9圖 specific .com hierarchy 一半 csdn member 下載安裝
Android效能最佳化系列之布局最佳化
Android效能最佳化系列之記憶體最佳化
為什麼APK要瘦身。APK越大,在下載安裝過程中,他們耗費的流量會越多,安裝等待時間也會越長;對於產品本身,意味著下載轉化率會越低(因為競品中,使用者有更多機會選擇那個體驗最好,功能最多,效能最好,包最小的),所以apk的瘦身最佳化也很重要,本篇部落格將講述apk瘦身的相關內容。
包體分析
在Android Studio工具列裡,開啟build–>Analyze APK, 選擇要分析的APK包
可以看到佔用空間的主要是代碼、圖片、資源和lib和assert檔案,主要方向精簡代碼、壓縮圖片、去除無用的庫、減少asserts裡面檔案。
使用一套資源
對於絕大對數APP來說,只需要取一套設計圖就足夠了。鑒於現在解析度的趨勢,建議取720p的資源,放到xhdpi目錄。
相對於多套資源,只使用720P的一套資源,在視覺上差別不大,很多大公司的產品也是如此,但卻能顯著的減少資源佔用大小,順便也能減輕設計師的出圖工作量了。
注意,這裡不是說把不是xhdpi的目錄都刪除,而是強調保留一套設計資源就夠了。
開啟minifyEnabled混淆代碼
在gradle使用minifyEnabled進行Proguard混淆的配置,可大大減小APP大小:
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選項的清單,標準輸出到給定的檔案
壓縮
-dontshrink 不壓縮輸入的類檔案 -printusage {filename} -whyareyoukeeping {class_specification}
最佳化
-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} 設定源檔案中給定的字串常量
開啟shrinkResources去除無用資源
在gradle使用shrinkResources去除無用資源,效果非常好。
android { buildTypes { release { shrinkResources true } }}
清理無用資源
版本迭代過程中,不但有廢棄代碼冗餘,肯定會有無用的圖片存在。在build.gradle 裡面配置shrinkResources true,在打包的時候會自動清除掉無用的資源,但經過實驗發現打出的包並不會,而是會把部分無用資源用更小的東西代替掉。注意,這裡的“無用”是指調用圖片的所有父級函數最終是廢棄代碼,而shrinkResources true 只能去除沒有任何父函數調用的情況,真正起效果只能通過Android Studio內建的 “Remove Unused Resources”小外掛程式來實現了,直接。
更人性化是該尋找結果可以“一鍵刪除”。當然,可能圖片是經過反射或字元拼接等方式擷取,所以這個檢測列表也不是全對,刪除後很大機率編譯失敗或部分頁面掛死、無圖等問題,這個無解,工具還沒智能到這個地步,你只能一遍又一遍“編譯—解決部分問題—再編譯再”,別問我為什麼知道。
刪除無用的語言資源
大部分應用其實並不需要支援幾十種語言的國際化支援。還好強大的gradle支援語言的配置,比如國內應用只支援中文:
android { defaultConfig { resConfigs "zh" }}
使用tinypng有損壓縮
TinyPNG工具只支援上傳PNG圖片到官網上壓縮,然後下載儲存,在保持alpha通道的情況下對PNG的壓縮可以達到1/3之內,而且用肉眼基本上分辨不出壓縮的損失.
Tinypng的官方網站:http://tinypng.com/
使用jpg格式
如果對於非透明的大圖,jpg將會比png的大小有顯著的優勢,雖然不是絕對的,但是通常會減小到一半都不止。
在啟動頁,活動頁等之類的大圖展示區採用jpg將是非常明智的選擇。
使用webp格式
webp支援透明度,壓縮比比jpg更高但顯示效果卻不輸於jpg,官方評測quality參數等於75均衡最佳。
相對於jpg、png,webp作為一種新的圖片格式,限於android的支援情況暫時還沒用在手機端廣泛應用起來。從Android 4.0+開始原生支援,但是不支援包含透明度,直到Android 4.2.1+才支援顯示含透明度的webp,使用的時候要特別注意。
官方介紹:https://developers.google.com/speed/webp/docs/precompiled
縮小大圖
如果經過上述步驟之後,你的工程裡面還有一些大圖,考慮是否有必要維持這樣的大尺寸,是否能適當的縮小。
事實上,由於設計師出圖的原因,我們拿到的很多圖片完全可以適當的縮小而對視覺影響是極小的。
覆蓋第三庫裡的大圖
有些第三庫裡引用了一些大圖但是實際上並不會被我們用到,就可以考慮用1x1的透明圖片覆蓋。
你可能會有點不舒服,因為你的drawable下竟然包含了一些莫名其妙的名稱的1x1圖片…
刪除armable-v7包下的so
基本上armable的so也是相容armable-v7的,armable-v7a的庫會對圖形渲染方面有很大的改進,如果沒有這方面的要求,可以精簡。
這裡不排除有極少數裝置會Crash,可能和不同的so有一定的關係,請大家務必測試周全後再發布。
刪除x86包下的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編譯
對於一些庫是按照需要動態載入,可能在某些版本並不需要,但是代碼又不方便去除否則會編譯不過。
使用provided可以保證代碼編譯通過,但是實際打包中並不引用此第三方庫,實現了控制APP大小的目標。
但是也同時就需要開發人員自己判斷不引用這個第三方庫時就不要執行到相關的代碼,避免APP崩潰。
向量圖
向量圖是由點與線組成,和位元影像不一樣,它再放大也能保持清晰度,而且使用向量圖比位元影像設計方案能節約30~40%的空間,現在Google一直在強調扁平化方式,向量圖可很好的契合該設計理念。
—優勢
(1)佔用儲存空間小
(2) 無極展開不會出現鋸齒,可以照顧不同尺寸的機型
(3)Android Studio內建很多資源,減小UI工作量
—劣勢
(1) 只支援5.0及以上系統
(2) 與位元影像相比多了一層計算,需消耗更多效能
(3) 不支援.9圖
(4)不適合表現真實照片和複雜圖形,一般使用在簡單的icon和動畫上
使用shape背景
特別是在扁平化盛行的當下,很多純色的漸層的圓角的圖片都可以用shape實現,代碼靈活可控,省去了大量的背景圖片。
使用著色方案
相信你的工程裡也有很多selector檔案,也有很多相似的圖片只是顏色不同,通過著色方案我們能大大減輕這樣的工作量,減少這樣的檔案。
藉助於android support庫可實現一個全版本相容的著色方案,參考代碼:DrawableLess.java
線上化素材庫
如果你的APP支援素材庫(比如聊天表情庫)的話,考慮線上載入模式,因為往往素材庫都有不小的體積。
這一步需要開發人員實現線上載入,一方面增加代碼的複雜度,一方面提高了APP的流量消耗,建議酌情選擇。
避免重複庫
避免重複庫看上去是理所當然的,但是秘密總是藏的很深,一定要當心你引用的第三方庫又引用了哪個第三方庫,這就很容易出現功能重複的庫了,比如使用了兩個圖片載入庫:Glide和Picasso。
通過查看exploded-aar目錄和External Libraries或者反編譯產生的APK,盡量避免重複庫的大小,減小APP大小。
清理第三方庫和冗餘代碼
版本迭代過程中,因為刪減功能經常有冗餘代碼和第三方庫留下,這或多或少都會增加包體,這種情況沒有捷徑,只能每個檔案尋找,這是苦力活。還有要查看第三方庫有沒可能精簡,比如Google分基礎、廣告和分析包,網路程式庫、supportv4等,這個就具體情況具體分析,不多闡述。
支援外掛程式化
外掛程式化支援人員動態載入代碼和動態載入資源,把APP的一部分分離出來了,對於業務龐大的項目來說非常有用,極大的分解了APP大小。
因為外掛程式化技術需要一定的技術保證和服務端系統支援,有一定的風險,如無必要(比如一些小型項目,也沒什麼擴充業務)就不需要了,建議酌情選擇。
Facebook的redex最佳化位元組碼
redex是facebook發布的一款android位元組碼的最佳化工具,需要按照說明文檔自行配置一下。
redex input.apk -o output.apk --sign -s <KEYSTORE> -a <KEYALIAS> -p <KEYPASS>
下面我們來看看它的效果,僅redex的話,減小了157k:
下面我們來看看它的效果,僅redex的話,減小了157k:
如果先進行混淆,再redex,減小了565k,redex只貢獻了10k:
如果先進行redex,在進行混淆,減小了711k,redex貢獻了157k:
最後一種的效果是最好的,這是很容易解釋的,如果最後是redex的重新打包則浪費了前面的7zip壓縮,所以為了最優效果要注意順序。
另外,據反應redex後會有崩潰的現象,這個要留意一下,我這裡壓縮之後都是可以正常啟動並執行。
詳情參考:ReDex
Android效能最佳化系列之apk瘦身