你必須要懂的APK瘦身知識

隨著業務復雜度的逐漸增加,代碼、資源也在不斷的增加,此時你的APP大小也在增加。從用戶層面來說,面對動輒幾十兆的APP來說在非WIFI情況下還是會猶豫要不要下載,不下載你就可能因此失去了一個用戶。從公司層面來講,流量就是錢,減少APP的大小就顯得尤為重要。從開發者層面上來講,你掌握了這個手藝也會略顯逼格滿滿。

廢話不多說了,開始正題。

01 APK結構的那些事

知己知彼,方能百戰不殆。了解應用程序APK的結構對于我們來說很有幫助。APK文件由一個ZIP存檔組成,其中包含組成應用程序的所有文件。這些文件包括Java類文件,資源文件和包含編譯資源的文件。

APK包含以下目錄:

  • META-INF/:包含CERT.SFCERT.RSA簽名文件以及MANIFEST.MF 清單文件。
  • assets/:包含應用可以使用AssetManager對象檢索的應用資源。
  • res/:包含未編譯到的資源 resources.arsc
  • lib/:包含特定于處理器軟件層的編譯代碼。該目錄包含了每種平臺的子目錄,像armeabiarmeabi-v7aarm64-v8ax86x86_64,和mips
  • resources.arsc:包含已編譯的資源。該文件包含res/values/ 文件夾所有配置中的XML內容。打包工具提取此XML內容,將其編譯為二進制格式,并將內容歸檔。此內容包括語言字符串和樣式,以及直接包含在resources.arsc文件中的內容路徑 ,例如布局文件和圖像。
  • classes.dex:包含以Dalvik / ART虛擬機可理解的DEX文件格式編譯的類。
  • AndroidManifest.xml:包含核心Android清單文件。該文件列出應用程序的名稱,版本,訪問權限和引用的庫文件。該文件使用Android的二進制XML格式。

來看看淘寶APP的unzip之后的文件目錄

taobao_app.png

一般來講APK結構中比較大的部分一般是classes.dex、lib、res、assets這些文件或者目錄。所以接下來將會針對這四種情況進行講解。

?

另外,我們通過APK Analyser 可以分析 APK


APK Analyser.png

02 減小 classes.dex

classes.dex 包含了所有 Java 代碼。當你編譯你的應用時,gradle 會將你的所有模塊里的 .class 文件轉換成 .dex 文件并將這些文件合成一個 classes.dex 文件。

單個的 classes.dex 文件可以容納大約 64K 方法。如果你達到了這個限制,你必須要在你的工程中啟用 multidexing。這將會創建另一個 classes1.dex 文件去存儲剩下的方法。所以 classes.dex 文件數目由你的方法數而定。

減少第三庫的使用

隨著業務的頻繁變更以及復雜度的增加,我們往往會使用第三方Libaray,有時候我們可能僅僅用到了很少一部分的功能,這個時候就需要慎重考慮完全引用。從我的開發經驗上來講,寧愿參照自己去實現,也不愿意多引入一個第三方庫。

避免枚舉

一個枚舉可以為您的應用程序的classes.dex文件添加大約1.0到1.4 KB的大小 。這些添加可以快速累積到復雜系統或共享庫。如果可能,請考慮使用@IntDef注釋,這種類型轉換保留了枚舉的所有類型安全優勢。

使用ProGuard

下面這段來自 build.gradle 文件的代碼用于為發布構建啟用代碼壓縮:

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

?

除了 minifyEnabled 屬性外,還有用于定義 ProGuard 規則的 proguardFiles 屬性:

getDefaultProguardFile('proguard-android.txt') 方法可從 Android SDK tools/proguard/ 文件夾獲取默認的 ProGuard 設置。
提示:要想做進一步的代碼壓縮,請嘗試使用位于同一位置的 proguard-android-optimize.txt 文件。它包括相同的 ProGuard 規則,但還包括其他在字節碼一級(方法內和方法間)執行分析的優化,以進一步減小 APK 大小和幫助提高其運行速度。

proguard-rules.pro 文件用于添加自定義 ProGuard 規則。默認情況下,該文件位于模塊根目錄(build.gradle 文件旁)。

03 優化assets和res中的資源文件

題外話

res/raw和assets的相同點:

  1. 兩者目錄下的文件在打包后會原封不動的保存在apk包中,不會被編譯成二進制。

res/raw和assets的不同點:

  1. res/raw中的文件會被映射到R.java文件中,訪問的時候直接使用資源ID即R.id.filename;assets文件夾下的文件不會被映射到R.java中,訪問的時候需要AssetManager類。
  2. res/raw不可以有目錄結構,而assets則可以有目錄結構,也就是assets目錄下可以再建立文件夾。

針對不同的情況,對于資源文件有不同的優化策略。一般來講,對于res/drawable-**ddpi中的png資源可以進行壓縮。

