主頁 > 移動端開發 > Android包體積優化(常規、進階、極致)

Android包體積優化(常規、進階、極致)

2021-10-08 08:45:47 移動端開發

前言

包大小的重要性已經不需要多說,包大小直接影響用戶的下載,留存,甚至部分廠商預裝強制要求必須小于一定的值,但是隨著業務的迭代開發,應用會越來越大,安裝包會不停的膨脹,因此包大小縮減是一個長期持續的治理程序,

  • 提升下載轉化率,安裝包越小,轉化率越高,
  • 降低渠道推廣成本,
  • 降低安裝時間,檔案拷貝、Library解壓、編譯ODEX、簽名校驗這些,包體積越大越耗時,
  • 降低運行時記憶體等等,

環境

  • Android Studio Arctic Fox | 2020.3.1 Patch 2
  • AGP 7.0
  • 專案地址:wanandroid_jetpack

優化前

在這里插入圖片描述

  • 4.7MB,4.2MB是google play下載的大小,會有壓縮,

除了AS自帶的Analyzer之外,還有ApkChecker、ClassyShark等工具,

APK的組成

檔案描述
libso檔案,不同的cpu架構
res編譯后的資源檔案,drawable、layout等
assets應用程式的資源、字體、音頻檔案等
classes(n).dexdx編譯后的java檔案
META-INF簽名資訊相關
resources.arsc二進制資源檔案
kotlin編譯后的kotlin檔案
AndroidManifest.xml清單檔案

APK構建流程

在這里插入圖片描述
這是官方新版的打包流程,雖然省略了一些步驟,但是大致的流程還是比較清晰的,
再次簡化一下:

資源檔案、Java檔案 > dex檔案 > APK

優化思路

APK本質是一個壓縮檔案,是打包后的產物,那可以作為切入點的階段就是打包前、以及打包中,

  • 打包前,即減少打包的檔案,比如無用的資源、代碼;
  • 打包中,對打包中的產物進行壓縮,比如資源檔案、So檔案;

關鍵詞:減少、壓縮,

常規操作

1.Lint檢測無用資源檔案

Analyze > Run Inspection by Name > Unused resources

在這里插入圖片描述
在這里插入圖片描述
檢測結果:
在這里插入圖片描述
確定無用洗掉即可,

注意:
因為lint是本地靜態掃描,所以動態參考的資源檔案并不會識別出來,也會出現在檢測串列里,

2.Lint檢測代碼

Analyze > Inspect code 

在這里插入圖片描述
檢測結果:
在這里插入圖片描述
因為這個專案是用kotlin寫的,所以直接看kotlin目錄下的檢測結果,

注意:
因為lint是本地靜態掃描,所以反射、動態參考的class并不會識別出來,也會出現在檢測串列里,

3.圖片壓縮

推薦使用tinypng在線壓縮,

4.TinyPngPlugin

手動壓縮畢竟不高效,可以使用TinyPngPlugin一鍵壓縮,
plugins搜索TinyPng安裝即可,(新版AS安裝完plugin已經不需要重啟了)

壓縮結果:
在這里插入圖片描述
9張圖片,可以看到效果還是非常可觀的,
如果圖片多,效果更加明顯,

經過上面的操作,包體積減小4%,這還只是一個4.7MB的APK而已,

5.WebP

那這9張圖還能繼續優化嗎?
可以,WebP格式的體積更小,而已AS也提供了一鍵轉換支持,
在這里插入圖片描述
以ic_avatar.png為例:

ic_avatar.png優化后
原始大小113.09KB
TingPng壓縮36.85KB
WebP8.66KB

可以看到,轉WebP之后,較原始大小減少了近93%,恐怖如斯~

6.開啟混淆

minifyEnabled true,默認啟用R8代碼縮減功能,

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

慎用R8,因為:

R8 會忽略試圖修改默認優化行為的所有 ProGuard 規則,例如 -optimizations 和 - optimizationpasses,

可以開啟混淆,而不使用R8,

android.enableR8=false
android.enableR8.libraries=false

混淆參考:Android混淆從入門到精通

7.縮減資源

shrinkResources true

