Android打包提速實踐

本文會不定期更新税课,推薦watch下項目邮屁。如果喜歡請star姆涩,如果覺得有紕漏請?zhí)峤籭ssue,如果你有更好的點子可以提交pull request卫旱。本文意在分享作者在實踐中對于debug包和release包的打包提速的方案人灼。

本文固定連接:https://github.com/tianzhijiexian/Android-Best-Practices

需求

讓打包變得更快一點,再快一點顾翼!

實現(xiàn)

刪除不必要的module

AS的代碼結構和eclipse完全不同投放,它為開發(fā)者提供了單工程多module的形式。但多建立一個module就需要多維護一個module适贸。所以如果僅僅是為了方便寫代碼而建立一個module是不可取的灸芳,我強烈建議先做好項目結構的梳理再考慮是否需要建立module。
下面是一個多module的app結構圖:

framework

在as中通過自帶的預覽工具拜姿,也可以幫助我們進行modules的梳理:

module

這個項目中的module有很多烙样,所以gradle在編譯的時候會去檢測module的依賴鏈,gradle會幫助我們層層梳理module之間的關系蕊肥,避免因為module之間相互引用而來帶的問題谒获。這些梳理工作和module的合并工作都會帶來build的時間,如果你的項目build十分緩慢壁却,我強烈建議你去梳理下module的關系批狱,合并部分module。將穩(wěn)定的底層module打包為aar展东,上傳到公司的maven倉庫赔硫,借此來加快build速度。

刪除module中的無用文件

as默認在建立module的同時會建立test目錄:

test

如果你根本沒有編寫測試代碼的打算盐肃,你完全可以刪除test目錄爪膊。
當然,如果你的module就是純代碼砸王,根本沒用到資源文件惊完,也請一并把res目錄刪除掉。

res

刪除主項目中無用的資源文件

項目開發(fā)中多少都會存留一些無用的代碼和資源处硬,資源越多打包合并資源的時間就越長。然而刪除無用的代碼對于提升打包速度的作用微乎其微拇派,我們可以利用混淆這一利器在打release包的時候將無用代碼一次性剔除掉荷辕。對于資源文件,as提供了自動檢測失效文件和刪除的功能件豌,這個絕對值得一試疮方。

remove res

在彈出的對話框中,我強烈建議不要勾選刪除無用的id茧彤,因為databinding會用到一些id骡显,但這在代碼中沒有體現(xiàn),所以as會認為這些id是無用的。如果你刪除了這些id惫谤,那么就等著編譯失敗吧壁顶。別問我是怎么知道的T_T。順便說一下溜歪,每次做這種操作前記得commit一下若专,方便做diff。

dialog

利用no-op加快debug的速度

如果項目中有很多公司自己的module依賴蝴猪,那么你完全可以采用類似于這篇的技巧调衰,給私有的module做no-op(什么是no-op可以看這篇的例子)。因為一般私有的module會比較穩(wěn)定自阱,并且對外暴露的方法不多嚎莉,甚至會是別的項目組開發(fā)的,所以如果這個module本身是用來做監(jiān)控統(tǒng)計這樣的不影響功能工作的話沛豌,建議和開發(fā)者商量提供no-op版本趋箩。文中的舉例:

debugCompile(project(':share-lib-no-op')) {}
releaseCompile(project(':share-lib')) {}
debugCompile(project(':zxing-no-op')) {}
releaseCompile(project(':zxing')) {}

用no-op版本的好處就是只使用接口不使用實現(xiàn),將實現(xiàn)的代碼全部剔除琼懊,如果做的好的話甚至可以再debug時不用multidex阁簸。但壞處就是需要進行協(xié)作交流,如果module對外的接口變動了哼丈,應該考慮到對no-op版本的影響启妹。

減少方法數(shù),不使用multidex

關于什么是multidex醉旦,和怎么使用它饶米,請參考這篇文章:
http://blog.csdn.net/t12x3456/article/details/40837287

它是一種不得已而為之的舉措吏垮,在使用的時候我經常會發(fā)現(xiàn)在一些特殊的機型上會出現(xiàn)一些奇奇怪怪的錯誤蝙叛,總之就是有很多坑焕数。
在build時間這一塊寻拂,multidex因為有分包和壓縮的過程摄杂,所以它對于編譯速度方面有有嚴重的影響厂捞。我通過dexcount這個插件分析了我們的項目后馍迄,發(fā)現(xiàn)項目中有一些庫已經不再用或者有更好的替代品兴泥,于是我精簡了第三方庫主卫,并且開啟了support包的混淆逃默,最終讓我們的項目的release包的方法數(shù)達到了一個合理的水平。

