標籤:絕對路徑 eve 添加 操作 ring service 建立 compile hive
關於建立Android Library所須要知道的一切
Android 庫(Library)在結構上與 Android 應用模組同樣。應用模組所能夠包括的東西。在庫中都同意存在,包括代碼檔案、資源檔和manifest檔案等。
應用模組編譯後產生的是一個apk檔案,能夠直接在裝置上執行,可是,庫模組編譯後產生的是一個Android Archive檔案,簡稱AAR。
AAR檔案無法像apk檔案一樣直接在裝置上執行,我們一般用它作為Android app的依賴。
普通JAR檔案僅僅能包括代碼檔案和資訊清單檔,而ARR檔案不僅能夠包括代碼檔案。還能夠包括Android的資源檔和manifest檔案。這樣。我們就能夠把資源檔像布局檔案、圖片檔案等和Java代碼檔案一起分享出去。能夠說ARR檔案是真正專屬於Android的“JAR”包。
庫模組在下面情況下非常實用:
- 建立多個app。這些app須要使用多個同樣的組件。像activity、service或UI 布局等。
- 建立一個app。而這個app可能須要依據須要編譯成多個APK版本號碼,比方免費版和付費版,而兩個版本號碼都須要使用到同樣的組件。
在不論什麼一種情況下,你僅僅須要將要重用的檔案放到庫模組中,然後以依賴項的形式為每一個應用模組加入庫就可以。
建立庫模組
在你的工程中,建立一個新的庫模組。能夠遵循例如以下的步驟:
- 點擊 File > New > New Module.
- 在Create New Module的表單中。選擇Android Library。並點擊下一步(Next)。
在該表單中還有一個選項用於建立一個Java Library,Java Library就是我們所知的傳統的JAR檔案。JAR檔案在非常多工程中十分實用,尤其當你想分享代碼給其它工程的時候。可是JAR檔案並不同意包括Android資源檔和manifest檔案,而資源檔在Android項目中對代碼重用具有非常大的協助。所以本篇主要對Android庫作介紹。
- 為你的庫命名並選擇最低SDK版本號碼號,然後點擊Finish,完畢建立。
僅僅要Gradle同步完畢後,庫模組就會出現左邊的工程面板中。
應用模組轉成庫模組
假設你有一個已經存在的應用模組。並想重用它的全部代碼。你能夠把它轉成一個庫模組:
1.開啟屬於該應用模組下的build.gradle檔案,在最頂部,你能夠看見例如以下的顯示:
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檔案夾,專門用於存放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的模組下才幹被識別。
產生AAR檔案
我們能夠通過點擊Build > Make Project產生aar檔案,aar檔案會在project-name/module-name/build/outputs/aar/ 下產生。普通情況下會有兩個aar檔案,一個debug版本號碼。一個release版本號碼。
當我們拿到後aar檔案後。就能夠把它公布出去。其它小夥伴就能夠利用上面的方式引入aar檔案到工程中了。
AAR檔案解刨
AAR 檔案的副檔名為 .aar,該檔案本身就是一個zip檔案,必須要包括下面內容:
- /AndroidManifest.xml
- /classes.jar
- /res/
- /R.txt (由R.java轉換而來)
此外,AAR檔案可能包括下面可選條目中的一個或多個:
- /assets/
- /libs/name.jar
- /jni/abi_name/name.so(當中 abi_name 是 Android 支援的 ABI 之中的一個)
- /proguard.txt
- /lint.jar
庫的私人資源
預設情況下庫中的全部資源都是公開狀態。也就是說同意應用模組直接訪問。可是假設你想讓庫中的資源僅供內部使用,而不想暴露給外部。您應通過聲明一個或多個公開資源的方式來使用這樣的自己主動私人標識機制。資源套件括您項目的 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=0x7f020001、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:7f040002App:My name is AppLibrary:7f040002Library:My name is AppLibrary:7f040001Library: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標為私人資源,為了正常化。我能夠採取例如以下措施:
- 在應用模組中更換不同的資源名。不要與庫中的資源名一樣。
- 假設真的要使用同名資源,使用tools標記為重寫狀態:
<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>
此方式並無法取消私此資源是私人資源的狀態,僅僅只是取消了資源檔裡的警告而已。
asserts合并衝突
當應用依賴庫時,應用的assert檔案夾會和庫的asserts檔案夾進行合并,假設有同樣路徑檔案,則以應用模組的為準。比如,應用模組存在asserts/ha.json檔案,庫模組下也有asserts/ha.json檔案,由於兩個路徑一樣。當合并後apk中僅僅保留應用模組asserts/ha.json。假設庫模組的ha.json檔案是存放在assert/json檔案夾下。那麼當合并後,兩個json檔案都存在。 由於它們路徑不一樣。一個是asserts/ha.json 還有一個是asserts/json/ha.json。
Google官方說:工具不支援在庫模組中使用原始資源檔(儲存在 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。它同意你以簡單的位元組流的形式開啟和讀取和應用程式綁定在一起的原始資源檔。
應用模組的 minSdkVersion 必須大於或等於庫定義的版本號碼
庫作為相關應用模組的一部分編譯,因此。庫模組中使用的 API 必須與應用模組支援的平台版本號碼相容。
每一個庫模組都會建立自己的 R 類
在您構建相關應用模組時,庫模組將先編譯到 AAR 檔案裡。然後再加入到應用模組中。因此,每一個庫都有其自己的 R 類,並依據庫的軟體包名稱命名。
從主模組和庫模組產生的 R 類會在所需的全部軟體包(包括主模組的軟體包和庫的軟體包)中建立。
庫模組可能包括自己的 ProGuard 設定檔
通過將 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
關於建立Android Library所須要知道的一切