圖片資源優化策略

格式壓縮

使用TinyPng或者Guetzli進行壓縮。Guetzli的使用可以參見我之前寫的博文在Mac上使用Google圖片壓縮工具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圖像。

看下圖:


webp_compress_performance.png

壓縮效率極高,僅為PNG格式的12%。驚喜不驚喜。。。

使用矢量圖形

您可以使用矢量圖形來創建與分辨率無關的圖標和其他可伸縮媒體。使用這些圖形可以大大減少您的APK足跡。矢量圖像在Android中表示為VectorDrawable對象。通過一個VectorDrawable對象,一個100字節的文件可以生成一個與屏幕尺寸一致的清晰圖像。

但是,系統渲染每個 VectorDrawable對象需要很長時間,而較大的圖像需要更長的時間才能顯示在屏幕上。因此,只有在顯示小圖像時才考慮使用這些矢量圖形。

其它策略

有時候我們可能對一張圖片進行重復利用,比如一張圖片僅僅是整體顏色的變換可以使用setColorFilter或者tint。盡量減少使用幀動畫,那可是一堆圖片呀。

壓縮資源

要啟用資源壓縮,請在 build.gradle 文件中將 shrinkResources 屬性設置為 true。

android {...buildTypes {release {shrinkResources trueminifyEnabled trueproguardFiles 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 

safestrict的優化策略:

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"
}

?

04 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 moreCaused 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

另外關于SO的優化我會單獨拿出來講一講。



原文鏈接:https://www.jianshu.com/p/5921e9561f5f

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/278082.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/278082.shtml
英文地址,請注明出處:http://en.pswp.cn/news/278082.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

DHT網絡

(基礎技術) 現在有一種方法&#xff0c;可以通過磁力鏈接&#xff0c;例如magnet:?xturn:btih:0482e0811014fd4cb5d207d08a7be616a4672daa&#xff0c;就可以獲取BT文件。 這個是通過DHT網絡來實現的。 DHT網絡是一個去中心化的&#xff0c;分布式信息存儲系統。 存儲的信息就…

Java基礎 Day04(個人復習整理)

分支結構 2、switch語句 因為if語句的級聯式最多只會處理三種情況&#xff0c;如果出現多情況 1>可以繼續使用if語句的級聯式&#xff0c;但是可能代碼的可讀性就會變差。  2>采用switch語句來解決。 switch語法格式&#xff1a; switch (存在多種情況的變量) {case 值…

java如何獲取一個double的小數位數

前言 看標題是不是覺得這是一個很簡單的問題&#xff0c;我一開始也是這么認為的&#xff0c;但是實際情況下&#xff0c;在各種情況下我們都進行了測試&#xff0c;發現很多實際情況是無法不盡如人意的。 方法分析 當前能想到的比較容易有下面幾種 1、直接使用double處理 2、將…

Node文件模塊

在上一篇文章中有提到&#xff0c;Node模塊分為核心模塊和文件模塊&#xff0c;接下來就簡單總結一下文件模塊。 文件模塊則是在運行時動態加載&#xff0c;需要完整的路徑分析、文件定位、編譯執行過程、速度相比核心模塊稍微慢一些&#xff0c;但是用的非常多。這些模塊需要我…

PHP GD庫解析一張簡單圖片并輸出

這里只演示一下2種顏色值的圖片&#xff0c;簡單描述下概念。 首先要安裝下GD庫。否則下面的代碼運行不了。 $size getimagesize(2.png); // 獲取圖片大小 $res imagecreatefrompng(2.png); // 獲取指定圖片的資源對象for ($i 0; $i < $size[1]; $i) {for ($j 0; $j &…

Permutations CodeForces - 736D (矩陣逆)

對于刪除每個對(x,y), 可以發現他對答案的貢獻為代數余子式$A_{xy}$ 復習了一下線代后發現代數余子式可以通過伴隨矩陣求出, 即$A_{xy}A^*[y][x]$, 伴隨矩陣$A^*|A|A^{-1}$可以通過高斯消元$O(\frac{n^3}{\omega})$求出 #include <iostream> #include <algorithm> …

開發Teams的messaging extension

什么是Messaging Extension Messaging Extension是微軟Teams的一種十分有用的擴展方式。可以讓用戶發送adaptive cards。具體的說明不在這里展開了。可以閱讀微軟官方的詳細說明&#xff1a; https://docs.microsoft.com/en-gb/microsoftteams/platform/concepts/messaging-e…

歸并排序(轉)

轉載自&#xff1a;https://www.cnblogs.com/chengxiao/p/6194356.html 歸并排序&#xff08;MERGE-SORT&#xff09;是利用歸并的思想實現的排序方法&#xff0c;該算法采用經典的分治&#xff08;divide-and-conquer&#xff09;策略&#xff08;分治法將問題分(divide)成一些…

Site24x7 為Teams提供可智能 DevOps

我們生活在一個云的時代, SaaS 應用程序每天都在推動我們的生產力。作為一個消費者, 很難想象如果你最喜歡的應用無法訪問&#xff0c;即使只是一秒鐘無法訪問。作為 SaaS業務, 更難以想象您的服務面臨停機, 每一分鐘停止服務都會花費大量的資金, 當然還損失客戶的信任。Site24…

XUbuntu22.04之跨平臺容器格式工具:MKVToolNix(二百零三)

簡介&#xff1a; CSDN博客專家&#xff0c;專注Android/Linux系統&#xff0c;分享多mic語音方案、音視頻、編解碼等技術&#xff0c;與大家一起成長&#xff01; 優質專欄&#xff1a;Audio工程師進階系列【原創干貨持續更新中……】&#x1f680; 優質專欄&#xff1a;多媒…

redis集群搭建踩坑筆記

推薦參考教程&#xff1a;https://blog.csdn.net/pucao_cug/article/details/69250101 錯誤&#xff1a; from /usr/lib/ruby/2.3.0/rubygems/core_ext/kernel_require.rb:55:in require from /usr/local/redis-3.0.6/src/redis-trib.rb:25:in <main> 解決&#xff1a; g…

Docker 創建鏡像

文章首發自個人網站&#xff1a;https://www.exception.site/docker/docker-create-image 本文中&#xff0c;您將學習 Docker 如何創建鏡像&#xff1f;Docker 創建鏡像主要有三種&#xff1a; 基于已有的鏡像創建&#xff1b;基于 Dockerfile 來創建&#xff1b;基于本地模板…

hdfoo站點開發筆記

為了安全,也要兼顧編輯器切換管理 開發時不必管目錄名稱的事, 只是在部署的時候,才修改應用目錄和tp目錄的名字就行了. 為了提高tp的加載效率, 始終給app和tp以絕對路徑.就是以 realpath來定位 realpath返回的就是 一個絕對路徑, 在lx中是以 斜杠 根樹開始的. 參數可以是文件名…

論文致謝

這篇致謝語&#xff0c;是我論文的最后一節&#xff0c;也是我放在最后的最后寫的內容。之所以拖到最后&#xff0c;是因為我不知道該用怎么的方式來結束我的論文。我想&#xff0c;要結束的不只是文章&#xff0c;還是研究生生涯&#xff0c;是我在廈門大學三年來的一切&#…

使用Azure Pipelines來實現Teams App的CI

我在之前的文章里介紹了如何一步步配置CI/CD來部署Teams App( 之前的文章 )&#xff0c;隨著Azure DevOps的發展&#xff0c;微軟推出了Azure Pipelines。在這篇文章中&#xff0c;主要介紹什么是Azure Pipelines&#xff0c;以及如何使用Azure Pipelines來進行Teams App的構建…

004-React入門概述

一、概述 參考地址&#xff1a;https://reactjs.org/docs/try-react.html 1.1、本地快速體驗 <!DOCTYPE html> <html><head><meta charset"UTF-8" /><title>Hello World</title><script src"https://unpkg.com/react16/…

Python --- 卸載

python的卸載 1、? rpm -qa|grep python3.6|xargs rpm -ev --allmatches --nodeps ##強制刪除已安裝程序及其關聯 2、? whereis python3.6 |xargs rm -frv 允許你對輸出執行其他某些命令 3、? whereis python ##驗證刪除&#xff0c;返回無結果轉載于:https://www.…

開發Teams Tabs應用程序

什么是Teams Tabs Tabs是微軟Teams的一種十分有用的擴展方式。可以非常方便的和現有的網站或者網頁應用進行整合。具體的說明不在這里展開了。可以閱讀微軟官方的詳細說明&#xff1a; https://docs.microsoft.com/en-gb/microsoftteams/platform/concepts/tabs/tabs-overvie…

(轉)關于SimpleDateFormat安全的時間格式化線程安全問題

想必大家對SimpleDateFormat并不陌生。SimpleDateFormat 是 Java 中一個非常常用的類&#xff0c;該類用來對日期字符串進行解析和格式化輸出&#xff0c;但如果使用不小心會導致非常微妙和難以調試的問題&#xff0c;因為 DateFormat 和 SimpleDateFormat 類不都是線程安全的&…

IDEA開發工具的學習

1.設置jdk的版本 &#xff0c;快捷鍵&#xff1a;ctrl shirt alt s 打開項目的設置&#xff0c;選擇Project 進行 jdk版本的設置。 2.鼠標移到項目上&#xff0c;右鍵&#xff0c;Show in Explorer 定位到當前項目對應的文件夾中 3.每次關閉項目時&#xff0c;需要手動選擇Fi…