優(yōu)化前
精簡庫簇搅,開啟support包的混淆后

為了控制變量完域,我專門做了一個空項目,用來做support包混淆前后的對比瘩将,我們來看一下數(shù)據(jù):

混淆前
混淆后

當一個第三方sdk說不要混淆support包吟税,不要混淆我sdk的代碼的時候凹耙,我強烈建議你考慮下方法數(shù)的問題。混淆的作用之一是將代碼進行優(yōu)化和縮短方法名肠仪、字段名肖抱;作用之二就是刪除沒有被用到的變量和方法。第三方sdk的方法數(shù)眾多藤韵,如果沒辦法混淆虐沥,那么會帶來大量的方法數(shù),這點需要十分的小心泽艘∮眨混淆雖然是一個十分有用的工具,但也是很多錯誤的來源匹涮,所以我建議你小心謹慎的多多使用它天试!

對第三方庫進行優(yōu)化

上面講到了優(yōu)化第三方庫會減少方法數(shù),這里簡單講一下一般的優(yōu)化策略:

1.利用debugCompile來依賴debug時才用到的庫
debugCompile我在第三方庫開發(fā)實踐中已經講到了然低,這里就不多說了喜每。

2.利用更小的庫替代現(xiàn)有的庫
這個就要看開發(fā)人員的經驗和知識面了,雖然是廢話雳攘,如果能真正做到带兜,成果是極其明顯的。

3.利用exclude來排出某些不需要的依賴
以rn舉例吨灭,rn是一個龐大的庫刚照,引入rn后會依賴很多別的庫:

rn

在我們的項目中,我利用了自己編寫的網絡請求模塊進行網絡請求喧兄,所以我就想要剔除掉rn引入的okhttp无畔,我又發(fā)現(xiàn)它還引入了support包,而我項目中也肯定有support包吠冤,所以我也想要排出掉它(不排除support包也沒事浑彰,gradle會僅包含最新的庫版本,我這里僅僅是舉個例子)

  compile ('com.facebook.react:react-native:+'){
    exclude group: 'com.squareup.okhttp3', module: 'okhttp'
    exclude group: 'com.android.support', module: 'support-v4'
    exclude group: 'com.android.support', module: 'support-v7'
  }

重新build一次后拯辙,你會發(fā)現(xiàn)okhttp已經被剔除掉了:

exclude okhttp

對于本地的module也是可以這樣處理的:

compile(project(':react-native-custom-module')) {
    exclude group: 'com.facebook.react', module: 'react-native'
}

用公司的倉庫做緩存

我推薦的做法是項目所有的依賴(私有或第三方)都通過公司的倉庫進行獲取郭变,公司的倉庫會自己查找jcenter等倉庫,下載好需要的依賴涯保,并進行緩存饵较。這樣的好處是,當一個同事引入了新庫或者更新庫版本后遭赂,別的同事在build時可以直接拿緩存,大大減少了下載依賴的時間横辆。這點雖然是小優(yōu)化撇他,但是對于新人和團隊協(xié)作來說是很重要的茄猫。

debug時跳過某些task

我們的項目中用到了很多gradle插件,有些插件會在build時運行自己的task:

gradle plugin

tiny是用來壓縮圖片的困肩,buildtime是用來檢測build時間的划纽,dexcount是用來分析方法數(shù)的。這些插件對于我們的開發(fā)帶來了巨大的幫助锌畸,但也增加了build時間勇劣。

我分享下我的做法:

  1. 在每次發(fā)版本前開啟tiny,直接build一次潭枣,壓縮完圖片后將其關閉比默。
  2. 在需要檢測和診斷build時間的時候啟用buildtime,一般的debug時不開啟它盆犁。
  3. 在release包中開啟dexcount命咐,并且讓其于Jenkins進行結合。這樣既不會影響debug包谐岁,又可以進行方法數(shù)的持續(xù)監(jiān)控醋奠。

關于dexcount是如何和Jenkins結合的,并且是如何產生下面的圖表的伊佃,請參考:
http://www.th7.cn/Program/Android/201606/870070.shtml

dexcount

放棄lambda表達式窜司,謹慎使用AspectJ

