背景

閒魚包大小隨着用戶的增多和業務的持續迭代不斷增長。過去的半年時間,Android端包大小漲了43%,iOS端也漲了26%,若再不加管控,按照目前的增長速度iOS再過1年可直逼200M。

包大小對

應用的下載轉化率和留存率起到至關重要的作用。首先是蘋果公司不支持流量下載超過200M的包,且據Google play統計,包大小每增加6M,下載轉化率會下跌1%。此外也能提升用戶的留存率,因爲當手機內存不夠用時,會優先刪除佔內存較大的app。

爲了讓每一次新需求集成時,開發能切實感受到對整體包大小的影響,讓每一次包大小變動都有跡可循,需要對包大小進行科學分析。現在開發每次提交代碼後,會觸發打包平臺自動打包,包構建成功後會自動進行包對比分析,併發回開發包增量分析報告郵件。在介紹這個包增量分析工具之前,先給大家科普下安裝包的構成。

安裝包構成

安卓包構成

Android安裝包是以後綴名爲“apk”的壓縮包。閒魚安裝包解壓後的主要構成如下:

AndroidManifest.xml

配置文件:包含包名、組件、權限的配置信息等。

resources.arsc

android資源索引表:包含資源名稱、類型、值、ID和配置信息。

classes.dex

:是很多.class文件處理後的產物,最終可以在 Android 運行時環境執行。

/assets

:放置隨包打入的文件,如text、二進制數據等。

/res

資源文件:存放圖片、字符串、佈局文件、xml文件等,運行打包時沒有使用的文件資源不會打入包中。

/lib :程序運行時依賴的庫。

iOS包構成

iOS安裝包是後綴爲“ipa”的壓縮包,解壓後主要包含以下幾部分:
簽名文件:裏面的CodeResources包含對bundle中的所有資源文件的簽名信息。
資源文件:程序運行過程中需要的資源,比如圖片、音頻、視頻、nib文件、配置文件等。
可執行文件:是通過編譯器、連接器將我們編寫的代碼、靜態庫、動態庫編譯成的文件,是程序的主體。其中靜態庫在鏈接時會被完整的複製到可執行文件中,被多次使用就有多份拷貝,動態庫則是鏈接時不復制,程序運行時由系統動態加載到內存,系統只加載一次,多個程序共用。
bundle文件:工程中使用的其他第三方或資源的bundle。

包分析方案

安卓包分析

apk壓縮包按照資源文件類型分類,主要有:so資源(程序運行依賴的庫,如接入UC瀏覽器內核SDK時,引入的so達到驚人的12M)、圖片資源(png、webp、jpg等)、Java代碼(dex文件)、xml代碼這幾類,此外還可橫向統計flutter相關資源情況。

由於可以拿到單個文件的信息,所以我們開發了工具解析apk包中的內容,從文件類型角度分析包資源佔比情況,以及將資源文件按照大小排序展示,並以圖表形式直觀告訴開發資源情況。

iOS靜態庫大小

通過分析link map文件獲得靜態庫大小,網上有很多link map的解析工具。核心是解析link map文件中的Object files和Symbols中的數據。

每一行代表對應可執行文件的編號,如CPUPermute.o文件編號是3。

在Symbols部分,Address是偏移地址,Size是所佔內存大小,File所指的編號就是Object files中的文件編號,將Symbols中所有相同編號的Size累加起來,即可獲得該編號對應可執行文件的大小了。

然後根據可執行文件的目錄信息,可知該文件所屬的靜態庫,從而計算出對應靜態庫代碼大小。此外靜態庫大小在計算時需要排除對應的

dead Stripped Symbols 的大小來獲得真正的二進制大小,因爲這些是無用的符號,鏈接的時候不會加入。

iOS動態庫大小

動態庫通常位於安裝文件根目錄下的Frameworks目錄中,通常是一個後綴爲.framework的文件夾。

由於動態庫在arm64架構下比較大,且蘋果在拆包階段會將打包好的通用的主二進制和動態庫拆分成單架構的主二進制和動態庫,所以只要是涉及二進制只計算arm64單架構的情況即可。

