袁宜霞
關(guān)鍵詞:軟件安裝包;可執(zhí)行文件;編譯優(yōu)化
0 引言
隨著移動(dòng)應(yīng)用市場(chǎng)競(jìng)爭(zhēng)越來(lái)越激烈,精細(xì)化運(yùn)營(yíng)顯得越來(lái)越重要,手機(jī)軟件安裝包的大小不僅影響用戶(hù)下載意愿和用戶(hù)體驗(yàn),也會(huì)影響渠道分發(fā)和推廣成本甚至關(guān)系著研發(fā)維護(hù)成本,安裝包過(guò)大會(huì)帶來(lái)很多弊端。首先,用戶(hù)花費(fèi)流量來(lái)進(jìn)行下載意愿降低;包體的下載過(guò)程越長(zhǎng),用戶(hù)主動(dòng)取消下載可能性越大,網(wǎng)絡(luò)不暢或者空間不足帶來(lái)的下載中斷概率增大;在手機(jī)空間不足導(dǎo)致用戶(hù)需要清理空間時(shí),包體越大的軟件被清理的可能性越大。其次,在軟件分發(fā)渠道,有些廠商會(huì)限制用戶(hù)使用蜂窩網(wǎng)絡(luò)下載包體過(guò)大安裝包,或者大幅提高安裝包大的軟件分發(fā)費(fèi)用;買(mǎi)量推廣的成本增大而用戶(hù)轉(zhuǎn)換率降低。最后,安裝包越大意味著代碼和資源越多,研發(fā)團(tuán)隊(duì)需要更高的學(xué)習(xí)和維護(hù)成本,也更容易出錯(cuò)。
本文以iOS安裝包為例,制定了一套安裝包縮減的整體方案并詳細(xì)闡述了原理與具體實(shí)現(xiàn)。
1 iOS 軟件安裝包分析
iOS軟件安裝包為IPA格式,此格式文件本質(zhì)是一種壓縮包,解壓縮后可以看到文件夾中含有一個(gè)Pay? load目錄。此目錄下包含了與IPA包同名的可執(zhí)行文件,資源文件、配置文件和lproj目錄。其中,可執(zhí)行文件是安裝包的核心部分,文件大小占據(jù)整個(gè)安裝包的較大比例,是逆向工程的重要目標(biāo)。資源文件主要包括圖片、視頻、音頻等,這類(lèi)文件數(shù)量較多。lproj目錄包含各種本地化的字符串,為逆向工程提供重要線索[1]。
2 iOS 軟件安裝包縮減方案與實(shí)現(xiàn)
本文將從可執(zhí)行文件、資源優(yōu)化、產(chǎn)品功能優(yōu)化、編譯優(yōu)化和符號(hào)信息設(shè)置幾個(gè)方面來(lái)進(jìn)行安裝包縮減方案的制定與實(shí)現(xiàn)。
2.1 可執(zhí)行文件優(yōu)化與監(jiān)控方案
在iOS中可執(zhí)行文件的格式是Mach-O,LinkMap文件是集成開(kāi)發(fā)工具Xcode生成可執(zhí)行文件時(shí)同步產(chǎn)生的鏈接信息,記錄了可執(zhí)行文件的各個(gè)組成部分,包括代碼段和數(shù)據(jù)段的分布情況。開(kāi)發(fā)者需要在Xcode中打開(kāi)Write Link Map File選項(xiàng)并編譯后才能獲得LinkMap文件。LinkMap文件有三個(gè)部分,分別是:Object files列舉了可執(zhí)行文件里所有.o文件,以及每個(gè)文件的編號(hào);Sections是可執(zhí)行文件的段表,列舉了各個(gè)段在可執(zhí)行文件中的偏移位置和大小,包括代碼段和數(shù)據(jù)段;Symbols詳細(xì)存儲(chǔ)了每個(gè)文件中的各個(gè)字段位置和大小[2]。otool是Xcode自帶的Object file 展示工具,常用于逆向工程。
1) 刪除無(wú)用的類(lèi)
由于iOS編程語(yǔ)言O(shè)bjective-C的動(dòng)態(tài)特性,它使用類(lèi)名和方法名對(duì)這個(gè)類(lèi)和方法進(jìn)行調(diào)用,所以編譯器將項(xiàng)目中全部OC源文件編譯到可執(zhí)行文件,不論該類(lèi)和方法是否被使用。在代碼中通過(guò)手動(dòng)搜索al? loc、new、ClassName *等關(guān)鍵字代碼逐個(gè)排查所有類(lèi)是否被使用的方法無(wú)疑是成本巨大且難以實(shí)施的。如下將詳細(xì)描述一個(gè)能自動(dòng)化實(shí)現(xiàn)查找無(wú)用類(lèi)的方案,通過(guò)下述方案獲得所有無(wú)用類(lèi)的類(lèi)名,并刪除這些無(wú)用類(lèi)的代碼能帶來(lái)可執(zhí)行文件大小的縮減。
Xcode自帶的Analyze靜態(tài)分析工具能查找出一些沒(méi)有使用過(guò)的第三方庫(kù),通過(guò)清除這類(lèi)第三方庫(kù)實(shí)現(xiàn)壓縮安裝包的目的。開(kāi)發(fā)時(shí)盡量減少第三方庫(kù)的引入,如果避免不了優(yōu)先選擇精簡(jiǎn)庫(kù),在LinkMap中可以看到第三方庫(kù)所占的包大小,可以作為是否引入該庫(kù)的評(píng)估依據(jù)。具體方法為:通過(guò)LinkMap中Ob? ject files 部分查看某個(gè)文件編號(hào),再通過(guò)此編號(hào)在Symbols部分查看這個(gè)文件的每個(gè)段所占用大小并進(jìn)行累加,所得到的總大小就是該文件在可執(zhí)行文件中所占空間大小,此過(guò)程使用自動(dòng)化腳本實(shí)現(xiàn)。例如:libWeChatSDK 這個(gè)靜態(tài)鏈接庫(kù)文件的文件編號(hào)為1260,把Sysmbols 中1260 對(duì)應(yīng)的所有段大小累加為0x00000040+0x00000040+0x000000A0=288B。
在不斷迭代開(kāi)發(fā)中,工程中存在較大數(shù)量的重復(fù)代碼,這些代碼無(wú)用的能進(jìn)行刪除,有用的能通過(guò)函數(shù)化、面向?qū)ο缶幊痰确绞饺ミM(jìn)行優(yōu)化,從而減少安裝包大小。XCode中使用PMD靜態(tài)分析工具對(duì)代碼進(jìn)行掃描[3],在編譯項(xiàng)目后,會(huì)有匯總文檔給出重復(fù)代碼提示,且在項(xiàng)目代碼中也會(huì)明確提示當(dāng)前代碼與其他文件的多少行開(kāi)始重復(fù)了。開(kāi)發(fā)者依據(jù)提示可快捷地進(jìn)行重復(fù)代碼優(yōu)化或者刪除。
可執(zhí)行文件占據(jù)安裝包的大小比例高,所以在版本迭代開(kāi)發(fā)中監(jiān)控可執(zhí)行文件增長(zhǎng)很有必要。如3) 所述,利用自動(dòng)化腳本對(duì)LinkMap文件進(jìn)行分析可以獲得每個(gè)代碼文件在可執(zhí)行文件中的大小,對(duì)比不同的兩個(gè)版本能夠獲得各代碼文件所占可執(zhí)行文件大小的變化,將這些變化進(jìn)行排序展示和監(jiān)控分析,對(duì)于控制可執(zhí)行文件的增長(zhǎng)具有益處。表1為文件瘦身排行。
2.2 資源優(yōu)化
在iOS安裝包中主要包括圖片、音頻、視頻等,下面將從這幾個(gè)部分展開(kāi)優(yōu)化。
1) 刪除未被使用的圖片、音頻和視頻資源
逐個(gè)使用資源名稱(chēng)去整個(gè)工程項(xiàng)目代碼文件中搜索是否被引用的方法非常耗時(shí),一個(gè)項(xiàng)目需要幾個(gè)小時(shí),性?xún)r(jià)比極低,本文將介紹自動(dòng)化實(shí)現(xiàn)查找未被使用圖片、音頻和視頻的方案,耗時(shí)僅僅幾分鐘甚至幾十秒。本方案的過(guò)程為:①獲得安裝包中的所有文件名,通過(guò)正則表達(dá)式r3"|w(.a+v|w?)m\.a[|sowggf||falpv|em|apc4c||rgmifv|jbp|ga|vjpi|emgp|bemg|pra|p|rnagm]|m"提ov|取wm出v|m所p有圖片、音頻和視頻資源名稱(chēng)。eral s②trin在g:L(.i+n)k"M提a取p 文出件項(xiàng)目中代通碼過(guò)中正全則部表使達(dá)用式了r的".字* l符it?串。原因在于LinkMap文件中列舉出了工程代碼中所有的字符串,而資源文件一般都是使用字符串在代碼中被使用。如下LinkMap文件中Symbols部分的lit? eral string:后面跟隨的就是代碼中使用的字符串,pCnlogu,dqArlcboudme_對(duì)fou應(yīng)nd安對(duì)裝應(yīng)包安中裝的包圖片中資的源音C頻lou資dA源lbuqmr?. code_found.wav。
在不影響用戶(hù)體驗(yàn)的情況下,部分不常用的視頻、音頻和圖片資源、字體庫(kù)等可以放置到云端,用戶(hù)使用時(shí)實(shí)現(xiàn)按需下載,這在一定程度上能減少安裝包大小。利用XCode中的On-Demand Resources 配置,能便捷地將資源配置為按需加載,在需要使用時(shí)請(qǐng)求從AppStore中下載,這對(duì)于游戲或者包含大量多媒體資源的軟件安裝包縮減是非常有效的手段。
2.3 產(chǎn)品功能優(yōu)化
經(jīng)過(guò)長(zhǎng)期累月迭代開(kāi)發(fā)的軟件,軟件里面有大量的已經(jīng)失效功能或者曝光率低的功能代碼,這部分功能的刪減能帶來(lái)安裝包體大小的縮減。失效功能代碼的刪減相對(duì)比較容易實(shí)現(xiàn),但判定某個(gè)功能是否曝光率低是需要數(shù)據(jù)支撐并通過(guò)項(xiàng)目團(tuán)隊(duì)多方確認(rèn)。通常軟件界面需要較多圖片等資源,這里提出結(jié)合界面曝光率和界面二進(jìn)制文件大小兩個(gè)維度來(lái)確定是否刪減功能的方案。一方面,通過(guò)在View Controller 中加入曝光上報(bào)數(shù)據(jù),獲取客戶(hù)端界面曝光率;另一方面,通過(guò)2.1 中所述自動(dòng)化方法從LinkMap 獲取View Controller二進(jìn)制文件的大小,從而估計(jì)這個(gè)模塊的大小。最后,對(duì)于提取出的曝光率低而二進(jìn)制文件占比又比較大的界面,在項(xiàng)目團(tuán)隊(duì)進(jìn)行討論,有重點(diǎn)地進(jìn)行功能優(yōu)化、刪減或者改為網(wǎng)頁(yè)形式實(shí)現(xiàn),例如生命周期不長(zhǎng)的運(yùn)營(yíng)活動(dòng)類(lèi)需求就比較適合使用網(wǎng)頁(yè)形式實(shí)現(xiàn)。
2.4 編譯優(yōu)化和符號(hào)信息設(shè)置
1) 編譯優(yōu)化
Xcode采用Clang編譯,Optimization Level中提供了6個(gè)編譯模式[5],分別是:不做代碼優(yōu)化的None,優(yōu)化代碼性能最小影響編譯時(shí)間的Fast,開(kāi)啟不依賴(lài)時(shí)間/空間的所有優(yōu)化項(xiàng)的Faster,開(kāi)啟全部?jī)?yōu)化會(huì)導(dǎo)致可執(zhí)行文件增大的Fastest,開(kāi)啟除增加包體大小以外的全部?jī)?yōu)化項(xiàng)的Fastest Smallest,激進(jìn)不太推薦的Fastest, Aggressive Optimization。在安裝包的發(fā)布版本中,選擇Fastest Smallest編譯模式,在保證代碼執(zhí)行效率的同時(shí)最小限度影響包大小。
2) 符號(hào)信息設(shè)置
symbols是所有的變量、類(lèi)、函數(shù)、枚舉、變量和地址映射關(guān)系,以及一些在調(diào)試的時(shí)候使用到的用于定位代碼在源碼位置的調(diào)試符號(hào),和斷點(diǎn)定位以及堆棧符號(hào)化有很重要的關(guān)系。對(duì)于發(fā)布出去的版本而言,并不是所有的符號(hào)都是必要的,比如調(diào)試符號(hào),所以這類(lèi)型符號(hào)的刪減也能帶來(lái)包體大小的縮減。在Xcode 中將Strip Linked Product設(shè)置為yes能清除不必要的符號(hào)信息,同時(shí)把Deployment Postprocessing 設(shè)置為YES 使其生效。將Symbols Hidden by Default設(shè)置為yes把symbols申明為私有外部符號(hào)也能減少包大小。
3 結(jié)束語(yǔ)
隨著技術(shù)發(fā)展和用戶(hù)需求的增加,手機(jī)軟件安裝包越來(lái)越大,這提高了用戶(hù)下載成本,對(duì)用戶(hù)新增和軟件留存率有所影響,在進(jìn)行軟件推廣時(shí)也面臨成本增加、用戶(hù)轉(zhuǎn)化率低和各類(lèi)限制,無(wú)形中也會(huì)增加軟件研發(fā)維護(hù)成本。針對(duì)iOS軟件安裝包,本文從多個(gè)方面制定了一套詳細(xì)的自動(dòng)化縮減方案,并進(jìn)行自動(dòng)化監(jiān)控,希望能協(xié)助移動(dòng)應(yīng)用項(xiàng)目團(tuán)隊(duì)進(jìn)一步提升用戶(hù)體驗(yàn),打造精品。