Android Studio創建JAR/AAR庫


[時間:2017-09] [狀態:Open]
[關鍵詞:Android,Android Studio,gradle,jar,aar,library]

0 引言

最近在工作中遇到了升級Android Studio 2.3.3穩定版之后,無法編譯jar包的問題。之后尋找AS文檔-探索 Android Studio發現。可以通過AS創建和編譯jar包,順便看到支持原生開發,可以直接在AS中調試c/c++代碼,這是非常不錯的功能。終於可以擺脫純打日志的開發環境了。

本系列文章也就因此而出現。我希望閱讀文本文之后,大家能夠基本了解如何使用新版的Android Studio開發原生引用。
這里說明一點,本文是參考谷歌的Android Studio官網來的,也可以認為是一種翻譯版。可以訪問的話你可以直接查看對應內容。

這是第三篇:使用Android Studio創建庫文件(Java)。(嚴格來說這跟原生開發沒什么關系,但是為了完整的完成我最初的目標,還是整理下此文吧。)

1 環境准備

請參考本系列的第一篇:原生庫示例創建及驗證中的要求,安裝和更新Android Studio。

2 Android庫簡介

Android庫在結構上與app module等價。它可以包含所有用於構建app的東西,包括源碼、資源文件和Android manifest。Android庫不是直接編譯成可在設備上執行的APK文件,而是編譯為AAR(Android Archive)文件,你可以將該文件作為app module的依賴項。和JAR包不同的是,AAR文件可以包含Android資源和manifest文件,這就是說除了Java類和方法之外,AAr還支持打包諸如layouts和drawables之類的共享資源。
Android庫模塊在以下情況下很有用:

  • 當你在構建多個使用相同組件的app時,比如Activity、service或UI layout。
  • 當你基於多個APK變種構建app時,例如免費版和付費版,他們共享同樣的核心組件。

在以上了兩種情況中,只要簡單的把需要重用的文件放到庫模塊中,然后在app module中添加該庫作為依賴項就可以了。本文將告訴你如何實現這些。

3 新建庫模塊

AS中新建一個庫模塊,步驟如下:

  1. 點擊菜單中的 File > New > New Module
  2. 在Create New Module窗口中,選擇Android Library,點擊Next。
    • 這里也可以選擇新建Java庫,也就是構建傳統的JAR包。
  3. 給你的庫選擇一個名字,並選擇一個最低SDK版本,之后點擊Finish。
    當Gradle完成工程同步,庫模塊就會顯示在工程面板中。

4 將現在app module轉為庫模塊

可以參考下列步驟:

  1. 打開module層的build.gradle文件

  2. 刪除applicationId這一行,這個標志只能在Android app module中定義。

  3. 在該文件的開頭,你應該能看到下面內容:

    apply plugin: 'com.android.application'

    將其更改為:

    apply plugin: 'com.android.library'

  4. 保存該文件,並點擊菜單中的Tools > Android > Sync Project with Gradle Files。

這就搞定了。整個模塊的結構是不變的,但現在它是以Android庫運行的,構建時會新建一個AAR文件,而不是APK。

5 配置AAR作為依賴項

在其他app module中使用Android庫時,需要按照下面方式配置:

  1. 使用以下兩種方式將庫添加到你的工程中(如果你在同一個工程中新建了庫模塊,你可以跳過此步驟):
    • 添加編譯好的AAR/JAR文件(該庫必須已經構建好)
      1. 點擊菜單中的File > New > New Module。
      2. 點擊Import .JAR/.AAR Package,並點擊Next。
      3. 輸入編譯好的AAR/JAR文件的路徑,並點擊Finish。
    • 將庫模塊導入到你的工程(庫源代碼將成為你工程的一部分)
      1. 點擊菜單中的File > New > Import Module.
      2. 輸入庫模塊的目錄,並點擊Finish。
        The library module is copied to your project, so you can actually edit the library code. If you want to maintain a single version of the library code, then this is probably not what you want and you should instead add the compiled AAR file as described above.
  2. 檢查下你的settings.gradle文件中新加入的庫是否在其中,如下面所示添加了"my-library-module":
    include ':app', ':my-library-module'
  3. 打開app module的build.gradle文件,並在dependencies塊中添加一行,如下代碼片段所示:
    dependencies {
        compile project(":my-library-module")
    }
    
  4. 點擊Sync Project with Gradle Files

在上面示例中,編譯配置中添加了一個名為my-library-module的庫作為整個app module的構建依賴項。如果你希望在特定構建變量上需要該庫,不要使用compile,而是使用buildVariantNameCompile命令。例如,如果你只想在"pro"產品中包含該庫,你需要這樣編寫:

