<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          iOS包體積優(yōu)化實(shí)踐

          共 8550字,需瀏覽 18分鐘

           ·

          2022-05-26 08:10

          ????關(guān)注后回復(fù)?“進(jìn)群”?,拉你進(jìn)程序員交流群????

          作者丨Augus

          來源丨搜狐技術(shù)產(chǎn)品(ID:sohu-tech)


          ??

          本文字?jǐn)?shù):7972

          預(yù)計閱讀時間:20分鐘

          ?

          用最通俗的語言,描述最難懂的技術(shù)

          前情描述

          最近領(lǐng)導(dǎo)給我分配了包體積監(jiān)控指標(biāo),恰好之前我也做過相關(guān)包體積的優(yōu)化,于是便綜合之前的實(shí)踐經(jīng)驗,對此我們的項目的包體積優(yōu)化做一個整體的記錄,希望可以幫助有需要的小伙伴

          iOS(安裝)包

          ipa全稱為iPhone Application Archive,這里指的包在iOS其實(shí)就是安裝包,直觀展示就是xxx.ipa文件

          iOS包內(nèi)容

          想要對其優(yōu)化,就要知道包里面都有什么,知道了有什么,針對不同類型的文件,做不同的處理,從而達(dá)到一定的優(yōu)化

          我們首先找到一個xxx.ipa文件,然后把后綴改為xxx.zip,然后進(jìn)行解壓縮操作,如下圖所示

          然后右鍵選中顯示包內(nèi)容,里面就是安裝包包含的所有資源,大概可以分為以下幾類

          • _CodeSignature文件夾:ipa包簽名文件的存放文件夾
          • Assets.carAssets.xcassts在編譯過程中生成的最終展示文件,默認(rèn)里面存放各種分辨率圖片(測試項目未使用)
          • embedded.mobileprovision:證書配置文件
          • Info.plist:項目配置表
          • PluginsApp創(chuàng)建的擴(kuò)展,比如WidgetPushShare
          • .IprojApp所支持的語言文件
          • exec文件:可執(zhí)行文件,例如widgetExtension
          • 圖片資源:.png,.jpg,.webp,.gif
          • 其它資源文件
            • .xml,.json
            • .plist:項目中使用資源的.plist文件
            • .bundleMac OS下的資源包集合
            • .conf:相關(guān)的配置文件
            • .cer.der.p12:鑰匙串文件
            • .wav:音頻文件
            • .js.html
            • .nibXcode自帶的數(shù)據(jù)文件,包含一個窗口程序和應(yīng)用程序委托對象
            • .sqlite:數(shù)據(jù)庫文件
            • .txt:文本文件
            • .momXcode創(chuàng)建的數(shù)據(jù)模型文件

          這次測試之前IPA未解壓的大小是76.5MB,解壓之后的大小是140.1MB

          解壓后各個部分大小的明細(xì)如下

          內(nèi)容大小
          _CodeSignature1.8MB
          Assets.car(部分使用)518KB
          embedded.mobileprovision55KB
          Info.plist16KB
          Plugins2.7MB
          Iproj2KB
          exec104.9MB
          圖片資源(.png,.jpg,.webp,.gif16.7MB
          others13.4MB

          優(yōu)化策略

          上述了解完了IPA各個組成之后,我們按照Xcode編譯優(yōu)化,資源文件優(yōu)化以及代碼優(yōu)化的順序來一步一步進(jìn)行分析

          Xcode編譯優(yōu)化

          這個部分是最容易的,也是最容易忽略的,下面是筆者進(jìn)行的總結(jié),我們一個一個分析

          編譯指令集

          首先查看我們目前的架構(gòu)組成

          augus@MacBookPro?xxx.app?%?lipo?-info?xxx
          Architectures?in?the?fat?file:?sohunews?are:?armv7?arm64

          我們再看下各個架構(gòu)指令集對應(yīng)的機(jī)型

          #?armv6:?iPhone,?iPhone?3G,?iPod?1G/2G??
          #?armv7:?iPhone?3GS,?iPhone?4,?iPhone?4S,?iPod?3G/4G/5G,?iPad,?iPad?2,?iPad?3,?iPad?Mini??
          #?armv7s:?iPhone?5,?iPhone?5c,?iPad?4??
          #?arm64:?iPhone?X,iPhone?8(Plus),iPhone?7(Plus),iPhone?6(Plus),iPhone?6s(Plus),?iPhone?5s,?iPad?Air(2),?Retina?iPad?Mini(2,3)??
          #?arm64e:?XS/XS Max/XR/ iPhone 11, iPhone 11 pro,iPhone 11 Pro Max,iPhone SE (2nd generation),iPhone 12 mini,iPhone 12,iPhone 12 Pro,iPhone 12 Pro Max,Phone 13 mini,Phone 13,iPhone 13 Pro,iPhone 13 Pro Max
          #?x86_64:?模擬器64位處理器
          #?i386:?模擬器32位處理器

          此次測試中我們是不需要32位架構(gòu)armv7的,所以我們可以設(shè)置在打包的時候進(jìn)行只打armv64即可。

          方法1:Build Settings-Architectures,把你需要的打包標(biāo)識符下的設(shè)置為arm64Architectures指定工程可以編譯出多個指令集的代碼包,ipa就會變大;

          方法2:Build Settings-Excluded Arcitectures,在你要的打包標(biāo)識符下面增加兩個配置項目Any iOS SDKAny iOS Simulator SDK,然后分別設(shè)置為armv7arm64;這個選項的意思是Release模式下針對真機(jī)armv7指令集排除,針對模擬器把arm64排除。

          這個優(yōu)化之后,ipa壓縮包大小為51.4MB,解壓縮包大小變?yōu)?code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(244, 138, 0);">90.9MB,其中exec變?yōu)?code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(244, 138, 0);">56.6MB,效果很明顯

          代碼優(yōu)化

          Build Settings-Optimization Level在發(fā)布模式設(shè)置為[-Oz],其他模式根據(jù)場景進(jìn)行選擇,具體參考官方文檔(https://help.apple.com/xcode/mac/11.4/#/itcaec37c2a6)進(jìn)行設(shè)置;這個設(shè)置指的是生成的代碼在速度和二進(jìn)制大小方面的優(yōu)化程度

          Optimization Level默認(rèn)是-Os-OzXcode 11新增的編譯優(yōu)化選項,該設(shè)置通過將重復(fù)的代碼模式隔離到編譯器生成的函數(shù)中來實(shí)現(xiàn)額外的尺寸節(jié)省

          以下是不同的選項對應(yīng)的編譯速度和二進(jìn)制文件大小變化趨勢,來源于WWDC2019 Session 409 https://developer.apple.com/videos/play/wwdc2019/409/

          優(yōu)化完成之后ipa大小是51MB,解壓縮包大小是87.9MB

          資源目錄優(yōu)化

          Build Settings-Asset Catalog Compiler Options-Optimization設(shè)置為space;這個選項可以改變actool在構(gòu)建Assets.car時選取的編碼壓縮算法,減少包大小。

          使用以下命令檢查Assets.car中圖片的編碼壓縮算法

          #?可以把對應(yīng)信息生成.json文件,用于對比不同
          xcrun?--sdk?iphoneos?assetutil?--info?Assets.car?>?Assets.json

          項目之前用的是默認(rèn)配置,由于Assets.car存放了少量資源,大部分都是存放在項目的根目錄;

          優(yōu)化之后的ipa包大小是51.3MB,解壓縮包大小是90.8MBAssets.car大小是469KB

          調(diào)試符號

          Build Settings-Generate Debug Symbols設(shè)置為NO;這個選項的意思是是否在源文件編程成.o文件時,添加編譯參數(shù)-g-gmodule,就是generate complete debug info,所以產(chǎn)生的.o會變大,從而最終的可執(zhí)行文件也就會變大。

          需要注意的是,如果設(shè)置為NO,在Xcode中設(shè)置斷點(diǎn)不會中斷,不能進(jìn)行斷點(diǎn)調(diào)試。且最后不能生成dSYM文件,即使Debug Infomation Format設(shè)置了,也無法生成,因為生成的前提是得有調(diào)試信息,建議不要設(shè)置。

          無用符號

          Build Settings-Deployment Postprocessing,調(diào)試模式下NO,發(fā)布模式下YES

          Deployment PostprocessingStrip的總開關(guān)。也就是說,只有Deployment Postprocessing這里設(shè)置了YESStrip Debug Symbols During CopyStrip Linked Product設(shè)置為YES才會生效,其余情況均不生效

          • Strip Linked Product:對最終的二進(jìn)制文件是否進(jìn)行去除無用符號
          • Strip Debug Symbols During Copy:文件拷貝編譯階段是否進(jìn)行strip,設(shè)置為YES之后,會把拷貝進(jìn)項目的第三方庫、資源或者Extension的調(diào)試符號剝離

          這個優(yōu)化之后,ipa壓縮包大小為51.4MB,解壓縮包大小變?yōu)?code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(244, 138, 0);">90.9MB,其中exec變?yōu)?code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(244, 138, 0);">56.6MB,之前已經(jīng)開啟,所以無變化

          第三個關(guān)于符號的優(yōu)化是Build Settings-Symbols Hidden by Default,調(diào)試模式下為NO,發(fā)布模式下為YES。該選項的意思是當(dāng)啟用時,所有的符號多被聲明為私有的extern,除非在代碼中使用attribute((visibility("default")))明確標(biāo)記為導(dǎo)出;反之,則所有符號都會被導(dǎo)出。

          該測試項目中已開啟,包大小無變化

          復(fù)用字符串

          Build Settings-Make Strings Read-Only設(shè)置為YES;就是復(fù)用字符串字面。

          該測試項目中已開啟,包大小無變化

          無效代碼

          Build Settings-Dead Code Stripping設(shè)置為YES;是否消除無用代碼

          該測試項目中已開啟,包大小無變化

          異常捕獲機(jī)制

          Build Settings-搜索exceptions

          如果想要對項目瘦身,需要對途中的綠色未知設(shè)置為NO

          Enable C++ ExceptionsEnable Objective-C Exceptions是指項目對錯誤的異常處理,比如try catch, throw之類的語句;所以如果你的項目中有類似的處理,關(guān)閉這個之后會報錯Cannot use '@try' with Objective-C exceptions disabled。如果宏定義有try,關(guān)閉之后也會報錯

          如果你的項目中可以設(shè)置關(guān)閉捕獲異常的開關(guān),還需要另外設(shè)置Build Settings-Other Link Flags去添加一個字段

          -fno-exceptions代表禁用異常機(jī)制,參考這里:

          http://gcc.gnu.org/onlinedocs/gcc-4.7.0/libstdc++/manual/manual/using_exceptions.html

          現(xiàn)在來總結(jié)下編譯優(yōu)化

          編譯選項_CodeSignatureAssets.carembedded.mobileprovisionInfo.plistPluginsIprojexec圖片資源othersipa解壓縮包
          初始配置1.8MB518KB55KB16KB2.7MB2KB104.9MB16.7MB13.4MB76.5MB140.1MB
          Architectures1.8MB518KB55KB17KB1.8MB2KB56.6MB16.7MB12.6MB51.4MB90.1MB
          Optimization1.8MB469KB55KB17KB1.8MB2KB56.6MB16.7MB13.4MB51.3MB90.8MB
          Optimization Level1.8MB469KB55KB17KB1.8MB2KB53.6MB16.7MB13.5MB51MB87.9MB

          資源文件優(yōu)化

          資源文件的優(yōu)化就相對比較簡單,但是比較繁瑣;與上面的Xcode編譯配置不同,一次設(shè)置永久有效,資源的優(yōu)化需要平時開發(fā)就需要關(guān)注,比如新資源的壓縮,無用資源的刪除等。

          資源文件優(yōu)化大體分為兩個方向,第一個就是無用資源的刪除,第二個就是已用資源的壓縮。這里建議分先后順序,就是先做刪除,后做壓縮,因為如果反過來,就會做一些無用功。

          無用資源的刪除

          • 已定義未使用的代碼文件
          • 已廢棄的業(yè)務(wù),代碼還在
          • 已引用的圖片但未使用
          • 某些重復(fù)資源的導(dǎo)入

          已用資源的優(yōu)化

          • 項目中引入的圖片、網(wǎng)頁、音頻等文件的壓縮

          無用資源的刪除

          隨著項目的迭代,每個項目都會或多或少存在冗余。可能是已經(jīng)下線的業(yè)務(wù),但是沒人通知開發(fā),于是代碼邏輯一直存在;可能是刪除某業(yè)務(wù)代碼的時候,對應(yīng)的圖片資源為刪除;又或者是多個開發(fā)導(dǎo)入了相同功能的第三方庫。

          對于這部分的優(yōu)化分為預(yù)防和治理

          關(guān)于預(yù)防

          個人認(rèn)為首先要有規(guī)范的流程,按流程執(zhí)行,減少信息不對等的情況出現(xiàn)

          產(chǎn)品和開發(fā),廣告和開發(fā),都會導(dǎo)致相關(guān)業(yè)務(wù)的冗余,產(chǎn)品知道具體的業(yè)務(wù)數(shù)據(jù),而開發(fā)不知道,所以通過某個固定時間的一次集中同步,讓開發(fā)可以了解到自己的業(yè)務(wù)是否活躍,從而對項目進(jìn)行相應(yīng)的調(diào)整。

          開發(fā)與開發(fā)之間的消息不對等,會導(dǎo)致各自開發(fā)自己的輪子,重復(fù)造輪子,所以可以通過建立公共文檔、開發(fā)流程規(guī)范、項目使用第三方庫規(guī)范、設(shè)計規(guī)范、代碼規(guī)范都一一列舉出來,每個人都能根據(jù)對應(yīng)的文檔了解到對應(yīng)項目的信息,每個人開發(fā)都應(yīng)該有一套統(tǒng)一的標(biāo)準(zhǔn),這樣就很大程度上避免了一人一套代碼問題的出現(xiàn)。

          具體規(guī)范流程可以根據(jù)自己公司或自己部分的實(shí)際情況來,多問為什么,比如這樣

          • 為什么會有類似的情況出現(xiàn)?
          • 出現(xiàn)之后是否有處理?
          • 怎么才能避免類似的事再次出現(xiàn)?

          關(guān)于治理

          已定義未使用的代碼

          如果你的項目代碼在百萬級以下,推薦你使用AppCode來靜態(tài)檢查無用代碼,如果超過了百萬的團(tuán)隊,一般會自己通過Clang靜態(tài)分析來開發(fā)工具,去檢查無用的代碼和類

          使用AppCode做分析很簡單,直接使用AppCode打開你需要檢查的工程,等待索引建立完成,點(diǎn)擊頂部菜單的Code-Inspect Code

          然后選擇掃描范圍,默認(rèn)是整個工程,可以自定義

          然后等待靜態(tài)分析完成即可,完成之后就會控制臺顯示Unused code的提示

          下面說下無用代碼的類型

          內(nèi)容中文翻譯
          Unused class無用類
          Unused global declaration無用的全局聲明
          Unused import statement無用的類引入聲明
          Unsed instance variable無用的實(shí)例變量
          Unused local variable無用的局部變量
          Unused macro無用的宏
          Unused method無用的方法
          Unused parameter無用的參數(shù)
          Unused property無用的屬性
          Unused value無用的值

          雖然AppCode完成了大部分的工作,但是還是有一些問題存在,下面是我測試總結(jié)的問題

          • JSONModel定義了未使用協(xié)議會被判定為無用協(xié)議
          • 如果子類使用了父類的方法,父類的這個方法會判斷為未使用
          • 通過點(diǎn)語法使用屬性,該屬性會被認(rèn)為未使用
          • 使用performSelector方式調(diào)用的方法檢查不出來,比如[self performSelector:@selector(fetchPhotos:)],會認(rèn)為fetchPhotos:是未使用
          • 運(yùn)行時聲明的類也檢查不出來,比如通過NSClassFromString方式調(diào)用的類會被查出未使用
          id?someClass?=?NSClassFromString(@"SomeClass");
          //?or
          [[self?class]?getPhotos];

          基于上述的原因,我們需要人工二次確認(rèn)才能夠安全刪除代碼,雖然繁瑣,但是很安全。

          已廢棄業(yè)務(wù),代碼還在

          定期對業(yè)務(wù)流程進(jìn)行梳理,結(jié)合綜合業(yè)務(wù)數(shù)據(jù)的埋點(diǎn),同產(chǎn)品和廣告確認(rèn)功能是否已經(jīng)下線,從而決定是否移除對應(yīng)的業(yè)務(wù)模塊

          已引入未使用的圖片

          這里我測試使用的是LSUnusedResources(https://github.com/tinymind/LSUnusedResources),針對使用編號規(guī)則的圖片來說,可以直接添加規(guī)則來處理,使用也很簡單;建議在刪除前在項目中進(jìn)行二次全局搜索確認(rèn),是否確實(shí)沒有使用

          某些重復(fù)資源的導(dǎo)入

          重復(fù)資源分為靜態(tài)庫和項目文件

          針對靜態(tài)庫,有多個相似功能進(jìn)行需求整合,把最優(yōu)解決方案的靜態(tài)庫留下,其余的跟相關(guān)產(chǎn)品和廣告人員進(jìn)行移除確認(rèn),比如線上崩潰采集聽云、buglymatrix

          針對項目文件,可以使用fdupes工具進(jìn)行重復(fù)文件掃描,該工具的原理是通過校驗所有的資源的MD5值,篩選出項目中重復(fù)的資源,文件比較順序是

          • 文件大小 > 部分MD5簽名對比 > 完整MD5簽名對比 > 逐字節(jié)對比

          fdupes的安裝和使用

          #?Searches?the?given?path?for?duplicate?files.?Such?files?are?found?by
          #?comparing?file?sizes?and?MD5?signatures,?followed?by?a?byte-by-byte?comparison.

          #?install?fdupes
          $?brew?install?fdupes

          #?where?xxx?is?the?directory?to?be?scanned,?and?xxxFdupesResult.txt?is?the?output?file?of?the?scan?result
          $?fdupes?-Sr?/User/augus/Documents/xxx?>?/User/augus/Documents/xxxFdupesResult.txt
          已用資源的優(yōu)化

          已用資源的優(yōu)化主要是就是圖片、網(wǎng)頁、json、音頻文件的壓縮

          網(wǎng)頁的壓縮,是放入App資源中的js或者html文件,最好是經(jīng)過?H5端壓縮后的

          json文件的壓縮,如果不是即時使用的,可以放倒云端或者后臺,進(jìn)行網(wǎng)絡(luò)獲取后使用

          音頻的壓縮,需要跟產(chǎn)品和廣告進(jìn)行溝通,在可接受范圍內(nèi),選擇系統(tǒng)可支持的壓縮比最高的格式

          最后說圖片的壓縮,分為以下幾個部分

          • 如果圖片小于100KB則使用TinyPng進(jìn)行再一步壓縮,使用TinyPng壓縮三次即可達(dá)到極限值;這里推薦一個TinyPng的多圖壓縮的腳本(https://github.com/mokong/BatchProcessImage),因為在線最多一次最多20張,原理就是封裝了官方的一個壓縮接口,通過一個郵箱注冊一個key,然后每個key就是500次/月。

          • 將圖片放入xcassets,因為xcassets里的@2x@3x圖片,在上傳時,會根據(jù)具體設(shè)備分開對應(yīng)分辨率的圖片,不會同時包含。而放入.bundle中的都會包含,所以要盡量把圖片放入xcassets中。Assets.car編譯過程中有時會選擇一些圖片,拼湊成一張大圖來提高圖片的加載效率。被放進(jìn)這張大圖的小圖會變?yōu)橥ㄟ^偏移量的引用,建議使用頻率高且小的圖片放到xcassets中,xcassets能保證加載和渲染速度最優(yōu)。

          • 大于100KB就不要放入xcassets中了。大的圖片可以考慮將圖片轉(zhuǎn)成WebP。WebP是Google公司的一個開源項目,能夠把圖片壓縮到很小,但是肉眼看不出來差別,目前iOS常用的圖片顯示類庫都支持該格式解析的拓展。可使用鵝廠的一個工具iSparta(http://isparta.github.io/)進(jìn)行批量轉(zhuǎn)換。

          WebP在CPU消耗和解碼時間上會比PNG高2倍,所以我們要在性能和體積上做取舍

          監(jiān)控機(jī)制

          優(yōu)化完成之后,如何保證包大小不會再次迅速增大?或者如何迅速定位增大原因,就需要依賴一套合適的監(jiān)控機(jī)制和合理的流程規(guī)范來保證。

          監(jiān)控機(jī)制保證實(shí)時發(fā)現(xiàn)問題,每次打包完成后,運(yùn)行腳本比較包大小差異,如果有增大超過了設(shè)置的閾值,則郵件通知相關(guān)負(fù)責(zé)人,負(fù)責(zé)人排查原因,同時做好記錄;每次打包的包大小進(jìn)行文檔記錄,造成包大小變化的原因記錄

          流程規(guī)范是用于保證每個項目開發(fā)者在開發(fā)中有良好的開發(fā)習(xí)慣,避免包大小突然增大,而一無所知

          • 引入新的第三方庫,要考慮項目中是否有相同類型的,是否可以自己實(shí)現(xiàn),是否會造成體積增大
          • 新增圖片資源,關(guān)注大小,是否能用代碼實(shí)現(xiàn),進(jìn)行適當(dāng)壓縮
          • 及時清理廢棄模塊
          • 每次打包關(guān)注包大小變化,文檔記錄,持續(xù)跟蹤

          結(jié)束語

          包大小不是一時可以完成,需要平時每個相關(guān)人都去注意,有了良好的開發(fā)規(guī)范,開發(fā)流程就能持續(xù)進(jìn)行改進(jìn),從而達(dá)到一個平衡穩(wěn)定狀態(tài)。

          參考文檔

          • Build Setting Reference https://help.apple.com/xcode/mac/11.4/#/itcaec37c2a6
          • 包體積大小:瘦身 https://www.zybuluo.com/qidiandasheng/note/1662385)
          • 抖音品質(zhì)建設(shè) - iOS 安裝包大小優(yōu)化實(shí)踐篇 https://blog.csdn.net/ByteDanceTech/article/details/112504772

          -End-

          最近有一些小伙伴,讓我?guī)兔φ乙恍?面試題?資料,于是我翻遍了收藏的 5T 資料后,匯總整理出來,可以說是程序員面試必備!所有資料都整理到網(wǎng)盤了,歡迎下載!

          點(diǎn)擊??卡片,關(guān)注后回復(fù)【面試題】即可獲取

          在看點(diǎn)這里好文分享給更多人↓↓

          瀏覽 76
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  囯产精品无码成人久久久 | 福利综合网 | 热亚洲热中文热日韩 | 韩国一区二区三区精品 | 亚洲超碰成人在线 |