編輯:Android資訊
Android 庫(Library)在結構上與 Android 應用模塊相同。應用模塊所可以包含的東西,在庫中都允許存在,包括代碼文件、資源文件和manifest文件等。
應用模塊編譯後生成的是一個apk文件,可以直接在設備上運行,但是,庫模塊編譯後生成的是一個Android Archive文件,簡稱AAR。AAR文件無法像apk文件一樣直接在設備上運行,我們一般用它作為Android app的依賴。
普通JAR文件只能包含代碼文件和清單文件,而ARR文件不僅可以包含代碼文件,還可以包含Android的資源文件和manifest文件。這樣,我們就可以把資源文件像布局文件、圖片文件等和Java代碼文件一起分享出去。可以說ARR文件是真正專屬於Android的“JAR”包。
庫模塊在以下情況下非常有用:
在任何一種情況下,你只需要將要重用的文件放到庫模塊中,然後以依賴項的形式為每個應用模塊添加庫即可。
在你的工程中,創建一個新的庫模塊,可以遵循如下的步驟:
只要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.添加庫到工程中有兩種方式(如果你是在相同項目中創建的庫模塊,則該模塊已經存在,您可以跳過此步驟)
這兩種引入庫的方式有所不同。如果直接引入的是庫模塊,你可以對庫的代碼進行編輯。但是如果導入的是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 的資源沖突,請使用在模塊(或在所有項目模塊)中具有唯一性的前綴或其他一致的命名方案。
我們舉個例子來證明觀點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: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 的部分壓縮和模糊選項
本文由碼農網 – 小峰原創翻譯,轉載請看清文末的轉載要求,歡迎參與我們的付費投稿計劃! 移動開發變得越來越受歡迎,但移動開發者正面臨著一系列挑戰。本文將介
Button,就是按鈕,是android中應用最多的組件之一,Button有兩種用法,一種是XML中配置,另一種是在程序中直接使用 在XML布局文件裡,會遇到如下
關於Android View控件 Android中控件大致被分為兩類ViewGroup,View。ViewGroup作為容器管理View。Android視圖,是類
在Android應用中, Activity是最核心的組件, 如何生成一個Activity實例, 可以選擇不同的啟動模式, 即LaunchMode. 啟動模式主要包