動態庫大小是直接用

lipo 拆成arm64單架構大小後計算framework文件夾佔磁盤大小獲得。

iOS模塊大小

模塊大小爲庫大小+該模塊所有資源文件佔磁盤的大小,若爲動態庫的模塊,則資源大小僅計算拷貝到主bundle的資源。分析結果如下圖所示:

需求增量卡口

瘦包主要靠開發努力,要讓大家在平時開發中有瘦包的意識,最好有工具能讓開發在日常開發中清楚知道每個文件/模塊的大小,切實感受到需求集成後對整體包大小的影響和相關文件/模塊變動情況,從而促進開發進行相應的優化。

增量自動分析

通過將前面介紹的包分析能力集成到打包腳本,在每次包構建成功時,也會同步產出基礎的包內容信息,再通過進一步的分析後獲得包中每個文件/模塊的大小情況。當代碼改動觸發重新打出新包後,文件/模塊通過一一對比的方式,找出哪些有新增,哪些被刪除,哪些內容發生變動,以及變動產生的大小,併產出對比報告郵件。通過這樣的方式讓開發對代碼增量有一個直觀感受。
那如何讓包增量分析工具能在日常開發中持續穩定發揮作用呢,接下來介紹閒魚的需求增量卡口設計。

增量卡口設計

在之前,閒魚的包大小差異通常都在拉出集成分支,打出版本release包時才發現,經常會震驚於這個版本的包又比上一個版本要大幾M,然後再緊急去尋找是什麼需求集成導致的巨大增量。但這時發現包大小的問題已經非常滯後了,版本馬上就要發佈,這個時候即使抓到了劇增的源頭,也很難在短時間內進行優化。

因此需要增加需求集成卡口,測試通過後在合入主分支之前,經過包增量確認再集成,而不是在集成後打出release包時。現在的做法如下,開發只需要提交代碼,即可自動獲得包增量分析報告。

其中包增量對比郵件內容,會包含與主分支最新構建、當前分支前一次構建,當前分支最初一次構建包的包大小和增量的對比結果。此外爲了數據的準確性,需要開發在拉出開發分支後先構建一個基準包,並在提測和集成前合併一把主幹,這樣報告數據纔會更準確。

最後是提測部分,開發同學發送提測郵件時需要標註本次提測包增量及圖片壓縮情況,若需求增量大於100K,根據超出範圍情況,需要備註原因和老闆確認。bug修復期間不免也會有代碼改動,在測試完成後集成前,會再確認一次包增量情況再集成。

效果與展望

閒魚需求增量卡口自6.20正式上線以來,所有客戶端新需求都受到了嚴格的卡口,可以感受到以下明顯變化:

  • iOS當前V6.7.40實現半年多以來首次出現了降幅。

  • 開發過程中,開發有意識通過優化老業務代碼和資源,爲新需求增量挪出空間。

需求增量卡口是長效控制包大小的一個關鍵路徑,加強開發在日常編碼中的瘦包意識,讓每一次需求都有跡可循。此外flutter產物更精細的分析方案和有效的瘦身方法也在持續探索中,對於存量的資源、業務代碼清理等手段也在有序進行,請對小胖魚早日瘦身拭目以待吧~

閒魚技術團隊不僅是阿里巴巴集團旗下閒置交易社區的創造者,更是移動與高併發大數據應用新技術的引導者與創新者。我們與 Google Flutter/Dart 小組密切合作,爲社區貢獻了多個高 star 的項目和大量 PR 。我們正在積極探索深度學習和視覺技術在互動、交易、社區場景的創新應用。閒魚技術與集團中間件團隊共同打造的 FaaS 平臺每天支持數以千萬級用戶的高併發訪問場景。  

就是現在! 客戶端/服務端java/架構/前端/質量 工程師 面向社會+校園招聘,base杭州阿里巴巴西溪園區,一起做有創想空間的社區產品、做深度頂級的開源項目,一起拓展技術邊界成就極致!

*投餵簡歷給小閒魚→ [email protected]

開源項目、峯會直擊、關鍵洞察、深度解讀

請認準 閒魚技術

相關文章