目前android不支持lambda,所以很多人都引入了 retrolambda航揉。一旦你引入了這個庫塞祈,你就必須面臨著字節(jié)碼轉換而帶來的build慢的問題。你用的越多迷捧,代碼看起來越簡單织咧,但build時間也會越來越長。所以漠秋,我不推薦在目前的階段使用它笙蒙,還是等等看看谷歌jack的表現(xiàn)吧。

AspectJ是aop的很好的工具庆锦,但因為需要在build時進行代碼的插入捅位,所以使用AspectJ后build時間會明顯的增加,具體看使用量而定搂抒。AspectJ的優(yōu)缺點十分明顯艇搀,我這里只是提出來,具體如何權衡求晶,就看大家自己了焰雕。我的話,因為用了UiBlock所以引入了AspectJ芳杏,讓我debug是build的速度慢了三秒鐘矩屁,但UiBlock的好處也十分明顯辟宗,所以我還是用了它。

dev包中設置minSdkVersion為21

因為在debug時吝秕,我們不會去開啟混淆泊脐,所以debug包是需要用mulitdex的

debugApplication

android5.0對于mulitdex做了優(yōu)化,具體可以參考官方的文章烁峭,我就直接說怎么做就好容客。先在gradle的配置中添加一個flavors,比如叫做dev约郁,在dev中配置最小支持的android版本為21.

gradle

然后在build時選中devDebug缩挑,這樣你debug的時候就是走最低支持api為21的編譯方式了。


build

特別注意:
你現(xiàn)在為了提速將最低版本寫為21棍现,假設你最終可能支持的是16调煎。這就有個風險點,因為as會在你寫代碼的時候認為你的應用就是支持21的己肮,所以對于一些1621的api不會有風險提示士袄。因此使用1621之間的api時需要人為的注意,這是最大的風險點;哑АBα!

開啟offline

這個是最簡單直接的加速方案了艘绍,效果極其明顯赤拒,誰用誰知道!

offline

優(yōu)化gradle

gradle的各種優(yōu)化配置網上已經有很多了诱鞠,這里建議看這篇文章

我自己的配置如下:

org.gradle.daemon=true
org.gradle.parallel=true

# ndk
android.useDeprecatedNdk=true

org.gradle.configureondemand=truex
org.gradle.jvmargs=-Xmx3072m -XX:MaxPermSize=1024m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8

總的來說除了增加內存這一項感覺還有點用處外挎挖,其余配置都不痛不癢。我最后直接加了4g的內存條航夺,一次性解決了大多數(shù)的問題蕉朵。

優(yōu)化crashlytics的upload

上面講到的都是build過程中的提速,但打包不僅僅包含了build阳掐,還包含了混淆始衅,簽名等過程。如果你的項目用了crashlytics缭保,crashlytics會在混淆時自動上傳map文件到服務器汛闸,這樣可以幫助你在分析崩潰的時候看到的是混淆前的代碼和行數(shù),十分方便艺骂。
萬事有利有弊诸老,我們項目的map文件為6m左右,crashlytics的服務器又是在國外钳恕,所以每次都會需要很長的一段時間别伏。
優(yōu)化點主要是提升上行帶寬和網絡速度吮廉,前者需要硬件的支持,后者可以通過vpn進行優(yōu)化畸肆。在配置release包打包命令的時候,可以不用每次都把build目錄刪除宙址,這在一定程度上也可解決此問題轴脐。

利用MultiChannelPackageTool進行多渠道打包

我們的應用可能會被分發(fā)到多個渠道,而我們又想進行多個渠道的數(shù)據(jù)分析抡砂,這就產生了目前android要打多個渠道包的現(xiàn)狀大咱。這篇文章詳細的分析了國內最高效的打包方案,文章短小精干注益,值得一讀碴巾。
我選擇的是MultiChannelPackageTool來進行打包,它的速度是最快的丑搔,而且使用方式十分的簡單厦瓢。他的原理是在zip文件的comment中加入渠道號,這樣既可以寫入渠道號又不會破壞zip的簽名啤月,因為apk本身就是一個zip文件煮仇,所以這個規(guī)則是可靠并完全適用的。

comment

具體的原理和實現(xiàn)方案也不難谎仲,這里可以參考趙林寫的這篇文章進行深入了解浙垫。

下面我給大家演示下實際的情況:

package

現(xiàn)在我們可以通過

MCPTool.getChannelId(context, "password", "")