productFlavors {
    pro { ... }
}
dependencies {
    proCompile project(":my-library-module")
}

通過上述設置之后,Android庫中所有的代碼和資源都可以在app module中訪問了,在構建時,對應庫的AAR文件會被打包到APK中。
如果你需要單獨共享AAR文件,你可以在project-name/module-name/build/outputs/aar/中找到它,你可以通過菜單中的Build > Make Project重新構建它。

7 在庫中發布非默認的variant

默認情況下,庫模塊僅發布和暴露"release"構建variant下的資源給其他Android工程/module。也就是說,如果app module將該庫作為依賴項,即使在debug版本下的app也只能訪問該庫的"release"variant。然后,你可以通過在庫的build.gradle文件中添加下面命令使得Gradle可以訪問"debug"構建variant下的資源:

android {
  ...
  // Sets the "debug" build variant as the default variant
  // of the library that Gradle should publish.
  defaultPublishConfig "debug"
}

這樣配置之后,Gradle將發布"debug"構建variant下的資源。然而,如果庫模塊使用product flavors,你就需要配defaultPublishConfig屬性,並使用全配置名來指定構建variant(否則,Gradle將不會發布你的庫,因為傳統的"release"及"debug" variant已經不存在了)。下面示例展示了如何組合使用 "demo" product flavor和"debug"構建類型的導出構建variant:

android {
  ...
  defaultPublishConfig "demoDebug"
}

謹記:如果你正在構建用於發布app的release版本,你需要修改defaultPublishConfig以使用庫的release variant對應的資源。同樣的,你可以設置Gradle來發布和暴露庫中所有可用的variant,同時每個app variant僅使用其需要variant的資源。在庫的build.gradle文件中添加以下行可以讓Gradle發布庫中所有的variants:

android {
  ...
  // Tells Gradle to build all variants of the library. Note that this
  // may increase build times because Gradle must build multiple AARs,
  // instead of only one.
  publishNonDefault true
}

現在你可以通過修改你的app的build.gradle文件的dependencies塊來訪問庫中所有可見的variants。下面位於app module的build.gradle文件中的代碼片段指示Gradle在構建app的"demoDebug"版本時使用庫的"demoDebug" variant,並在構建app的"fullRelease"版本時使用"fullRelease" variant。

android {...}
...

// Creates Gradle dependency configurations to use in the dependencies block.
configurations {
  // Initializes placeholder configurations that the Android plugin can use when targeting
  // the corresponding variant of the app.
  demoDebugCompile {}
  fullReleaseCompile {}
  ...
}

dependencies {
  // If the library configures multiple build variants using product flavors,
  // you must target one of the library's variants using its full configuration name.
  demoDebugCompile project(path: ':my-library-module', configuration: 'demoDebug')
  fullReleaseCompile project(path: ':my-library-module', configuration: 'fullRelease')
  ...
}

8 選擇作為public的資源

默認情況下庫中所有的資源都是public的。為了將所有資源默認設置為private,你需要至少定義一個特殊屬性作為public。資源包括你的工程下的res目錄中的所有文件。為了阻止庫的用戶訪問僅供內部使用的資源,你需要使用自動private設計機制,聲明一個或多個public資源。同時,你可以把所有資源設置為private,只要添加一個空的<public />標簽即可,這個標簽主要是標記不存在public資源,也就是所有資源都是private的。
為了聲明一個public資源,在庫的public.xml中添加一個 聲明。如果你之前沒有添加過public資源,你需要在res/values/目錄下創建一個public.xml文件。
下面示例代碼創建了兩個public字符串:mylib_app_name和mylib_public_string:

<resources>
    <public name="mylib_app_name" type="string"/>
    <public name="mylib_public_string" type="string"/>
</resources>

你需要保證中那些使用你的庫的開發者可以訪問的資源設置為public。例如,v7 appcompat庫中大多數資源是private的,但是控制Toolbar widget的屬性是public的,以支持material design

隱式地將屬性設置為private不僅可以防止庫的用戶得到內部庫資源的代碼自動補全提示,而且允許你在不破壞客戶端的前提下重命名或刪除private資源。private資源會被代碼自動補全和theme editor自動過濾掉,並且Lint在你引用private資源時會給出警告信息。
在構建庫時,Android Gradle插件將會獲取public資源定義,並將其提取到public.txt文件中,此文件會被打包到AAR文件中。

9 開發考量