假如有一些資源檔案不確定還用不用,也不敢刪,或者不確定需求是否會變更,所以先留著,那這種情況怎么辦呢?
可以使用shrinkResources來縮減資源,

    buildTypes {
        debug {
            minifyEnabled false
        }
        release {
            shrinkResources true
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }

要配合混淆minifyEnabled一起使用才行,原理也很簡單,代碼移除之后,參考的資源也就變成無用資源了,才可以進一步縮減,

8.so檔案縮減

比如集成了一個三方的直播或者瀏覽器,可能會提供很多so檔案,起初可能是一股腦的copy進專案,但并不一定都用的到,
比如各種cpu架構的so:

app/build/intermediates/cmake/universal/release/obj/
├── armeabi-v7a/
│   ├── libgameengine.so
│   ├── libothercode.so
│   └── libvideocodec.so
├── arm64-v8a/
│   ├── libgameengine.so
│   ├── libothercode.so
│   └── libvideocodec.so
├── x86/
│   ├── libgameengine.so
│   ├── libothercode.so
│   └── libvideocodec.so
└── x86_64/
    ├── libgameengine.so
    ├── libothercode.so
    └── libvideocodec.so

目前市面上的手機cpu都是arm架構的,所以保留arm的一種即可(定制的除外),armeabi-v7aarmeabi都可,其他直接洗掉,

android {
    defaultConfig {
        ndk {
            abiFilters 'armeabi-v7a'
        }
    }
}

如果開發需要模擬器除錯,就加上x86的架構,正式包記得去掉,或者在local.properties中用變數控制一下,

這塊如果之前沒有優化過,而又有很多so檔案的話,或許可以減少30%以上,恐怖如斯!

9.移除未使用的備用資源

在這里插入圖片描述
很多出海的應用會做國際化,但也適配不了這么多的語言,
除了自己app的之外,還有一些官方的、三方的,可以統一配置支持的語言,

    defaultConfig {
        resConfigs("en","zh","zh-rCN")
    }

資源檔案同理

    defaultConfig {
        resConfigs("xxhdpi","xxxhdpi")
    }

10.小結

針對上面的操作做個小結,看看目前效果如何,
在這里插入圖片描述

2MB,包體積減少57%,恐怖如斯!

如果是大型專案,收益非常可觀,

author:yechaoa

進階操作

上面只是一些常規操作,下面看一些進階操作,

1.resources.arsc資源混淆

資源混淆就是將原本冗長的資源路徑變短,例如將res/drawable/wechat變為r/d/a,
開源工具AndResGuard,

2.移除無用的三方庫

引入之后未使用的,或者是功能下架之后未移除的,

3.功能重復的三方庫整合

比如glide和picasso,都是圖片庫,保留其一即可,

4.ReDex

dex檔案是打包中的產物,redex是facebook開源的分包優化方案,
可以參考:ReDex,

5.so動態加載

前面已經做了so檔案縮減,但是可能so檔案占比還是比較大,可以考慮除了首次啟動外的so檔案做動態下發,
也就是插件化的思想,按需加載,但是收益很大的同時,風險也很大,有很多case需要考慮到,比如下載時機、網路環境、執行緒行程,加載失敗是否有降級策略等等,

可以參考facebook開源的SoLoader,

6.插件化

按需加載,收益越大風險越大,風險同上,

極致操作

那如果我想做到極致,還有哪些騷操作呢,ok,繼續,

1.原生改用H5或小程式等方案

有些功能可能原生做就顯得太重,比如各種促銷活動,需要加載各種大圖,原生既重又不夠動態化,這個時候H5是一種很好的替代方案,
但是如果你原本就不支持H5或者小程式的話,接入這種能力可能反而會加大包體積,做好對比,

2.砍功能

有些功能可能想的很美好,但上線之后收益并不大,是否需要重新思考價值點,最好找到資料依托,再跟產品打架,

3.修改三方庫的原始碼,不需要的代碼剔除

比如引入了一個功能很齊全的三方庫utils,但實際只用到幾個,對原始碼進行抽取也能減少包體積,同時還能減少網路下載的編譯時間,
弊端就是升級成本較大,

4.圖片網路化

即把圖片上傳到服務器,通過動態下載的方式減少包體積,弊端就是首次加載的時候依賴網路環境,對加載速度、流量需要做一個平衡,
圖片可以預加載,但是流量消耗是無法避免了,如果比較在意流量指標,需要權衡了,

5.DebugItem

DebugItem 里面主要包含兩種資訊:

  • 除錯的資訊,函式的引數變數和所有的區域變數,
  • 排查問題的資訊,所有的指令集行號和源檔案行號的對應關系,

去除debug資訊與行號資訊,如果不是極致,不推薦,
可以參考支付寶的這篇 支付寶 App 構建優化決議:Android 包大小極致壓縮,

6.R Field行內

行內R Field可以解決R Field過多導致MultiDex 65536的問題,而這一步驟對代碼瘦身能夠起到明顯的效果,

美團代碼片段:

ctBehaviors.each { CtBehavior ctBehavior ->
    if (!ctBehavior.isEmpty()) {
        try {
            ctBehavior.instrument(new ExprEditor() {
                @Override
                public void edit(FieldAccess f) {
                    try {
                        def fieldClassName = JavassistUtils.getClassNameFromCtClass(f.getCtClass())
                        if (shouldInlineRField(className, fieldClassName) && f.isReader()) {
                            def temp = fieldClassName.substring(fieldClassName.indexOf(ANDROID_RESOURCE_R_FLAG) + ANDROID_RESOURCE_R_FLAG.length())
                            def fieldName = f.fieldName
                            def key = "${temp}.${fieldName}"

                            if (resourceSymbols.containsKey(key)) {
                                Object obj = resourceSymbols.get(key)
                                try {
                                    if (obj instanceof Integer) {
                                        int value = ((Integer) obj).intValue()
                                        f.replace("\$_=${value};")
                                    } else if (obj instanceof Integer[]) {
                                        def obj2 = ((Integer[]) obj)
                                        StringBuilder stringBuilder = new StringBuilder()
                                        for (int index = 0; index < obj2.length; ++index) {
                                            stringBuilder.append(obj2[index].intValue())
                                            if (index != obj2.length - 1) {
                                                stringBuilder.append(",")
                                            }
                                        }
                                        f.replace("\$_ = new int[]{${stringBuilder.toString()}};")
                                    } else {
                                        throw new GradleException("Unknown ResourceSymbols Type!")
                                    }
                                } catch (NotFoundException e) {
                                    throw new GradleException(e.message)
                                } catch (CannotCompileException e) {
                                    throw new GradleException(e.message)
                                }
                            } else {
                                throw new GradleException("******** InlineRFieldTask unprocessed ${className}, ${fieldClassName}, ${f.fieldName}, ${key}")
                            }
                        }
                    } catch (NotFoundException e) {
                    }
                }
            })
        } catch (CannotCompileException e) {
        }
    }
}

同時可以參考位元組開源的shrink-r-plugin,還有滴滴開源的booster,

7.圖片著色器

針對同圖不同色的處理,可以使用tint,比如原本是一個黑色的回傳icon,現在另一個頁面要用白色了,就不需要兩張圖了,而是使用tint來修改為白色即可,

			<ImageView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:src="@drawable/ic_back_black"
                android:tint="@android:color/white" />

8.減少ENUM的使用

每減少一個ENUM可以減少大約1.0到1.4 KB的大小,

包體積監控

包體積監控應該作為發布流程的一個環節,最好是做到平臺化、流程化,否則很難持續,沒幾個版本包體積又漲上來了,

大致思想:當前版本與上一個版本的包大小做對比,超過200KB需要審批,臨時審批需要給出后續優化方案等等,

參考檔案

  • Improve your code with lint checks
  • Shrink, obfuscate, and optimize your app
  • Android App包瘦身優化實踐
  • ReDex
  • SoLoader
  • 支付寶 App 構建優化決議:Android 包大小極致壓縮
  • AndResGuard
  • 深入探索 Android 包體積優化
  • Android開發高手課包體積優化

轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/306276.html

標籤:其他

上一篇:基于 Vmware 搭建 Ubuntu Server 編譯環境(Samba + SSH + Git)

下一篇:Android隱藏選單欄

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【從零開始擼一個App】Dagger2

    Dagger2是一個IOC框架,一般用于Android平臺,第一次接觸的朋友,一定會被搞得暈頭轉向。它延續了Java平臺Spring框架代碼碎片化,注解滿天飛的傳統。嘗試將各處代碼片段串聯起來,理清思緒,真不是件容易的事。更不用說還有各版本細微的差別。 與Spring不同的是,Spring是通過反射 ......

    uj5u.com 2020-09-10 06:57:59 more
  • Flutter Weekly Issue 66

    新聞 Flutter 季度調研結果分享 教程 Flutter+FaaS一體化任務編排的思考與設計 詳解Dart中如何通過注解生成代碼 GitHub 用對了嗎?Flutter 團隊分享如何管理大型開源專案 插件 flutter-bubble-tab-indicator A Flutter librar ......

    uj5u.com 2020-09-10 06:58:52 more
  • Proguard 常用規則

    介紹 Proguard 入口,如何查看輸出,如何使用 keep 設定入口以及使用實體,如何配置壓縮,混淆,校驗等規則。

    ......

    uj5u.com 2020-09-10 06:59:00 more
  • Android 開發技術周報 Issue#292

    新聞 Android即將獲得類AirDrop功能:可向附近設備快速分享檔案 谷歌為安卓檔案管理應用引入可安全隱藏資料的Safe Folder功能 Android TV新主界面將顯示電影、電視節目和應用推薦內容 泄露的Android檔案暗示了傳說中的谷歌Pixel 5a與折疊屏新機 谷歌發布Andro ......

    uj5u.com 2020-09-10 07:00:37 more
  • AutoFitTextureView Error inflating class

    報錯: Binary XML file line #0: Binary XML file line #0: Error inflating class xxx.AutoFitTextureView 解決: <com.example.testy2.AutoFitTextureView android: ......

    uj5u.com 2020-09-10 07:00:41 more
  • 根據Uri,Cursor沒有獲取到對應的屬性

    Android: 背景:呼叫攝像頭,拍攝視頻,指定保存的地址,但是回傳的Cursor檔案,只有名稱和大小的屬性,沒有其他諸如時長,連ID屬性都沒有 使用 cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DURATIO ......

    uj5u.com 2020-09-10 07:00:44 more
  • Android連載29-持久化技術

    一、持久化技術 我們平時所使用的APP產生的資料,在記憶體中都是瞬時的,會隨著斷電、關機等丟失資料,因此android系統采用了持久化技術,用于存盤這些“瞬時”資料 持久化技術包括:檔案存盤、SharedPreference存盤以及資料庫存盤,還有更復雜的SD卡記憶體儲。 二、檔案存盤 最基本存盤方式, ......

    uj5u.com 2020-09-10 07:00:47 more
  • Android Camera2Video整合到自己專案里

    背景: Android專案里呼叫攝像頭拍攝視頻,原本使用的 MediaStore.ACTION_VIDEO_CAPTURE, 后來因專案需要,改成了camera2 1.Camera2Video 官方demo有點問題,下載后,不能直接整合到專案 問題1.多次拍攝視頻崩潰 問題2.雙擊record按鈕, ......

    uj5u.com 2020-09-10 07:00:50 more
  • Android 開發技術周報 Issue#293

    新聞 谷歌為Android TV開發者提供多種新功能 Android 11將自動填表功能整合到鍵盤輸入建議中 谷歌宣布Android Auto即將支持更多的導航和數字停車應用 谷歌Pixel 5只有XL版本 搭載驍龍765G且將比Pixel 4更便宜 [圖]Wear OS將迎來重磅更新:應用啟動時間 ......

    uj5u.com 2020-09-10 07:01:38 more
  • 海豚星空掃碼投屏 Android 接收端 SDK 集成 六步驟

    掃碼投屏,開放網路,獨占設備,不需要額外下載軟體,微信掃碼,發現設備。支持標準DLNA協議,支持倍速播放。視頻,音頻,圖片投屏。好點意思。還支持自定義基于 DLNA 擴展的操作動作。好像要收費,沒體驗。 這里簡單記錄一下集成程序。 一 跟目錄的build.gradle添加私有mevan倉庫 mave ......

    uj5u.com 2020-09-10 07:01:43 more
最新发布
  • 歡迎頁輪播影片

    如圖,引導開始,球從上落下,同時淡入文字,然后文字開始輪播,最后一頁時停止,點擊進入首頁。 在來看看效果圖。 重力球先不講,主要歡迎輪播簡單實作 首先新建一個類 TextTranslationXGuideView,用于影片展示 文本是類似的,最后會有個圖片箭頭影片,布局很簡單,就是一個 TextVi ......

    uj5u.com 2023-04-20 08:40:31 more
  • 【FAQ】關于華為推送服務因營銷訊息頻次管控導致服務通訊類訊息

    一. 問題描述 使用華為推送服務下發IM訊息時,下發訊息請求成功且code碼為80000000,但是手機總是收不到訊息; 在華為推送自助分析(Beta)平臺查看發現,訊息發送觸發了頻控。 二. 問題原因及背景 2023年1月05日起,華為推送服務對咨詢營銷類訊息做了單個設備每日推送數量上限管理,具體 ......

    uj5u.com 2023-04-20 08:40:11 more
  • 歡迎頁輪播影片

    如圖,引導開始,球從上落下,同時淡入文字,然后文字開始輪播,最后一頁時停止,點擊進入首頁。 在來看看效果圖。 重力球先不講,主要歡迎輪播簡單實作 首先新建一個類 TextTranslationXGuideView,用于影片展示 文本是類似的,最后會有個圖片箭頭影片,布局很簡單,就是一個 TextVi ......

    uj5u.com 2023-04-20 08:39:36 more
  • 【FAQ】關于華為推送服務因營銷訊息頻次管控導致服務通訊類訊息

    一. 問題描述 使用華為推送服務下發IM訊息時,下發訊息請求成功且code碼為80000000,但是手機總是收不到訊息; 在華為推送自助分析(Beta)平臺查看發現,訊息發送觸發了頻控。 二. 問題原因及背景 2023年1月05日起,華為推送服務對咨詢營銷類訊息做了單個設備每日推送數量上限管理,具體 ......

    uj5u.com 2023-04-20 08:39:13 more
  • iOS從UI記憶體地址到讀取成員變數(oc/swift)

    開發除錯時,我們發現bug時常首先是從UI顯示發現例外,下一步才會去定位UI相關連的資料的。XCode有給我們提供一系列debug工具,但是很多人可能還沒有形成一套穩定的除錯流程,因此本文嘗試解決這個問題,順便提出一個暴論:UI顯示例外問題只需要兩個步驟就能完成定位作業的80%: 定位例外 UI 組 ......

    uj5u.com 2023-04-19 09:16:23 more
  • FIDE重磅更新!性能飛躍!體驗有禮!

    FIDE 開發者工具重構升級啦!實作500%性能提升,誠邀體驗! 一直以來不少開發者朋友在社區反饋,在使用 FIDE 工具的程序中,時常會遇到諸如加載不及時、代碼預覽/渲染性能不如意的情況,十分影響開發體驗。 作為技術團隊,我們深知一件趁手的開發工具對開發者的重要性,因此,在2023年開年,FinC ......

    uj5u.com 2023-04-19 09:16:15 more
  • 游戲內嵌社區服務開放,助力開發者提升玩家互動與留存

    華為 HMS Core 游戲內嵌社區服務提供快速訪問華為游戲中心論壇能力,支持玩家直接在游戲內瀏覽帖子和交流互動,助力開發者擴展內容生產和觸達的場景。 一、為什么要游戲內嵌社區? 二、游戲內嵌社區的典型使用場景 1、游戲內打開論壇 您可以在游戲內繪制論壇入口,為玩家提供沉浸式發帖、瀏覽、點贊、回帖、 ......

    uj5u.com 2023-04-19 09:15:46 more
  • iOS從UI記憶體地址到讀取成員變數(oc/swift)

    開發除錯時,我們發現bug時常首先是從UI顯示發現例外,下一步才會去定位UI相關連的資料的。XCode有給我們提供一系列debug工具,但是很多人可能還沒有形成一套穩定的除錯流程,因此本文嘗試解決這個問題,順便提出一個暴論:UI顯示例外問題只需要兩個步驟就能完成定位作業的80%: 定位例外 UI 組 ......

    uj5u.com 2023-04-19 09:14:53 more
  • FIDE重磅更新!性能飛躍!體驗有禮!

    FIDE 開發者工具重構升級啦!實作500%性能提升,誠邀體驗! 一直以來不少開發者朋友在社區反饋,在使用 FIDE 工具的程序中,時常會遇到諸如加載不及時、代碼預覽/渲染性能不如意的情況,十分影響開發體驗。 作為技術團隊,我們深知一件趁手的開發工具對開發者的重要性,因此,在2023年開年,FinC ......

    uj5u.com 2023-04-19 09:14:08 more
  • 游戲內嵌社區服務開放,助力開發者提升玩家互動與留存

    華為 HMS Core 游戲內嵌社區服務提供快速訪問華為游戲中心論壇能力,支持玩家直接在游戲內瀏覽帖子和交流互動,助力開發者擴展內容生產和觸達的場景。 一、為什么要游戲內嵌社區? 二、游戲內嵌社區的典型使用場景 1、游戲內打開論壇 您可以在游戲內繪制論壇入口,為玩家提供沉浸式發帖、瀏覽、點贊、回帖、 ......

    uj5u.com 2023-04-19 09:08:34 more