得到渠道名稱,如果你用的是友盟來做監(jiān)控和統(tǒng)計郑诺,那么你肯定需要在代碼中設置友盟的key和channel名夹姥。通過友盟的文檔和論壇我發(fā)現(xiàn)友盟最新的sdk提供了這樣的機制,于是就有了如下代碼:

// 設置key和渠道號辙诞,在application中就需要進行設置
UMAnalyticsConfig config = new UMAnalyticsConfig(context, appKey, channelId);
MobclickAgent.startWithConfigure(config);

// 得到key和渠道號
String appKey = AnalyticsConfig.getAppkey(activity);
String channel = AnalyticsConfig.getChannel(activity);

采用增量編譯

as目前已經支持了增量編譯辙售,但是效果真的很差,甚至經常會增加build時間倘要,所以這里我還是推薦一直在更新的Jrebel做增量編譯的工具圾亏。我之前寫《Android中UI實時預覽實踐》的時候就有推薦過它,只不過那時候真的太貴了》馀。現(xiàn)在as出了增量編譯志鹃,它也坐不住了,立刻降價泽西,價錢還算是可以接收曹铃。至于效果嘛,我可以說是目前android增量編譯做的最好的了捧杉,如果你寫的是小型應用的話陕见,效果會更好∶匮現(xiàn)在它已經不用我們單獨配置maven倉庫了,完全和項目解耦评甜,而且它竟然支持注解和aop灰粮,堪稱黑科技!所以忍坷,如果你有心想要加快打包的速度粘舟,我強烈推薦你去試用上21天,看看它是否值得你為之付費佩研。

jirebel

升級jdk和gradle

最新的Gradle要比老版本要快柑肴,jdk1.8比jdk1.6要快,所以可以跟著官方升級新版本就好旬薯。

developer_kale@foxmail.com
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末晰骑,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子绊序,更是在濱河造成了極大的恐慌硕舆,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件政模,死亡現(xiàn)場離奇詭異岗宣,居然都是意外死亡,警方通過查閱死者的電腦和手機淋样,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進店門耗式,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人趁猴,你說我怎么就攤上這事刊咳。” “怎么了儡司?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵娱挨,是天一觀的道長。 經常有香客問我捕犬,道長跷坝,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任碉碉,我火速辦了婚禮柴钻,結果婚禮上,老公的妹妹穿的比我還像新娘垢粮。我一直安慰自己贴届,他們只是感情好,可當我...
    茶點故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著毫蚓,像睡著了一般占键。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上元潘,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天畔乙,我揣著相機與錄音,去河邊找鬼翩概。 笑死啸澡,一個胖子當著我的面吹牛,可吹牛的內容都是我干的氮帐。 我是一名探鬼主播,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼洛姑,長吁一口氣:“原來是場噩夢啊……” “哼上沐!你這毒婦竟也來了?” 一聲冷哼從身側響起楞艾,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤参咙,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后硫眯,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蕴侧,經...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年两入,在試婚紗的時候發(fā)現(xiàn)自己被綠了净宵。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,018評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡裹纳,死狀恐怖择葡,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情剃氧,我是刑警寧澤敏储,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布,位于F島的核電站朋鞍,受9級特大地震影響已添,放射性物質發(fā)生泄漏。R本人自食惡果不足惜滥酥,卻給世界環(huán)境...
    茶點故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一更舞、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧恨狈,春花似錦疏哗、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽贝搁。三九已至,卻和暖如春芽偏,著一層夾襖步出監(jiān)牢的瞬間雷逆,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工污尉, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留膀哲,地道東北人。 一個月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓被碗,卻偏偏與公主長得像某宪,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子锐朴,可洞房花燭夜當晚...
    茶點故事閱讀 42,762評論 2 345

推薦閱讀更多精彩內容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,501評論 25 707
  • 0x01 基本項目結構 使用Android Studio創(chuàng)建的Android項目會劃分成三個層級: project...
    銀小古兒閱讀 1,944評論 1 2
  • Spring Cloud為開發(fā)人員提供了快速構建分布式系統(tǒng)中一些常見模式的工具(例如配置管理兴喂,服務發(fā)現(xiàn),斷路器焚志,智...
    卡卡羅2017閱讀 134,599評論 18 139
  • liaoping閱讀 168評論 0 0
  • 當時間過了午夜酱酬,再沉厚的黑夜也會摻上黎明希望壶谒。可是當我嗅到這縷希望膳沽,心中滿是對自己的咒罵汗菜。 開始動手寫這篇文章的時...
    人生空白期閱讀 156評論 0 1