完全弄清support支持庫,以及v4 v7重複依賴問題深究

本篇文章已受權微信公衆號 hongyangAndroid (鴻洋)獨家發佈java

前言

衆所周知android提供了不少Support Library做爲api的補充,常見的有supprt-v4,v7等,但我發現這些支持庫的版本衆多,涉及的內容也比較龐雜,本文帶你們梳理一下常見的Support Library,而後文章後半部分對一個報錯問題展開深究,那就是咱們用開源庫時常常碰到的v4重複依賴問題:DexException Multiple dex files define。android

爲什麼提供支持庫

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的錯誤。這很好理解,由於舊版本上沒有新版本里新增的類。爲了不使用了最新功能開發的app只能在最新系統的設備上運行的尷尬,官方把新版系統framework中新增長的接口提出來放到了Android Support Library(支持包)中,開發者在遇到上面的狀況時,就可使用支持包中具備一樣功能的ActionBar類,這個支持包會打包進App裏,這樣使用了新版本系統上功能的App也能夠向後兼容之前的老系統版本設備了。 使用支持包中的類除了讓咱們免於判斷App運行的系統版本外,還可使App在各個版本保持一樣的用戶體驗。如在5.0如下系統使用material design。api

2.提供不適合打包進framework的功能微信

Android官方對App開發提供了推薦設計,但願Android應用都有相對一致的交互設計來減小用戶的使用成本,但願三方App相似系統應用從而完美融入到Android生態系統中。可是這都僅僅是推薦,不要求開發者必定要這樣,若是有這種需求就可使用官方支持包提供的這些功能,避免重複造輪子。如支持包中的DrawerLayout、Snackbar等類都是這種狀況。app

3.爲了支持不一樣形態的設備框架

經過使用支持包來在不一樣形態設備上提供功能,如手機、電視、可穿戴設備等。maven

support-library支持庫

Android 支持庫提供了諸多未內置於框架的功能。這些庫提供向後兼容版本的新功能、框架中未包含的實用 UI 元素,以及應用能夠利用的一系列實用程序。好比ide

Material Design是Android 5.0加入的新功能,可是不少設備依然裝的是Android4.0系統,若是爲了Material Design將minSdkVersion設置爲 api21顯然不合理的,那爲了Android5.0如下的設備可使用Material Design的效果,就應該使用support-library,包括以前的Fragment和如今的權限檢查,都是這個原理!工具

目前爲止Android Support Library包含的依賴包有:比較經常使用的是1,2,3

image.png

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庫的依賴關係圖:

image.png

好比下面這些都是v4包的內容: Fragment:一個專爲解決Android碎片化的類,經過它可讓同一個程序適配不一樣的屏幕。 NotificationCompat:支持更豐富的通知形式; LocalBroadcastManager:適合於應用內的消息傳遞。 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查看依賴庫的信息:

image.png
能夠看到咱們依賴的v4包就在sdk的extras目錄:
image.png
這個是咱們在androidStudio的SDK Manager中下載的,若是沒有下載gradle同步後會讓你去下載。

support-v7

V7和V4同樣,一樣包含多個依賴包,但和V4不一樣的是,V7下的多個子包並非後面拆分開來的,而是最初發布時就以各個獨立庫的形式發佈的。它是針對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接口的實現等,核心類有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

當你的項目代碼量愈來愈大的時候,會發現某一天運行在Android5.0如下的手機莫名崩潰。報錯:某個類class not found,而這個類明明就有啊。。。其實這就是 著名的方法數超過 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嗎?

爲啥問這個問題,源於我看網上不少文章,介紹v4的時候不假思索地下結論:v7包含v4!真的是這樣嗎???

咱們打開v7的jar包看源碼,其實appcompat-v7包自己是不包含v4的jar包的:

image.png

新建一個工程,加入v7的依賴包:

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])     compile 'com.android.support:appcompat-v7:24.2.1' } 複製代碼

看下項目目前的依賴包狀況:

image.png

果真,項目自動引入了v4下面的全部包,v7包涵v4的意思是:

compile 'com.android.support:appcompat-v7:24.2.1', gradle會自動加入全部v4包的依賴,而且是和v7相同的版本

support庫必須和compileVersion一致嗎?

image.png

不是必須的。只是官方建議保持一致,若是版本不一致仍然能夠編譯運行。

v4包的重複依賴問題

上面已經證實依賴v7包會自動引入v4包,那麼在項目中同時依賴v4和v7,會出現所謂的重複依賴編譯報錯嗎?

image.png

能夠成功編譯運行安裝,沒有報錯:

:mylibrary:preDebugUnitTestBuild UP-TO-DATE
:mylibrary:prepareDebugUnitTestDependencies
BUILD SUCCESSFUL
Total time: 7.005 secs

複製代碼

即便同時引入不一樣版本的v4包,也並無出現包依賴重複的報錯,能夠正常編譯運行:(注:紅線是版本和compileSdkVersion不一致致使,此處忽略)

image.png

確實引入了不一樣版本的v4包:

image.png

  • 結論: 若是都是maven的方式引入v4包,gradle會自動選擇版本較高的,好比這裏的21.0.3版本,不會致使衝突。

接下來,試試maven引入21.0.3的v4包,而後本地引入19.1.0的jar包:

image.png

運行時報錯: dex文件衝突

image.png

固然,若是lib放入的和maven配置v4包版本21.0.3相同,是能夠的。

(Android從support-20.0.0版本開始,v4的jar包所有升級爲aar包),解壓工具提取aar裏面的classes.jar而後重命名爲support-v4-21.0.3.jar放入lib文件夾

image.png

  • 結論:v4的依賴衝突實際上是不一樣版本v4的衝突,而且是本地lib和maven引入不一樣版本纔會衝突

異常衝突解決辦法

一個項目每每要引入不少開源庫,試圖統一全部moduler的v4版本是不現實的,只能經過exclude 方法過濾某些庫的v4包,保證整個項目只引入一個版本。

1. 首先查看當前項目各類庫的依賴狀況:

image.png

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' 
}
複製代碼
相關文章
相關標籤/搜索