Android 庫(Library)在結構上與 Android 應用模塊一樣。應用模塊所可以包括的東西。在庫中都贊成存在,包括代碼文件、資源文件和manifest文件等。css
應用模塊編譯後生成的是一個apk文件,可以直接在設備上執行,但是,庫模塊編譯後生成的是一個Android Archive文件,簡稱AAR。html
AAR文件沒法像apk文件同樣直接在設備上執行,咱們通常用它做爲Android app的依賴。java
普通JAR文件僅僅能包括代碼文件和清單文件,而ARR文件不只可以包括代碼文件。還可以包括Android的資源文件和manifest文件。這樣。咱們就可以把資源文件像佈局文件、圖片文件等和Java代碼文件一塊兒分享出去。可以說ARR文件是真正專屬於Android的「JAR」包。android
庫模塊在下面狀況下很是實用:git
在不論什麼一種狀況下,你僅僅需要將要重用的文件放到庫模塊中,而後以依賴項的形式爲每個應用模塊加入庫就能夠。github
在你的工程中,建立一個新的庫模塊。可以遵循例如如下的步驟:json
僅僅要Gradle同步完畢後,庫模塊就會出現左邊的工程面板中。android-studio
假設你有一個已經存在的應用模塊。並想重用它的所有代碼。你可以把它轉成一個庫模塊:bash
1.打開屬於該應用模塊下的build.gradle文件,在最頂部,你可以看見例如如下的顯示:markdown
java apply plugin: 'com.android.application'
2.把應用的插件改爲庫的插件:
java apply plugin: 'com.android.library'
3.點擊Sync Project with Gradle Files.
處理完上面這些,整個模塊的結構不會被改變,但是該模塊已經變爲了庫模塊,編譯後生成的是AAR文件而再也不是APK文件了。
爲了在應用模塊中使用庫模塊。你需要做例如如下的處理:
1.加入庫到工程中有兩種方式(假設你是在一樣項目中建立的庫模塊,則該模塊已經存在,您可以跳過此步驟)
加入編譯後的ARR(或JAR)文件:
1.點擊 File > New Module.
2.在Create New Module的窗體中,點擊 Import .JAR/.AAR Package 而後點擊 Next.
3.輸入ARR或JAR文件所在的路徑。並點擊Finish。建立後例如如下所看到的:
導入外部庫模塊到工程中:
1.點擊 File > New > Import Module.
2.輸入Library模塊所在的路徑,並點擊Finish。建立後例如如下所看到的:
這兩種引入庫的方式有所不一樣。假設直接引入的是庫模塊,你可以對庫的代碼進行編輯。
但是假設導入的是AAR文件,那麼則沒法進行編輯,就像JAR文件同樣。
2.當庫模塊或AAR文件引入到工程後。請確保庫被列在settings.gradle文件裏,就例如如下所看到的。當中mylibrary是庫的名稱:
include ':app', ':mylibrary'
3.打開應用模塊下的build.gralde文件,並在dependencies塊中加入新的一行,使之成爲該應用的依賴。例如如下片斷所看到的:
dependencies {
compile project(":mylibrary")
}
4.點擊 Sync Project with Gradle Files.
配置完上面的信息後,名爲mylibrary的庫模塊就會成爲應用的依賴。
而後你就可以在應用模塊中讀取不論什麼屬於庫模塊的代碼和資源文件。
事實上咱們還有一種引入本地aar文件的方式。首先在工程的下先創建一個aar文件夾,專門用於存放aar文件,而後在應用的build.gradle加入例如如下配置:
repositories {
flatDir {
dirs '../aar' // aar文件夾
}
}
而後將aar文件複製到工程/aar文件夾下,在應用模塊的dependencies中加入aar引用:
compile(name: 'mylibrary-debug', ext: 'aar')
經過上面的配置,這樣aar就被引入過來了。這樣的方式與上面介紹的引入方式有點不一樣,上面做法是把引入的aar文件封裝成一個獨立的模塊,而後以compile project的方式引入。而現在的這樣的方式有點像jar包的引入方式。
注意:
依據上面的條件,假設把flatDir配置在project的gradle文件裏allprojects.repositories塊下面,發現app項目沒法識別到aar文件。經過規律發現,不管aar文件放在哪裏,僅僅要在app的gradle中配置flatDir都可以被識別。但是假設flatDir配置在project的gradle中,僅僅能把aar文件放到app的模塊下才幹被識別。
咱們可以經過點擊Build > Make Project生成aar文件,aar文件會在project-name/module-name/build/outputs/aar/ 下生成。普通狀況下會有兩個aar文件,一個debug版本號。一個release版本號。
當咱們拿到後aar文件後。就可以把它公佈出去。其它小夥伴就可以利用上面的方式引入aar文件到工程中了。
AAR 文件的文件擴展名爲 .aar,該文件自己就是一個zip文件,必需要包括下面內容:
此外,AAR文件可能包括下面可選條目中的一個或多個:
默認狀況下庫中的所有資源都是公開狀態。也就是說贊成應用模塊直接訪問。但是假設你想讓庫中的資源僅供內部使用,而不想暴露給外部。您應經過聲明一個或多個公開資源的方式來使用這樣的本身主動私有標識機制。資源包括您項目的 res/ 文件夾中的所有文件,好比圖像、佈局等。
首先,在庫的res/values/下新建一個public.xml文件(假設不存在的話),而後在public.xml中定義公開的資源名。下面的演示樣例代碼可以建立兩個名稱分別爲 lib_main_layout和 mylib_public_string的公開佈局資源和字符串資源:
<resources>
<public name="lib_main_layout" type="layout"/>
<public name="mylib_public_string" type="string"/>
</resources>
上面的定義的兩個資源表示公開狀態,可以被外部依賴直接訪問。而沒有被定義在當中的資源都爲隱式私有狀態,外部依賴沒法合法訪問。
當中name爲資源名,type是資源類型有:string、layout、drawable、dimen等。
注意,假設想讓庫中的所有資源都爲私有的,你必需要在public.xml中定義至少一個屬性。
在外部依賴使用庫私有資源的時候,你是沒法經過R點的方式進行提示的。這也爲了避免暴露私有資源的一種手段。假設你強制使用了該資源,編譯器會發出警告:
從上面可以看出。lib_main_layout和mylib_public_string資源都可以直接使用的,而未定義的都爲私有資源,外部依賴使用的時候,編譯器會發出警告信息。
但是這裏有一點需要注意,使用私有資源並不會發生不論什麼錯誤。應用模塊可以正常的使用這些私有資源。之因此提供這樣的機制,是爲了告訴你。庫模塊並不想把這些資源暴露給你,可能這些資源有特殊用途之類的。假設你真想使用私有資源。並且不想編譯器發出如上的警告,你可以把私有資源拷到本身的應用模塊下。
隱私的賦予資源私有屬性不只可以必定程度上防止外部使用,並且還贊成你重命名或刪除私有資源時,不會影響到使用到該庫的應用模塊。私有資源不在代碼本身主動完畢和 Theme Editor 的做用範圍內,並且假設您嘗試引用私有資源,Lint 將顯示警告。
將庫模塊引用加入至您的Android 應用模塊後,庫模塊會依據優先級的順序與應用模塊進行合併。
構建工具會將庫模塊中的資源與相關應用模塊的資源合併。
假設在兩個模塊中均定義了一樣的資源 ID,那就默認使用應用模塊的資源。
假設多個 AAR 庫之間發生衝突,將使用依賴項列表首先列出(位於 dependencies 塊頂部)的庫中的資源。
爲了不常用資源 ID 的資源衝突。請使用在模塊(或在所有項目模塊)中具備惟一性的前綴或其它一致的命名方案。
咱們舉個樣例來證實觀點1。觀點2感興趣的同窗可以本身驗證。
首先在庫模塊mylibraryone中定義了例如如下的string資源:
<resources>
<string name="app_name">My Library</string>
<string name="test_one">My name is Library</string>
<string name="my_library">Library</string>
</resources>
經過該庫的R文件,這三個資源文件的id值爲:app_name=0x7f020000、my_library=0x7f02000一、test_one=0x7f020002
而後在應用模塊mytesttwo中這也定義了例如如下的string資源:
<resources>
<string name="app_name">MyTestTwo</string>
<string name="test_one">My name is App</string>
</resources>
請注意。當中資源名app_name 和test_one 和庫中定義的string資源名同樣。
咱們把mylibraryone庫該做爲mytesttwo應用的依賴,並又一次編譯。你們可以發現在應用模塊生成了兩個R文件:
當中第一個是庫合併過來後的R文件,而第二個是應用本身的R文件。
咱們對照下。兩個R文件的內容:
mylibraryone:
public final class R {
public static final class string {
public static final int app_name = 0x7f040000;
public static final int my_library = 0x7f040001;
public static final int test_one = 0x7f040002;
}
}
mytesttwo:
public final class R {
.....
public static final class mipmap {
public static final int ic_launcher=0x7f020000;
}
public static final class string {
public static final int app_name=0x7f040000;
public static final int my_library=0x7f040001;
public static final int test_one=0x7f040002;
}
}
mylibraryone庫的R文件僅僅包括本身的資源,並且所有的資源值都發生了改變。並且庫中的資源id也都合併到應用的R文件裏了。
從上面的兩個文件可以看出一個特性:
用庫的R文件和應用的R文件都能訪問到庫的資源。但是沒法用庫的R文件訪問應用資源。
既然現在庫的資源和應用的資源現在進行了合併。那當咱們使用test_one字符串的時候用的是哪個呢?咱們在應用模塊下直接輸出id值來瞧瞧:
Log.d("cryc","App:"+Integer.toHexString(com.example.mytesttwo.R.string.test_one)+"");
Log.d("cryc","App:"+getString(com.example.mytesttwo.R.string.test_one)+"");
Log.d("cryc","Library:"+Integer.toHexString(com.example.mylibraryone.R.string.test_one)+"");
Log.d("cryc","Library:"+getString(com.example.mylibraryone.R.string.test_one));
Log.d("cryc","Library:"+Integer.toHexString(com.example.mylibraryone.R.string.my_library));
Log.d("cryc","Library:"+getString(com.example.mylibraryone.R.string.my_library));
輸出結果:
App:7f040002
App:My name is App
Library:7f040002
Library:My name is App
Library:7f040001
Library:Library
你們可以看出,假設庫和應用的資源名衝突了,不管使用哪一個R文件。都那默認使用應用的資源。
你們也許還有疑問。假設我在庫中使用test_one資源,那到底是使用庫的資源仍是應用的資源?答案是應用的資源,因爲庫被合併到應用後。庫的R文件資源id值都發生了變化。
而咱們用R文件去訪問資源的時候。都是拿變化後的R文件去訪問,因此假設有資源衝突默認都是以應用資源爲準。因此這裏我也可以得出還有一個結論:
當庫和應用模塊資源衝突的情形下,不管在應用中仍是在庫中使用該資源。都默認以應用資源爲主。前提是應用模塊有依賴該庫模塊。
因此爲了不常用資源 ID 的資源衝突。請使用在模塊(或在所有項目模塊)中具備惟一性的前綴或其它一致的命名方案。
比方庫名是PullToRefresh。那麼該庫下的資源命名可以用ptr做爲前綴。
關於R文件:
R文件(R.java)是由Android 資源打包工具AAPT(Android Asset Packaging Tool))本身主動生成,包括了res文件夾下所有資源的Id。每當建立一個新資源,會本身主動地在R文件里加入該資源的id。咱們可以在代碼中使用該id,執行不論什麼有關該資源的操做。注意,假設咱們手動刪除R文件。編譯器會本身主動建立。
R文件是一個java文件,因爲它是被本身主動建立的,因此Android studio 會把它進行隱藏,詳細位置在 app/build/generated/source/r/debug
當Library模塊中存在私有資源,假設應用模塊資源名和私有資源名衝突了,編譯器會發出警告:
當咱們在應用中使用該資源時,也會發出該警告:
儘管咱們使用該資源時用的是應用模塊的資源。但是庫已經把test_one標爲私有資源,爲了規範化。我可以採取例如如下措施:
<resources xmlns:tools="http://schemas.android.com/tools">
<string name="app_name">MyTestTwo</string>
<string name="test_one" tools:override="true">My name is App</string>
</resources>
此方式並沒有法取消私此資源是私有資源的狀態,僅僅只是取消了資源文件裏的警告而已。
當應用依賴庫時,應用的assert文件夾會和庫的asserts文件夾進行合併,假設有一樣路徑文件,則以應用模塊的爲準。好比,應用模塊存在asserts/ha.json文件,庫模塊下也有asserts/ha.json文件,因爲兩個路徑同樣。當合並後apk中僅僅保留應用模塊asserts/ha.json。假設庫模塊的ha.json文件是存放在assert/json文件夾下。那麼當合並後,兩個json文件都存在。 因爲它們路徑不同。一個是asserts/ha.json 還有一個是asserts/json/ha.json。
谷歌官方說:工具不支持在庫模塊中使用原始資源文件(保存在 assets/ 文件夾中),但是通過個人測試,在應用模塊中可以任意使用庫中的assets資源並沒有不論什麼問題。
關於asserts文件夾
Android資源文件大體可以分爲兩種:
第一種是res文件夾下存放的可編譯的資源文件:這樣的資源文件系統會在R.java裏面本身主動生成該資源文件的ID,因此訪問這樣的資源文件比較簡單。經過R.XXX.ID就能夠;
另一種是assets文件夾下存放的原生資源文件:
因爲系統在編譯的時候不會編譯assets下的資源文件。因此咱們不能經過R.XXX.ID的方式訪問它們。那我麼能不能經過該資源的絕對路徑去訪問它們呢?因爲apk安裝以後會放在/data/app/**.apk文件夾下。以apk形式存在,asset/res和被綁定在apk裏,並不會解壓到/data/data/YourApp文件夾下去。因此咱們沒法直接獲取到assets的絕對路徑。因爲它們根本就沒有。
還好Android系統爲咱們提供了一個AssetManager工具類。查看官方API可知,AssetManager提供相應用程序的原始資源文件進行訪問;這個類提供了一個低級別的API。它贊成你以簡單的字節流的形式打開和讀取和應用程序綁定在一塊兒的原始資源文件。
庫做爲相關應用模塊的一部分編譯,所以。庫模塊中使用的 API 必須與應用模塊支持的平臺版本號兼容。
在您構建相關應用模塊時,庫模塊將先編譯到 AAR 文件裏。而後再加入到應用模塊中。所以,每個庫都有其本身的 R 類,並依據庫的軟件包名稱命名。
從主模塊和庫模塊生成的 R 類會在所需的所有軟件包(包括主模塊的軟件包和庫的軟件包)中建立。
經過將 ProGuard 配置文件加入到包括其 ProGuard 指令的庫,您可以在本身的庫上啓用代碼壓縮。構建工具會爲庫模塊將此文件嵌入到生成的 AAR 文件裏。在您將庫加入到應用模塊時,庫的 ProGuard 文件將附加至應用模塊的 ProGuard 配置文件 (proguard.txt)。
經過將 ProGuard 文件嵌入到您的庫模塊中。您可以確保依賴於此庫的應用模塊沒必要手動更新其 ProGuard 文件就可使用庫。當 ProGuard 在 Android 應用模塊上執行時。它會同一時候使用來自應用模塊和庫的指令,所以您不該當僅僅在庫上執行 ProGuard。
要指定您的庫的配置文件名,請將其加入到 consumerProguardFiles 方法中,此方法位於您的庫的 build.gradle 文件的 defaultConfig 塊內。好比,下面片斷會將 lib-proguard-rules.txt 設置爲庫的 ProGuard 配置文件:
android {
defaultConfig {
consumerProguardFiles 'lib-proguard-rules.txt'
}
...
}
默認狀況下,應用模塊會使用庫的公佈構建,即便在使用應用模塊的調試構建類型時亦是如此。要使用庫中不一樣的構建類型,您必須將依賴項加入到應用的 build.gradle 文件的 dependencies 塊中。並在庫的 build.gradle 文件裏將 publishNonDefault 設置爲 true。好比。您應用的 build.gradle 文件裏的下面代碼段會使應用在應用模塊於調試模式下構建時使用庫的調試構建類型,以及在應用模塊於公佈模式下構建時使用庫的公佈構建類型:
dependencies {
debugCompile project(path: ':library', configuration: 'debug')
releaseCompile project(path: ':library', configuration: 'release')
}
您還必須在本身庫的 build.gradle 文件的 android 塊內加入下面代碼行。以便將此庫的非公佈配置展現給使用它的項目:
android {
...
publishNonDefault true
}
只是請注意。設置 publishNonDefault 會添加構建時間。
爲了確保您的庫的 ProGuard 規則不會將意外的壓縮反作用施加到應用模塊,請僅包括適當規則,停用不適用於此庫的 ProGuard 功能。
嘗試協助開發人員的規則可能會與應用模塊或它的其它庫中的現有代碼衝突,所以不該包括這些規則。好比。您的庫的 ProGuard 文件可以指定在應用模塊的壓縮期間需要保留的代碼。
注:Jack 工具鏈僅支持 ProGuard 的部分壓縮和模糊選項
https://developer.android.com/studio/projects/android-library.html#aar-contents
http://www.jianshu.com/p/59efa895589e
http://tikitoo.github.io/2016/05/26/android-studio-gradle-build-run-faster/
http://blog.csdn.net/z1074971432/article/details/38912747