Android Gradle必備使用技巧,未完待續(xù)缕贡,歡迎關注公眾號
flysnow_org
,第一時間看后續(xù)技巧。
隨著工程越來越大善绎,功能越來越多黔漂,開發(fā)人員越來越多,代碼越來越復雜禀酱,不可避免的會產生一些不在使用的資源,這類資源如果沒有清理的話牧嫉,會增加我們Apk的包大小剂跟,也會增加構建的時候。
要清理這些無用的資源酣藻,第一個辦法是我們在開發(fā)的過程中曹洽,把不再使用的資源清理掉,這個靠開發(fā)人員的自覺以及對程序代碼邏輯的了解成都辽剧,而且清理成本也比較大送淆。
第二個辦法是使用Android Lint,它會幫我們檢測出哪些資源沒有被使用怕轿,然后我們按照檢測出來的列表清理即可偷崩,這種辦法需要我們隔一段時間就要清理一次,不然就可能會有無用的資源遺留撞羽,做不到及時性阐斜。
以上兩個方式還有一個不能解決的問題,他就是第三方庫里的資源的問題诀紊。如果你引用的第三方庫里也含有無用的資源谒出,那么這兩種辦法都不能做到清理他們,因為他們被打包在第三方庫里邻奠,沒有辦法做刪除笤喳。
針對以上情況,Android Gradle為我們提供了在構建打包時自動清理掉未使用資源的方法碌宴,這個就是Resource Shrinking杀狡。他是一種在構建時,打包成Apk之前唧喉,會檢測所有資源捣卤,看看是否被引用,如果沒有八孝,那么這些資源就不會被打包到Apk包中.
因為是在這個過程中(構建時)董朝,Android Gradle構建系統(tǒng)會拿到所有的資源,不管是你項目自己的干跛,還是引用的第三方的子姜,它都一視同仁的處理,所以這個時機點可以控制哪些資源可以被打包,所以能解決第三方不使用的資源的問題哥捕。
比如我們常用的Google Play Service牧抽,這個是一個比較大的庫,它支持很多Google的服務遥赚,比如Google Drive扬舒,Google Sign In等等,如果你在你的應用中只使用了Google Drive這個服務凫佛,并沒有使用到Google Sign In服務讲坎,那么在構建打包的時候,會自動的處理Google Sign In功能相關的無用資源圖片愧薛。
Resource Shrinking要結合著Code Shrinking一起使用晨炕,什么是Code Shrinking呢?就是我們經常使用的ProGuard毫炉,也就是我們要啟用minifyEnabled瓮栗,是為了縮減代碼的;
我們上面已經講了瞄勾,自動清理未使用的資源的原理很簡單费奸,就是判斷有沒有用到這些資源,如果你的代碼還在使用丰榴,那么自然不會被清理货邓,所以要和代碼清理結合使用,先清理掉無用的代碼四濒,這樣這些無用的代碼引用的資源才能被清理掉换况。那么我們如何配置使用呢,看下面的示例盗蟆,如下Gradle配置來啟用Resource Shrinking:
android {
compileSdkVersion 23
buildToolsVersion "23.0.1"
buildTypes {
release {
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
啟用Resource Shrinking是通過調用BuildType的shrinkResources來設置的戈二,只要給這個方法傳遞一個true的參數(shù),就可以啟用喳资,默認情況下是不啟用的觉吭。
/**
* Whether shrinking of unused resources is enabled.
*
* Default is false;
*/
public void shrinkResources(boolean flag) {
this.shrinkResources = flag;
}
當我們開啟了shrinkResources后,打包構建的時候仆邓,Android Gradle就會自動的處理未使用的資源鲜滩,不把他們打包到生成的Apk中,我們可以在我們構建輸出的日志中看到處理結果节值,以我們當前的示例代碼為例徙硅,我們運行./gradlew :app:assembleRelease
就可以看到如下日志:
:app:transformClassesWithDexForRelease
:app:transformClassesWithShrinkResForRelease
Removed unused resources: Binary resource data reduced from 159KB to 29KB: Removed 81%
Note: If necessary, you can disable resource shrinking by adding
從159KB減少到29KB,減少了81%搞疗,效果非常顯著嗓蘑,當然這是因為我演示的,現(xiàn)實中可能不會減少這么多,但是減少一點是一點桩皿。
以前是一個匯總的日志輸出豌汇,如果你想看詳細日志,想知道哪些資源被自動清理了泄隔,可以使用--info標記拒贱,顯示詳細的Gradle信息,然后把和自動清理資源的日志過濾出來即可佛嬉。我們可以通過如下命令實現(xiàn):
./gradlew clean :app:assembleRelease --info | grep "unused resource"
運行后我們可以通過日志輸出看到具體的哪些資源被清理了:
Skipped unused resource res/drawable/unused.jpg: 133399 bytes (replaced with small dummy file of size 0 bytes)
Removed unused resources: Binary resource data reduced from 159KB to 29KB: Removed 81%
自動清理未使用的資源這個功能雖好柜思,但是有時候會誤刪,為什么呢巷燥,因為我們在代碼編寫的時候可能會使用反射去引用資源文件,尤其很多你引用的第三方庫會這么做号枕,這時候Android Gradle就區(qū)分不出來了缰揪,可能會誤認為這些資源沒有被使用。針對這中情況葱淳,Android Gradle為我們提供了keep方法來讓我們配置哪些資源不被清理钝腺。
keep方法使用非常簡單,我們要新建一個xml文件來配置赞厕,這個文件是 res/raw/keep.xml
艳狐,然后通過tools:keep屬性來配置,這個tools:keep接受一個以逗號(,)分割的配置資源列表皿桑,并且支持星號(*)通配符毫目。
有沒有覺得它和我們用ProGuard的配置文件是一樣的,我們在ProGuard配置文件里配置保存一些不被混淆的類也是這么做的诲侮。此外镀虐,對于res/raw/keep.xml
這個文件我們不用擔心,Android Gradle構建系統(tǒng)最終打包的時候會清理它沟绪,不會把它打包進Apk中的刮便,除非你在代碼中通過R.raw.keep引用了它。
以下是res/raw/keep.xml示例绽慈,引用自Android Tech Docs
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools"
tools:keep="@layout/l_used*_c,@layout/l_used_a,@layout/l_used_b*"/>
keep.xml還有一個屬性是 tools:shrinkMode
恨旱,用于配置自動清理資源的模式,默認是safe坝疼,是安全的搜贤,這種情況下,Android Gradle可以識別代碼中類似于如下示例的引用
getResources().getIdentifier("unused","drawable",getPackageName());
這類代碼也被構建系統(tǒng)認為是使用了資源文件裙士,不會被清理入客。如果把清理模式改為strict,那么就沒有辦法識別了,這個資源會被認為沒有被引用桌硫,也會被清理掉夭咬。
除了shrinkResources之外,Android Gradle還為我們 提供了一個resConfigs铆隘,它屬于ProductFlavor的一個方法卓舵,可以讓我們配置哪些類型的資源才被打包到Apk中,比如只有中文的膀钠,只有hdpi格式的圖片等等掏湾,這是非常重要的,比如我們引用的第三方庫肿嘲,特別是Support Library 和 Google Play Services這兩個主要的大庫融击,因為國際化的問題,他們都支持了幾十種語言雳窟,但是對于我們的App來說尊浪,我們并不需要這么多,比如我們只用中文的語言就可以了封救,其他的都不需要拇涤;比如我們支持hdpi格式的圖片就好了,其他的都不需要誉结,這時候我們就可以通過resConfigs方法來配置:
android {
compileSdkVersion 23
buildToolsVersion "23.0.1"
defaultConfig {
applicationId "org.flysnow.app"
minSdkVersion 14
targetSdkVersion 23
versionCode 1
versionName '1.0.0'
resConfigs 'zh'
}
}
這樣我們就只保留了zh資源鹅士,其他非zh資源都不會被打包到Apk文件中。
其實這個resConfig的配置有3中辦法惩坑,一般常用的是resConfigs這個方法掉盅,因為可以同時指定多個配置,你也可以使用resConfig(后面沒有s)來指定一個配置旭贬,它一次只能添加一個怔接,如果要添加多個,要么調用多次稀轨,要么使用resConfigs方法扼脐。我們看下他們的方法原型,了解他們的方法原理:
/**
* Adds a resource configuration filter.
*
* <p>If a qualifier value is passed, then all other resources using a qualifier of the same type
* but of different value will be ignored from the final packaging of the APK.
*
* <p>For instance, specifying 'hdpi', will ignore all resources using mdpi, xhdpi, etc...
*/
public void resConfig(@NonNull String config) {
addResourceConfiguration(config);
}
/**
* Adds several resource configuration filters.
*
* <p>If a qualifier value is passed, then all other resources using a qualifier of the same type
* but of different value will be ignored from the final packaging of the APK.
*
* <p>For instance, specifying 'hdpi', will ignore all resources using mdpi, xhdpi, etc...
*/
public void resConfigs(@NonNull String... config) {
addResourceConfigurations(config);
}
/**
* Adds several resource configuration filters.
*
* <p>If a qualifier value is passed, then all other resources using a qualifier of the same type
* but of different value will be ignored from the final packaging of the APK.
*
* <p>For instance, specifying 'hdpi', will ignore all resources using mdpi, xhdpi, etc...
*/
public void resConfigs(@NonNull Collection<String> config) {
addResourceConfigurations(config);
}
resConfig的使用非常廣泛奋刽,它的參數(shù)就是我們在Android開發(fā)時的資源限定符瓦侮,不止于我們上面描述的語言和密度,還包括Api Level佣谐,分辨率等等肚吏,具體的可以參考Android Doc文檔。
以上自動清理資源只是在打包的時候狭魂,不打包到Apk中罚攀,實際上并沒有刪除我們工程中的資源党觅,如果我們在使用的時候發(fā)現(xiàn)有大量的無用資源被清理,那么我們自己最好還是把這些資源文件從我們的工程中刪除吧斋泄,這樣也好維護一些杯瞻。
Android Gradle必備使用技巧,未完待續(xù)炫掐,歡迎關注公眾號
flysnow_org
魁莉,第一時間看后續(xù)技巧。