本篇文章已授權微信公眾號 hongyangAndroid (鴻洋)獨家發(fā)布
前言
眾所周知android提供了很多Support Library作為api的補充力试,常見的有supprt-v4苏携,v7等毛仪,但我發(fā)現(xiàn)這些支持庫的版本眾多搁嗓,涉及的內(nèi)容也比較龐雜,本文帶大家梳理一下常見的Support Library箱靴,然后文章后半部分對一個報錯問題展開深究腺逛,那就是我們用開源庫時經(jīng)常碰到的v4重復依賴問題: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的設備上完美運行慨绳,但是app在android 2.3的設備就會crash,報找不到ActionBar的錯誤真竖。這很好理解脐雪,因為舊版本上沒有新版本里新增的類。為了避免使用了最新功能開發(fā)的app只能在最新系統(tǒng)的設備上運行的尷尬恢共,官方把新版系統(tǒng)framework中新增加的接口提出來放到了Android Support Library(支持包)中战秋,開發(fā)者在遇到上面的情況時,就可以使用支持包中具有同樣功能的ActionBar類讨韭,這個支持包會打包進App里脂信,這樣使用了新版本系統(tǒng)上功能的App也可以向后兼容以前的老系統(tǒng)版本設備了癣蟋。
使用支持包中的類除了讓我們免于判斷App運行的系統(tǒng)版本外,還可以使App在各個版本保持同樣的用戶體驗狰闪。如在5.0以下系統(tǒng)使用material design疯搅。
2.提供不適合打包進framework的功能
Android官方對App開發(fā)提供了推薦設計,希望Android應用都有相對一致的交互設計來減少用戶的使用成本埋泵,希望三方App類似系統(tǒng)應用從而完美融入到Android生態(tài)系統(tǒng)中幔欧。但是這都僅僅是推薦,不要求開發(fā)者一定要這樣丽声,如果有這種需求就可以使用官方支持包提供的這些功能礁蔗,避免重復造輪子。如支持包中的DrawerLayout雁社、Snackbar等類都是這種情況浴井。
3.為了支持不同形態(tài)的設備
通過使用支持包來在不同形態(tài)設備上提供功能,如手機霉撵、電視磺浙、可穿戴設備等。
support-library支持庫
Android 支持庫提供了諸多未內(nèi)置于框架的功能徒坡。這些庫提供向后兼容版本的新功能屠缭、框架中未包含的實用 UI 元素,以及應用可以利用的一系列實用程序崭参。比如
Material Design是Android 5.0加入的新功能,但是很多設備依然裝的是Android4.0系統(tǒng)款咖,如果為了Material Design將minSdkVersion設置為 api21顯然不合理的何暮,那為了Android5.0以下的設備可以使用Material Design的效果,就應該使用support-library铐殃,包括之前的Fragment和現(xià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個部分有依賴關系羊异,二是compat庫占了v4庫的一半大小事秀,v4庫的依賴關系圖:
比如下面這些都是v4包的內(nèi)容:
Fragment:一個專為解決Android碎片化的類彤断,通過它可以讓同一個程序適配不同的屏幕。
NotificationCompat:支持更豐富的通知形式易迹;
LocalBroadcastManager:適合于應用內(nèi)的消息傳遞斑鸦。
ViewPager:一個可以管理子view的viewgroup选侨,用戶可以在各個view之間自由切換,這個在很多應用中都有使用到;
上面說到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包各自對應著特定的功能嘿歌,每一個都可以單獨地被引用掸掏。
v7 app-compat這個包支持對Action Bar接口的設計模式、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
當你的項目代碼量越來越大的時候,會發(fā)現(xiàn)某一天運行在Android5.0以下的手機莫名崩潰鸳君。報錯:某個類class not found访圃,而這個類明明就有啊。相嵌。腿时。其實這就是 著名的方法數(shù)超過 64K 的應用異常况脆。解決辦法就是這個支持庫。
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重復依賴深究
下面詳細介紹 很常見的v4庫的重復依賴問題批糟,先拋出兩個問題:
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包的重復依賴問題
上面已經(jīng)證明依賴v7包會自動引入v4包煞茫,那么在項目中同時依賴v4和v7帕涌,會出現(xiàn)所謂的重復依賴編譯報錯嗎?
可以成功編譯運行安裝续徽,沒有報錯:
:mylibrary:preDebugUnitTestBuild UP-TO-DATE
:mylibrary:prepareDebugUnitTestDependencies
BUILD SUCCESSFUL
Total time: 7.005 secs
即使同時引入不同版本的v4包宵膨,也并沒有出現(xiàn)包依賴重復的報錯,可以正常編譯運行:(注:紅線是版本和compileSdkVersion不一致導致炸宵,此處忽略)
確實引入了不同版本的v4包:
- 結(jié)論: 如果都是maven的方式引入v4包,gradle會自動選擇版本較高的谷扣,比如這里的21.0.3版本土全,不會導致沖突。
接下來会涎,試試maven引入21.0.3的v4包裹匙,然后本地引入19.1.0的jar包:
運行時報錯: dex文件沖突
當然,如果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. 首先查看當前項目各種庫的依賴情況:
2. 找到里面版本沖突的依賴庫,然后查找app項目绘盟,開源庫的lib目錄鸠真,刪除對應的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'
}