在你開發庫模塊和依賴庫的app時,請留心以下行為和限制。
一旦在Android app module中添加了對庫模塊的引用,你就可以設置其相對優先級。在編譯時,庫模塊會一個個合並到app中,按照優先級的高低順序合並。

  • 資源合並沖突
    構建工具會將庫模塊的資源和其所依附的app module進行合並。如果給定的資源ID在兩個module中都有定義,則使用app中的資源。
    如果在多個AAR庫中發生沖突,那么在dependencies列表中第一個出現(在dependencies塊的頂部)的資源會被使用。
    為了避免通用資源ID的沖突,可以考慮使用前綴或者統一命名方案,以保證每個module的名字都是唯一的(或在整個工程module中是唯一的)。
  • 庫模塊可以包含JAR包
    你可以開發一個本身包含JAR包的庫模塊;然而,你需要對依賴該庫的app module進行手工編輯構建路徑,並添加該JAR包所在路徑。
  • 庫模塊可以依賴外部的JAR包
    你可以開發一個依賴外部庫的庫模塊。(例如,Maps外部庫)。在這種情況下,依賴該庫的app在構建時必須使用一個包含該外部庫(例如,Google API Add-on)的target。需要注意的是,在庫模塊和app module的manifest文件中必須聲明該外部庫,使用 元素。
  • 庫模塊不能包含原始asset
    在庫模塊中,工具並不支持使用原始asset文件。app中使用的任何asset資源必須保存在其assets/目錄下。
  • app module的minSdkVersion必須大於等於庫中定義的版本。
    一個庫被編譯為app module的一部分,所以在庫中使用的API必須與app module支持的平台版本兼容。
  • 每個庫模塊都可以創建單獨的R類
    在你構建有庫依賴的app module時,庫模塊首先被編譯到AAR文件中,然后添加到app module中。因此,每個庫都有其自己的R類,其命名是按照庫的包名確定的。從主模塊和庫模塊生成的R類在所有包中創建,這些都是會包含在主模塊包中和庫的包中。
  • 庫模塊可以包含自己的ProGuard配置文件
    你可以在庫上實現代碼縮減,通過在你的庫中添加ProGuard配置文件,其中包含了ProGuard指令。構建工具會把這個文件嵌入到生成的AAR文件中。當你把該庫添加到app module之后,庫的ProGuard文件會被添加到app Module的ProGuard配置文件(proguard.txt)中。
    通過在你的庫模塊中嵌入一個ProGuard文件,你可以確保那些依賴於該庫的app module在使用你的庫是無需手動更新他們的ProGuard文件。當ProGuard在Android app module上執行時,它會自動使用來自app module和庫中的指令,這樣你就不用單獨執行庫中的配置文件了。
    為了指定你的庫配置文件的名字,在consumerProguardFiles方法中添加下參數,該方法在你的庫的build.gradle文件中的defaultConfig塊中。例如,下面代碼段將lib-proguard-rules.txt作為該庫的ProGuard配置文件:
android {
    defaultConfig {
        consumerProguardFiles 'lib-proguard-rules.txt'
    }
    ...
}

為了保證你的庫中的ProGuard規則不會對app module中的代碼縮減產生副作用,只包含那些在你的庫中不工作的禁用ProGuard功能的規則。那些用於輔助開發者的規則可能會與app module或其他庫有沖突,因此不可以包含類似規則。例如,你庫的ProGuard文件可以指定在app module最小化時那些代碼可以保留。

  • 測試庫模塊和測試app一樣
    主要區別在於庫和它的依賴項是自動作為測試APK的依賴項的。這意味着,測試APK包含了不僅僅是它自身的代碼,還有庫的AAR及庫的依賴項。因為並不存在獨立的“測試下的app”,androidTest任務僅安裝(和卸載)測試APK。
    在合並多個manifest文件時,Gradle將遵循默認優先級規則,並將庫的manifest依次合並到測試APK的主manifest中。

10 AAR文件剖析

AAR文件的文件擴展名是.aar,對應的Maven生成的類型也應該是aar。該文件本身是一個zip文件,包含下列必須條目:

/AndroidManifest.xml
/classes.jar
/res/
/R.txt
/public.txt

另外,AAR文件可以包含一個或多個下列可選條目:

/assets/
/libs/name.jar
/jni/abi_name/name.so (where abi_name is one of the Android supported ABIs)
/proguard.txt
/lint.jar

11 小結及后續

本文作為Android創建的第三篇,整體比較簡單,內容主要是翻譯部分,整理並介紹了如何使用AS構建JAR包。僅供后續參考。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM