本篇文章已授權(quán)微信公眾號 hongyangAndroid (鴻洋)獨家發(fā)布
前言
眾所周知android提供了很多Support Library作為api的補充,常見的有supprt-v4,v7等,但我發(fā)現(xiàn)這些支持庫的版本眾多,涉及的內(nèi)容也比較龐雜,本文帶大家梳理一下常見的Support Library,然后文章后半部分對一個報錯問題展開深究,那就是我們用開源庫時經(jīng)常碰到的v4重復(fù)依賴問題:DexException Multiple dex files define。
為何提供支持庫
google為啥要弄這么多支持庫,直接放到sdk里面不好么? 參閱官方文檔有下面3個原因:
1.向后兼容
如,我們開的App需要支持的minSdkVersion=9,targetSdkVersion=11,在程序里使用了android 3.0 (API level 11)提供的ActionBar類,使用compileSdkVersion=11成功編譯出apk。在android 3.0的設(shè)備上完美運行,但是app在android 2.3的設(shè)備就會crash,報找不到ActionBar的錯誤。這很好理解,因為舊版本上沒有新版本里新增的類。為了避免使用了最新功能開發(fā)的app只能在最新系統(tǒng)的設(shè)備上運行的尷尬,官方把新版系統(tǒng)framework中新增加的接口提出來放到了Android Support Library(支持包)中,開發(fā)者在遇到上面的情況時,就可以使用支持包中具有同樣功能的ActionBar類,這個支持包會打包進App里,這樣使用了新版本系統(tǒng)上功能的App也可以向后兼容以前的老系統(tǒng)版本設(shè)備了。
使用支持包中的類除了讓我們免于判斷App運行的系統(tǒng)版本外,還可以使App在各個版本保持同樣的用戶體驗。如在5.0以下系統(tǒng)使用material design。
2.提供不適合打包進framework的功能
Android官方對App開發(fā)提供了推薦設(shè)計,希望Android應(yīng)用都有相對一致的交互設(shè)計來減少用戶的使用成本,希望三方App類似系統(tǒng)應(yīng)用從而完美融入到Android生態(tài)系統(tǒng)中。但是這都僅僅是推薦,不要求開發(fā)者一定要這樣,如果有這種需求就可以使用官方支持包提供的這些功能,避免重復(fù)造輪子。如支持包中的DrawerLayout、Snackbar等類都是這種情況。
3.為了支持不同形態(tài)的設(shè)備
通過使用支持包來在不同形態(tài)設(shè)備上提供功能,如手機、電視、可穿戴設(shè)備等。
support-library支持庫
Android 支持庫提供了諸多未內(nèi)置于框架的功能。這些庫提供向后兼容版本的新功能、框架中未包含的實用 UI 元素,以及應(yīng)用可以利用的一系列實用程序。比如
Material Design是Android 5.0加入的新功能,但是很多設(shè)備依然裝的是Android4.0系統(tǒng),如果為了Material Design將minSdkVersion設(shè)置為 api21顯然不合理的,那為了Android5.0以下的設(shè)備可以使用Material Design的效果,就應(yīng)該使用support-library,包括之前的Fragment和現(xiàn)在的權(quán)限檢查,都是這個原理!
目前為止Android Support Library包含的依賴包有:比較常用的是1,2,3
support-v4
v4名稱是最開始支持api level4的庫,官方在Support Library 24.2.0版本的時候移除了對Android 2.2(API Level 8)及以下版本的支持,所以從Android Support Library 24.2.0開始,V4包支持的最低版本是Android 2.3即API Level 9),并且把v4庫拆分成5個部分,可以在項目中按需要引用,但是必要性不是很大,一是因為這5個部分有依賴關(guān)系,二是compat庫占了v4庫的一半大小,v4庫的依賴關(guān)系圖:
比如下面這些都是v4包的內(nèi)容:
Fragment:一個專為解決Android碎片化的類,通過它可以讓同一個程序適配不同的屏幕。
NotificationCompat:支持更豐富的通知形式;
LocalBroadcastManager:適合于應(yīng)用內(nèi)的消息傳遞。
ViewPager:一個可以管理子view的viewgroup,用戶可以在各個view之間自由切換,這個在很多應(yīng)用中都有使用到;
上面說到v4是兼容level9之前的版本,那如果我們的compileSdkVersion>9是不是可以不用v4了? 這個不一定的,比如ViewPager這個類只在V4包中才有,在sdk中沒有。
- 如何使用v4
compile 'com.android.support:support-v4:21.0.3'
同步gradle之后,在ExternalLibrarys右鍵v4選擇:library propertity查看依賴庫的信息:
可以看到我們依賴的v4包就在sdk的extras目錄:
這個是我們在androidStudio的SDK Manager中下載的,如果沒有下載gradle同步后會讓你去下載。
support-v7
V7和V4一樣,同樣包含多個依賴包,但和V4不同的是,V7下的多個子包并不是后面拆分開來的,而是最初發(fā)布時就以各個獨立庫的形式發(fā)布的。它是針對Android 2.3(API Level 9)及以上的版本谷歌提供了一系列的support包(和V4包的命名一樣,V7最初支持的最低版本是Android 2.1即API Level 7,所以稱其為V7,同樣在Android Support Library 24.2.0將V7支持的最低版本改為Android 2.3即API Level 9了),這些support包各自對應(yīng)著特定的功能,每一個都可以單獨地被引用。
v7 app-compat這個包支持對Action Bar接口的設(shè)計模式、Material Design接口的實現(xiàn)等,核心類有ActionBar、AppCompatActivity、AppCompatDialog、ShareActionProvider等
- 如何使用v7
compile 'com.android.support:appcompat-v7:24.2.1'
用這個maven方式配置v7會自動引入v4庫,so不需要再額外引入v4庫了。
gradle中jar依賴語句格式如 compile 'jar文件組(group/命名空間):jar文件名(name):jar文件版本(version)'。所以上面的語句意思是依賴Android支持庫中第24.2.1版的appcompat-v7庫。
Multidex Support Library
當(dāng)你的項目代碼量越來越大的時候,會發(fā)現(xiàn)某一天運行在Android5.0以下的手機莫名崩潰。報錯:某個類class not found,而這個類明明就有啊。。。其實這就是 著名的方法數(shù)超過 64K 的應(yīng)用異常。解決辦法就是這個支持庫。
android {
defaultConfig {
...
minSdkVersion 15
targetSdkVersion 26
multiDexEnabled true
}
...
}
dependencies {
compile 'com.android.support:multidex:1.0.1'
}
然后在自定義的Application的加入:
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
MultiDex.install(this);
}
v4 supportLibrary重復(fù)依賴深究
下面詳細(xì)介紹 很常見的v4庫的重復(fù)依賴問題,先拋出兩個問題:
v7包含v4嗎?
為啥問這個問題,源于我看網(wǎng)上很多文章,介紹v4的時候不假思索地下結(jié)論:v7包含v4!真的是這樣嗎???
我們打開v7的jar包看源碼,其實appcompat-v7包本身是不包含v4的jar包的:
新建一個工程,加入v7的依賴包:
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:24.2.1'
}
看下項目目前的依賴包情況:
果然,項目自動引入了v4下面的所有包,v7包涵v4的意思是:
compile 'com.android.support:appcompat-v7:24.2.1', gradle會自動加入所有v4包的依賴,并且是和v7相同的版本
support庫必須和compileVersion一致嗎?
不是必須的。只是官方建議保持一致,如果版本不一致仍然可以編譯運行。
v4包的重復(fù)依賴問題
上面已經(jīng)證明依賴v7包會自動引入v4包,那么在項目中同時依賴v4和v7,會出現(xiàn)所謂的重復(fù)依賴編譯報錯嗎?
可以成功編譯運行安裝,沒有報錯:
:mylibrary:preDebugUnitTestBuild UP-TO-DATE
:mylibrary:prepareDebugUnitTestDependencies
BUILD SUCCESSFUL
Total time: 7.005 secs
即使同時引入不同版本的v4包,也并沒有出現(xiàn)包依賴重復(fù)的報錯,可以正常編譯運行:(注:紅線是版本和compileSdkVersion不一致導(dǎo)致,此處忽略)
確實引入了不同版本的v4包:
- 結(jié)論: 如果都是maven的方式引入v4包,gradle會自動選擇版本較高的,比如這里的21.0.3版本,不會導(dǎo)致沖突。
接下來,試試maven引入21.0.3的v4包,然后本地引入19.1.0的jar包:
運行時報錯: dex文件沖突
當(dāng)然,如果lib放入的和maven配置v4包版本21.0.3相同,是可以的。
(Android從support-20.0.0版本開始,v4的jar包全部升級為aar包),解壓工具提取aar里面的classes.jar然后重命名為support-v4-21.0.3.jar放入lib文件夾
- 結(jié)論:v4的依賴沖突其實是不同版本v4的沖突,并且是本地lib和maven引入不同版本才會沖突
異常沖突解決辦法
一個項目往往要引入很多開源庫,試圖統(tǒng)一所有moduler的v4版本是不現(xiàn)實的,只能通過exclude 方法過濾某些庫的v4包,保證整個項目只引入一個版本。
1. 首先查看當(dāng)前項目各種庫的依賴情況:
2. 找到里面版本沖突的依賴庫,然后查找app項目,開源庫的lib目錄,刪除對應(yīng)的jar包改用maven形式引入。
3. 如果你的app必須要使用本地lib引入v4庫,那么就排除開源庫的v4包:
compile('com.facebook.fresco:fresco:0.10.0') {
exclude module: 'support-v4'
}
如果是源碼形式引入的開源庫:
compile (project(':thirdpart:RecyclerViewAdapterLibrary')){
exclude group: 'com.android.support'
}