背景
移動(dòng)開發(fā)中,對于包大小優(yōu)化是項(xiàng)目開發(fā)中需要考慮的蔬螟,尤其對于航母級App此迅,比如QQ、手淘等旧巾。網(wǎng)上關(guān)于包大小優(yōu)化的文章很多耸序,每篇文章說的都不盡相同,因此想根據(jù)已有的文章鲁猩、知識結(jié)合自己的理解坎怪、實(shí)踐,做一份梳理廓握。整理自己的包大小優(yōu)化邏輯搅窿,不光要知道怎么做可以讓包大小變化,還要知道為什么這么做能產(chǎn)生效果隙券。
分析
想要優(yōu)化安裝包大小男应,首先需要弄清楚影響安裝包大小的因素有哪些?在做這件事之前要先思考娱仔、分析沐飘、最后再去做,針對安裝包大小拟枚,首先分析影響安裝包大小的因素薪铜,有:Xcode的設(shè)置、資源恩溅、代碼三個(gè)方面隔箍。那針對這三個(gè)方面要如何優(yōu)化?又如何查看每一步優(yōu)化的結(jié)果脚乡?
首先是怎么優(yōu)化的問題:
Xcode的編譯設(shè)置優(yōu)化蜒滩,Xcode設(shè)置影響的是生成包的大小滨达,通過Xcode編譯選項(xiàng)優(yōu)化的設(shè)置,讓生成的ipa包變小俯艰,比如不含斷點(diǎn)調(diào)試捡遍、去掉異常支持等等。
資源文件的優(yōu)化竹握,資源不光有圖片資源画株,也包含代碼資源和其它導(dǎo)入的資源,可以通過分析安裝包構(gòu)成啦辐,看里面哪些部分比較大谓传、不合理,從而進(jìn)行優(yōu)化芹关。
代碼的優(yōu)化续挟,通過Link Map生成Link Map File,在編譯時(shí)開啟Xcode Build Settings中的Write Link Map File開關(guān)侥衬,Xcode就會(huì)生成一份Link Map File, 分析Link Map File各文件占用诗祸,結(jié)合iOS 上的可執(zhí)行文件 (Mach-O文件)進(jìn)行分析優(yōu)化。
Link Map File 分為三部分:Object Files轴总、Sections 和 Symbols直颅。
· Object Files 包含了代碼工程的所有文件;
· Sections 描述了代碼段在生成的Mach-O里的偏移位置和大兄庀啊际乘;
· Symbols 會(huì)列出每個(gè)方法、類漂佩、block,以及它們的大小罪塔。
然后是怎么查看每一步優(yōu)化的結(jié)果的問題:
查看每一步的優(yōu)化結(jié)果投蝉,可以通過分析打包出來的ipa的大小以及ipa的組成與初始的ipa包大小比較,即可直觀得到優(yōu)化的結(jié)果征堪。但可以更進(jìn)一步分析ipa的構(gòu)成瘩缆,對比優(yōu)化后的構(gòu)成,看每一步的操作具體影響的是包的哪一塊兒佃蚜,從而導(dǎo)致包的大小發(fā)生了變化庸娱。所以先來看一下一個(gè)ipa包含哪些內(nèi)容,然后每一步優(yōu)化之后谐算,對應(yīng)ipa的哪一部分發(fā)生了變化熟尉。
安裝包的構(gòu)成
iOS打包出來的ipa本質(zhì)上是一個(gè)壓縮包,所以可以將.ipa的后綴改為.zip洲脂,然后進(jìn)行解壓縮斤儿,之后會(huì)得到一個(gè)Payload文件夾,里面又一個(gè)xxx.app的文件,這個(gè)xxx.app就是包含所有文件的包了往果,選中xxx.app疆液,右鍵顯示包內(nèi)容,我們就可以直觀地看到安裝包中的內(nèi)容了陕贮,大致如下:
了解了ipa包的組成之后堕油,我們再回過頭來,按照Xcode的編譯優(yōu)化肮之、資源文件優(yōu)化掉缺、代碼優(yōu)化的步驟來一步步分析。
Xcode編譯設(shè)置
一般這一步容易被人忽略局骤,因?yàn)樘岬絻?yōu)化最先能想到的就是資源優(yōu)化攀圈,比如圖片壓縮、無用代碼刪除等等峦甩,而對于Xcode自身的編譯優(yōu)化提及的反而不多赘来。而且由于網(wǎng)上提供的參考針對每個(gè)項(xiàng)目可能結(jié)果都不一樣,有些編譯選項(xiàng)的設(shè)置是需要針與實(shí)際項(xiàng)目結(jié)合起來才可以凯傲,所以這里整理如下:
Xcode編譯優(yōu)化相關(guān):
1.Build Settings中去掉異常支持犬辰,Enable C++ Exceptions和Enable Objective-C Exceptions設(shè)置為NO,Other C Flags添加-fno-exceptions冰单;
注意:Enable C++ Excptions和Enable Objective-C Exceptions是指項(xiàng)目支持對錯(cuò)誤的異常處理幌缝,比如try catch、throw之類的诫欠;所以如果項(xiàng)目中使用的有類似的異常處理的涵卵,這個(gè)關(guān)閉了之后會(huì)報(bào)錯(cuò)(Cannot use '@try' with Objective-C exceptions disabled)。包括宏定義中使用的有try{}荒叼、@finally{}之類的轿偎,比如@strongify等,如果關(guān)閉了最后打包的時(shí)候也會(huì)報(bào)錯(cuò)被廓。
-fno-exceptions的意思是禁用異常機(jī)制坏晦,參考GCC如下圖,同樣當(dāng)項(xiàng)目中有try throw的時(shí)候嫁乘,就不要設(shè)置這個(gè)選項(xiàng)為NO
2.Build Settings -> Architectures昆婿,Release下設(shè)置為arm64
Architectures指定工程被編譯成可支持哪些指令集類型,支持的指令集越多蜓斧,就會(huì)編譯出多個(gè)指令集代碼的數(shù)據(jù)包仓蛆,ipa包就會(huì)變大。默認(rèn)的參數(shù)standard architectures(armv7,arm64) 法精,打的包里面有32位多律、64位兩份指令集痴突。如果不需要32位的,可以在other中更改支持的指令集狼荞,從而使ipa包變小辽装。
還有另外一種設(shè)置方法,Architectures不修改相味,Excluded Architectures中設(shè)置Release模式下?Any iOS SDK?-> armv7拾积,也可以實(shí)現(xiàn)同樣的效果。設(shè)置了之后丰涉,就是Release下把a(bǔ)rmv7的指令集排除在外拓巧。選中target會(huì)發(fā)現(xiàn)默認(rèn)設(shè)置了?Any iOS Simulator SDK?-> arm64,意思是模擬器的時(shí)候排除arm64指令集一死。
3.Build Settings -> Generate Debug Symbols設(shè)置為NO
Generate Debug Symbols的意思是生成調(diào)試符號肛度,當(dāng)這個(gè)選項(xiàng)設(shè)置為YES時(shí),每個(gè)源文件在編譯成.o文件時(shí)投慈,編譯參數(shù)多了-g和-gmodule承耿,意思是generate complete debug info,所以產(chǎn)生的.o文件會(huì)大伪煤,從而最終生成的可執(zhí)行文件也就會(huì)變大加袋。
注意Generate Debug Symbols設(shè)置為NO時(shí),在Xcode中設(shè)置的斷點(diǎn)不會(huì)中斷抱既,即不能斷點(diǎn)調(diào)試职烧。且最后不能生成dSYM文件,即使Debug Information Format設(shè)置了防泵,也不能生成蚀之,因?yàn)槭紫纫姓{(diào)試信息然后才能生成dSYM文件,而設(shè)置為NO捷泞,意味著不產(chǎn)生調(diào)試信息恬总,所以也就沒辦法生成dSYM文件。所以建議不要設(shè)置肚邢。
4.Build Settings -> Deployment Postprocessing,Debug模式下設(shè)置NO拭卿,Release下設(shè)為YES
Deployment Postprocessing是Strip配置的總開關(guān)骡湖,只有這個(gè)設(shè)置為YES之后,下面的Strip Linked Product峻厚、Strip Debug Symbols During Copy的設(shè)置才會(huì)生效响蕴。
a.Build Settings -> Strip Linked Product,Debug下設(shè)置為NO惠桃,Release下設(shè)置為YES
對最后生成的二進(jìn)制文件進(jìn)行strip浦夷,去除不必要的符號信息辖试,Release下可以為YES。注意劈狐,如果Deployment Postprocessing不打開罐孝,該選項(xiàng)沒有作用。去除了符號信息之后需要使用dSYM來進(jìn)行符號化肥缔,所以需要將 Debug Information Format 修改為DWARF with dSYM file(Release下)莲兢,如果在Debug下設(shè)置為DWARF with dSYM file那么在崩潰時(shí)將無法看到堆棧信息。
b.Build Settings -> Strip Debug Symbols During Copy续膳,Debug下設(shè)置為NO改艇,Release下設(shè)置為YES
文件拷貝編譯階段是否進(jìn)行strip,設(shè)置為YES之后坟岔,會(huì)把拷貝進(jìn)項(xiàng)目包的三方庫谒兄、資源或者Extension的Debug Symbol去除。同樣社付,如果Deployment Postprocessing不打開承疲,該選項(xiàng)沒有作用
c.Build Settings -> Symbols Hidden by Default,Debug模式下設(shè)置為NO瘦穆,Release下設(shè)置為YES
Symbols Hidden by Default會(huì)把所有符號都定義成"private extern"纪隙,移除符號信息。
5.Build Settings -> Make Strings Read-Only設(shè)置為YES
官方解釋:Make Strings Read-Only (GCC_REUSE_STRINGS), Reuse string literals. 就是復(fù)用字符串字面量扛或,提到復(fù)用绵咱,顧名思義就是減少生成不必要的,也是優(yōu)化的一種形式熙兔。
6.Build Settings -> Dead Code Stripping設(shè)置為YES
消除無效代碼悲伶,C/C++/Swift 等靜態(tài)語言編譯器會(huì)在 link 的時(shí)候移除未使用的代碼,對于OC等動(dòng)態(tài)語言是無效的住涉。
7.Asset Catalog Compiler編譯設(shè)置優(yōu)化麸锉,Build Settings -> Asset Catalog Compiler - Options 中Optimization改為space。
這個(gè)選項(xiàng)可以改變actool(compile asset catalog這個(gè)過程使用的工具舆声,內(nèi)置在Xcode里的)在構(gòu)建Assets.car時(shí)會(huì)按照一定策略選取編碼算法花沉,對其中的 png 圖片重新編碼, 從而減少包大小媳握。Assets.xcassets 壓縮格式對最終ipa包下assets.car文件大小的影響還是比較大的碱屁。但需要注意的是,cocoapods管理庫中的asset catalog的編譯過程在cocoapods生成的[CP] Copy Pods Resources這個(gè)腳本中蛾找,故上面的設(shè)置對Pod庫組件是無效的娩脾。壓縮策略有如下幾種:
8.Build Settings -> Optimization Level改為-Oz
Optimization Level默認(rèn)為-Os,-Oz是Xcode 11之后才出現(xiàn)的編譯優(yōu)化選項(xiàng)打毛,核心原理是對重復(fù)的連續(xù)機(jī)器指令外聯(lián)成函數(shù)進(jìn)行復(fù)用柿赊,因此開啟Oz俩功,能減少二進(jìn)制的大小,但同時(shí)會(huì)帶來執(zhí)行效率但額外消耗碰声」铗眩可參考What's New in Clang and LLVM
在What's New in Clang and LLVM的Presentation Slides中,蘋果給出了Optimization Level各參數(shù)優(yōu)化的選擇對比奥邮,如下圖万牺,對于性能要求高的拾枣,建議選擇-O2和-O3该互,對于包大小敏感的婚瓜,可選擇-Os和-Oz票唆,默認(rèn)-Os是性能和大小平衡比較好的希太。最終選擇什么侥祭,需要開發(fā)者根據(jù)自己實(shí)際項(xiàng)目而定平痰。
Optimization Level各參數(shù)對比:
Xcode編譯設(shè)置優(yōu)化總結(jié)如下:
資源文件優(yōu)化
資源文件的優(yōu)化款违,通常來說是比較簡單的藕坯,但是資源文件的優(yōu)化是需要持續(xù)進(jìn)行的团南,前面介紹的Xcode編譯設(shè)置優(yōu)化,配置好了之后炼彪,后續(xù)開發(fā)過程中只要不修改配置吐根,都無需重復(fù)關(guān)注。但資源文件不同辐马,隨著項(xiàng)目的迭代拷橘,會(huì)不斷引入新的資源文件,不斷有廢棄資源的產(chǎn)生喜爷,所以資源文件的優(yōu)化是要持續(xù)進(jìn)行的冗疮。
資源文件的優(yōu)化分為兩部分,即:無用資源的刪除檩帐、已用資源的壓縮术幔。在這里建議分先后順序,即先做刪除再做壓縮湃密,因?yàn)槿绻葔嚎s了诅挑,結(jié)果發(fā)現(xiàn)是無用資源,就白白浪費(fèi)了力氣泛源。
無用資源的刪除:
· 已定義未使用的代碼文件
· 已廢棄業(yè)務(wù)揍障,代碼還在
· 已引用的圖片但未使用
· 某些重復(fù)資源導(dǎo)入
已用資源的壓縮:
·項(xiàng)目中引入圖片、網(wǎng)頁俩由、json、音頻等文件的壓縮
無用資源的刪除
隨著項(xiàng)目的迭代癌蚁,每個(gè)項(xiàng)目都會(huì)或多或少存在冗余幻梯《祷可能是開發(fā)了的功能未上線但產(chǎn)品讓保留,保留著保留著就忘記了碘梢;可能是已下線的業(yè)務(wù)咬摇,沒人通知到開發(fā),于是代碼邏輯一直都在煞躬;可能是刪除某些業(yè)務(wù)代碼時(shí)肛鹏,對應(yīng)的圖片資源未刪除;又或者是每個(gè)開發(fā)恩沛,導(dǎo)入各自熟悉的第三方庫使用在扰。
已定義未使用的代碼
可使用AppCode進(jìn)行分析,打開AppCode雷客,待索引完成后芒珠,選擇頂部菜單中的Code->Inspect Code,然后選擇范圍搅裙,whole Project點(diǎn)擊OK皱卓,等待AppCode靜態(tài)分析即可。靜態(tài)分析完以后部逮,可以在Unused code里看到所有的無用代碼
AppCode中無用代碼靜態(tài)分析的類型有以下幾種:
AppCode靜態(tài)分析結(jié)果出來之后娜汁,刪除前要經(jīng)過確認(rèn),因?yàn)殪o態(tài)分析的結(jié)果可能會(huì)有誤差兄朋,比如針對performSelector調(diào)用的方法就會(huì)被檢測為沒有調(diào)用掐禁。
當(dāng)然也可以不利用AppCode,比如通過技術(shù)手段分析Mach-O文件 :
Mach-O文件中有__DATA.__objc_classrefs和__DATA.__objc_selrefs段蜈漓,分別近似于“被使用的類的集合”和“被使用的方法的集合”穆桂。通過取差集的方式可以篩選出未被使用的類和方法。
1. 排查無用類
使用otool命令可查看__DATA.__objc_classrefs段和__DATA.__objc_classlist段融虽,兩者的差集可以認(rèn)為是定義了但未使用的類享完。
不過__DATA.__objc_classrefs段和__DATA.__objc_classlist段中都只提供了類在二進(jìn)制文件中的位置地址,而沒有提供類名等可讀信息有额。所以在獲取到差集后般又,還需要結(jié)合下面這個(gè)命令的輸出,將地址轉(zhuǎn)換成可讀的類名巍佑。
使用腳本篩選出差集對應(yīng)的類后茴迁,還需要進(jìn)行一遍人工梳理,因?yàn)閯?dòng)態(tài)使用的類萤衰、從nib或storyboard初始化的類以及在同一個(gè)文件中定義的多個(gè)類會(huì)被誤判為未使用的類堕义。
2.?排查無用方法
所有已經(jīng)被實(shí)現(xiàn)的方法可以通過linkmap來獲取,對linkmap做grep操作即可獲得結(jié)果:
而所有已經(jīng)被使用的方法可以通過對二進(jìn)制文件逆向獲得脆栋。使用otool工具逆向二進(jìn)制文件的__DATA.__objc_selrefs?段倦卖,提取可執(zhí)行文件里引用到的方法名:
使用這種方法取到的差集洒擦,還需要排除掉系統(tǒng)API中的protocol,accessor方法等怕膛。
已廢棄業(yè)務(wù)熟嫩,代碼還在
需要梳理業(yè)務(wù)流程,結(jié)合線上業(yè)務(wù)數(shù)據(jù)點(diǎn)擊量褐捻,同產(chǎn)品和業(yè)務(wù)確認(rèn)對應(yīng)功能是否下線掸茅,從而決定是否移除對應(yīng)的業(yè)務(wù)模塊代碼。
已引入未使用圖片
推薦使用工具LSUnusedResources柠逞,原理大致是遍歷資源目錄下后綴 ["imageset", "jpg", "png"...] 的文件昧狮,然后在源文件 ["m", "swift", "xib", "storyboard"...] 中字符串匹配,無匹配則是無用的資源文件边苹。
使用時(shí)注意勾選Ignore similar name陵且,然后點(diǎn)擊右上角的Browse選中要掃描的項(xiàng)目地址,點(diǎn)擊右下角的search个束,就會(huì)開始掃描慕购,結(jié)果會(huì)在底部Unused Results中展示出來,然后CMD+A全選茬底,export沪悲,導(dǎo)出到一個(gè)文本文件中。也可以在對應(yīng)單條Item上面雙擊阱表,會(huì)打開對應(yīng)的文件夾殿如。建議刪除前在項(xiàng)目中搜索確認(rèn),是否確實(shí)沒有使用(類似字符串中間替換的可能會(huì)被掃描出來最爬,所以刪除前需要確認(rèn))
某些重復(fù)資源的導(dǎo)入
重復(fù)資源的導(dǎo)入涉馁,分為兩個(gè)方面,一方面是針對第三方SDK爱致,另一方面是項(xiàng)目文件烤送。
1.針對第三方SDK
項(xiàng)目中功能類似的SDK建議保留一個(gè),建議分析相同功能的類庫糠悯,結(jié)合實(shí)際情況帮坚,保留一個(gè)即可;另外互艾,有些第三方類庫導(dǎo)入時(shí)试和,可只導(dǎo)入實(shí)際使用的部分,不需全量導(dǎo)入纫普,比如百度地圖阅悍,定位和地圖分開的,開發(fā)者根據(jù)需求來選擇需要導(dǎo)入哪些。
2.針對項(xiàng)目文件
使用 fdupes 工具進(jìn)行重復(fù)文件掃描溉箕,原理是:通過校驗(yàn)所有資源的 MD5晦墙,篩選出項(xiàng)目中的重復(fù)資源。這里還要說下cocoapods帶來的圖片重復(fù)合并問題肴茄,也屬于這個(gè)范疇。現(xiàn)如今好多大的App都實(shí)行組件化但指,重度使用cocoapods進(jìn)行庫管理寡痰,越來越多的代碼被封裝成了pod庫,以庫的形式集成進(jìn)工程中棋凳。在檢查安裝包內(nèi)容時(shí)拦坠,看下.app文件的最外層的零散資源文件和pod庫的asset catalog里的資源文件重復(fù)了。因?yàn)槿绻鹥od庫在編寫podspec的時(shí)候剩岳,可能用了這樣的語句指定資源文件:
podspec中這樣書寫贞滨,會(huì)導(dǎo)致asset catalog中的圖片,既作為asset catalog被合并到主工程的asset.car中拍棕,也會(huì)作為png被拷貝到安裝包中晓铆。導(dǎo)致其中一套圖片白白占用了安裝包空間。應(yīng)該以白名單的形式明確指定哪些資源文件是pod庫中有效的資源文件绰播。
已用資源的壓縮
項(xiàng)目中引入圖片骄噪、網(wǎng)頁、json蠢箩、音頻等文件的壓縮链蕊,網(wǎng)頁的壓縮指的是,放入App資源中的js文件谬泌,最好是經(jīng)過H5端壓縮后的滔韵。json文件的壓縮,如果不是打開App時(shí)馬上要用到的數(shù)據(jù)掌实,可采取把對應(yīng)資源放到服務(wù)端陪蜻,下載后使用。音頻文件的壓縮潮峦,則是在可接受的范圍之內(nèi)囱皿,選擇系統(tǒng)可支持的壓縮比率高的格式。而最需要注意的是圖片的壓縮忱嘹,圖片的壓縮嘱腥,分為幾個(gè)部分
1.Compress PNG Files?打包的時(shí)候自動(dòng)對圖片進(jìn)行無損壓縮,注意:這個(gè)選項(xiàng)對asset catalog中的資源是無效的拘悦,因?yàn)檫@個(gè)選項(xiàng)僅適用于零散資源文件齿兔。
2.?Remove Text Medadata From PNG Files??移除 PNG 資源的文本字符
3.針對普通圖片,可以調(diào)用tinyPNG API進(jìn)行壓縮?
4.放入xcassets里的2x和3x圖片,在上傳時(shí)分苇,會(huì)根據(jù)具體設(shè)備分開對應(yīng)分辨率的圖片添诉,不會(huì)同時(shí)包含。而放入Bundle中的都會(huì)包含医寿。所以要盡量把圖片放入xcassets中栏赴。使用頻率高且小的圖片放到Asset.car中,Asset.car能保證加載和渲染速度最優(yōu)靖秩。但是大的圖片(大于100K)就不要放入Asset.car中了须眷。大的圖片可以考慮將圖片轉(zhuǎn)成WebP。
5. 將PNG 格式轉(zhuǎn) WebP沟突,WebP 壓縮率高花颗,而且肉眼看不出差異,同時(shí)支持有損和無損兩種壓縮模式惠拭。有損壓縮模式下可減少 64% 大小扩劝,無損壓縮模式下可減少 19% 大小,可使用iSparta進(jìn)行批量轉(zhuǎn)換职辅。注意:WebP在 CPU 消耗和解碼時(shí)間上會(huì)比 PNG 高兩倍棒呛,所以適合小圖。
6.Pod庫中的資源文件,推薦使用resource_bundles配合xcassets的方式來集成各個(gè)插件中的資源文件,即xcassets需要添加到podspec的resource_bundles中罐农,Pod庫中的代碼在讀取圖片資源時(shí)条霜,使用imageNamed:inBundle:compatibleWithTraitCollection:讀取,而不是imageNamed:讀取涵亏。但如果pod中有資源文件沒有用xcassets宰睡,那這些資源文件必須放入resource_bundles中,禁止放入resource中气筋;(resource_bundle中的資源在構(gòu)建期能經(jīng)過Xcode的優(yōu)化拆内,而resource中的資源不能)
這樣做的優(yōu)點(diǎn)有:
(1)各個(gè)pod管理各自的資源文件,不會(huì)有命名沖突的問題
(2)能利用蘋果的app slicing功能 宠默,下面我會(huì)講這個(gè)
資源文件優(yōu)化總結(jié)如下:
延伸一個(gè)知識點(diǎn)麸恍,蘋果官方的app slicing ,在以上一系列優(yōu)化過程中,我們僅僅關(guān)注了內(nèi)部平臺(tái)構(gòu)建出的安裝包的包大小搀矫,而忽視了apple已經(jīng)為我們提供了官方的解決方案抹沪。app slicing是iOS9增加的功能。當(dāng)用戶從app store上下載app時(shí)瓤球,可以只下載適用于其設(shè)備的app架構(gòu)版本和所需資源(如2x和3x設(shè)備)融欧,從而減少app所占的空間。如果開發(fā)者想要使用app slicing卦羡,只需要將資源文件用Asset Catalog管理噪馏,不需要做額外的任何事情麦到。所以一頓操作發(fā)現(xiàn),蘋果已經(jīng)為開發(fā)者尋求到了一個(gè)較優(yōu)的解決方案欠肾。
寫在最后
瘦身完成之后瓶颠,如何保證包大小不會(huì)再次迅速增大?就需要依賴適當(dāng)?shù)谋O(jiān)控機(jī)制和合理的流程規(guī)范來控制刺桃。
監(jiān)控機(jī)制保證實(shí)時(shí)發(fā)現(xiàn)問題粹淋,每次打包完成后比較包大小差異
流程規(guī)范是用于保證每個(gè)項(xiàng)目開發(fā)者知曉開發(fā)中注意什么,養(yǎng)成好的開發(fā)習(xí)慣瑟慈,避免造成包大小的突然變大廓啊。如:
1.引入新的三方庫時(shí),要考慮是否已有同類型的庫封豪,是否可以自己實(shí)現(xiàn),是否會(huì)造成體積增大炒瘟。盡量避免Objective-C和Swift混編吹埠,優(yōu)先引用相同語言類型的庫;
2.新增的圖片資源疮装,關(guān)注大小缘琅,是否能代碼實(shí)現(xiàn),注意放入項(xiàng)目的位置廓推,如果體積太大刷袍,壓縮后使用;
3.廢棄模塊或者業(yè)務(wù)代碼不要保留樊展,及時(shí)清理呻纹。畢竟git有記錄;
4.?及時(shí)關(guān)注包大小變化.
引用
1.深入探索 iOS 包體積優(yōu)化
2.今日頭條 iOS 安裝包大小優(yōu)化—— 新階段专缠、新實(shí)踐