Android Library在目录结构上与Android App相同,它能包含构建APP所需的一切(如源代码、资源文件、Android Manifest)。Android App最终被编译打包成能在Android设备上运行的APK文件,但是Android Library被编译成供其它Android App依赖的Android Archive (AAR)文件。Java Library最终被编译打包成Java Archive(JAR)文件,它不能打包Android资源文件,但是Android Library不仅能打包Java文件还能打包Android资源文件。
1、 当你需要向其它APP提供一个通用模块时。例如:你需要向其它APP提供通用的账户管理模块。
2、 当你需要构建不同的APK,但这些APK有共同核心功能时。例如:你的APP有免费版和付费版,但是它们有相同的核心功能。
在这两种情况下,只需将要重用的文件移动到Android Library中,然后将library添加为每个APP模块的依赖项,APP就能直接调用library中的功能,而不需要关心library的具体实现。
在你的Project中创建一个Android Library Module的步骤如下:
1、 点击File > New > New Module
2、 在Create New Module窗口中点击Android Library,然后点击Next。
3、 给library命名(如My Library)并设置minimum SDK version。
Gradle同步完成后你就能在左侧的Project面板中看到新建的library了,如图1所示:
如果你的App Module的全部代码都可以重用,那么你可以把这个App Module转换成Android Library Module,步骤如下:
1、 打开App Module的build.gradle
文件。
2、 删除applicationId
这一行。只有App Module才需要定义applicationId
。
3、 把文件顶部的
apply plugin: 'com.android.application'
改为
apply plugin: 'com.android.library'
4、 保存文件,点击Tools > Android > Sync Project with Gradle Files。
这样就完成了App Module到Android Library Module的转换。转换后Module的整个结构不变,但是它已经是一个Android Library Module了,编译后将生成AAR文件,而不是APK文件。在Project面板中选中Library Module,然后点击Build > Build APK,就能编译生成对应的AAR文件到build>outputs>aar目录。
在其它App Module中使用Android Library中的代码的步骤如下:
1、 通过以下任一种方式将Android Library添加到您的Project中(如果您的Android Library就在您的Project中,那么请跳过此步骤)。
方法一:添加编译生成的AAR文件到Project。
a、 点击File > New > New Module。
b、 点击Import .JAR/.AAR Package,然后点击Next。
c、 输入AAR文件的路径,然后点击Finish。
方法二:Import Android Library到Project(library的源代码就成了Project的一部分)。
a、 点击File > New > Import Module。
b、 输入library的目录地址,然后点击Finish。
这样library就被copy到Project,且你可以编辑library的代码。如果你想只维护一份library的代码,那么应该使用方法一,而不应该使用方法二。
2、 确认已在settings.gradle
中配置好library,如:
include ':app', ':mylibrary'
3、 打开App Module的build.gradle
文件,并在dependencies
中做好配置,如:
dependencies {
compile project(":mylibrary")
}
4、 点击Sync Project with Gradle Files。
上述例子中,在App Module用compile添加了名为mylibrary的library作为依赖,如果你只需在特定的产品版本上使用这个library,那么可以用buildVariantNameCompile
替代compile
。例如,你只想在”pro”版本上依赖mylibrary,那么应该做如下配置:
productFlavors {
pro { ... }
}
dependencies {
proCompile project(":mylibrary")
}
完成上述步骤后,App Module就能访问Android Library中的代码和资源了,并且编译时AAR文件会被打包进APK中。如果你需要获取AAR文件,你可以点击Build > Make Project生成它,并在project-name/module-name/build/outputs/aar/中找到它。
Android Library按照编译方式可分为“release”、“debug”版本;按照不同的产品可分为“demo”、“full”版本等。默认情况下,Android Library只向其它Android Project和App Module发布“release”版本。也就是说,如果一个App Module依赖这个Android Library,即使最终编译出的APP为“debug”版本,这个Android Library仍发布“release”版本。然而,你可以在library的build.gradle
文件里把library配置为默认发布“debug”版本,如下所示:
android {
...
// 设置library的发布版本默认为“debug”
defaultPublishConfig "debug"
}
现在library总是向其它Module发布“debug”版本,但是如果library需要发布不同的产品版本,那么你需要同时给defaultPublishConfig
设置编译方式和产品版本。下面的例子给library设置的产品版本为“demo”,编译方式为“debug”:
android {
...
defaultPublishConfig "demoDebug"
}
你也可以把library设置为发布所有版本,那么每个版本的app就可以使用对应的library版本,如下所示:
android {
...
//告诉Gradle编译library的所有版本。
//需要注意的是:因为Gradle需要编译多个AAR,而不是只编译一个AAR,所以这样会增加编译时间。
publishNonDefault true
}
接下来,你需要在app的build.gradle
文件里配置dependencies
,使app使用适合的library版本。例如在app的build.gradle
里配置:当编译app的“demoDebug”版本时,使用library的“demoDebug”版本;当编译app的“fullRelease”时,使用library的“fullRelease”版本。如下所示:
android {...}
...
configurations {
demoDebugCompile {}
fullReleaseCompile {}
...
}
dependencies {
// 如果library配置了多个版本,那么你必须在app中配置使用library的哪个版本
demoDebugCompile project(path: ':mylibrary', configuration: 'demoDebug')
fullReleaseCompile project(path: ':mylibrary', configuration: 'fullRelease')
...
}
Android Library中的所有Resource(res/
目录中的所有文件)默认是public属性。要使所有资源是private属性,那么必须至少将一个特定属性定义为public属性。为了防止library的用户访问library的内部资源,你需要通过申明一个或多个public资源来使library内的其它资源私有化。或者你可以通过添加空的
标签使library的所有资源私有化。
如果你想让某些资源对library的使用者是public的,请先在library的res/values/
文件夹下新建一个public.xml
文件,然后在library的public.xml
文件中添加
标签。如把library中名为mylib_app_name
和mylib_public_string
的两个字符串资源申明为public属性:
<public name="mylib_app_name" type="string"/>
<public name="mylib_public_string" type="string"/>
私有资源不会有代码补全建议,且当你非法访问一个私有资源时theme editor和lint都会有相应警告。资源私有化不仅防止library的使用者遇到来自library资源的代码补全建议,而且允许你对library的资源进行重命名或删除,而不用考虑对library用户的兼容性。编译Android Library时,Android Gradle plugin会搜集所有public资源并导入到public.txt文件中,最终打包进AAR文件。
App Module添加依赖Android Library时可以设置library的优先级,在编译时,app按照library从低到高的优先级依次与每个library合并。开发Android Library和相关APP时,请注意下面事项:
•资源合并冲突
编译工具会合并library和app的资源。如果某个resource ID在两个Module中都定义了,那么会使用app的资源。
如果冲突发生在多个AAR之间,那么会优先使用dependencies列表中排在前面的library的资源。
为了防止Module直接资源冲突,请给每个Module的资源使用唯一的前缀或命名空间,就像用包名唯一确认一个APP一样。
•Android Library可以包含JAR Library
可以在Android Library中使用JAR Library,并且依赖这个Android Library的App Module也需要配置好对这个JAR Library的引用。
•Android Library可以依赖external JAR library
Android Library可以依赖external JAR library,如一个地图的external library,那么依赖这个Android Library的App Module编译时必须要依赖包含这个external library的target,如Google APIs Add-On。Android Library Module和App Module都必须要在Manifest文件中用
申明使用这个external library。
•App Module的minSdkVersion必须等于或大于Android Library的minSdkVersion。
Android Library是作为App Module的一部分被编译的,所以它使用的API必须要与App Module支持的平台版本相匹配。
•每个Android Library独自创建其R class
当编译App Module时,Android Library被编译成AAR文件然后被添加到App Module。所以每个Android Library有其独有的R class,并根据其包名命名。App Module和Android Library的R class被生成长它们各自的package下。
•Android Library可以有独自的ProGuard配置文件
每个Android Library可以有自己的ProGuard配置文件,编译工具会把这个文件嵌入到生成的AAR文件中。当Android Library添加到App Module时,library的ProGuard文件会附加到App Module的ProGuard文件。当App Module运行ProGuard文件时,它会运行App和library的ProGuard文件,所以你不需要单独运行library的ProGuard文件。
在library的build.gradle
中用consumerProguardFiles
配置library的ProGuard文件,如下所示把lib-proguard-rules.txt
配置为library的ProGuard文件:
android {
defaultConfig {
consumerProguardFiles 'lib-proguard-rules.txt'
}
...
}
•测试Android Library与测试App一样
主要的不同是Android Library和它依赖的dependencies自动被包含成Test APK的依赖项。即Test APK不仅包含其自身的代码,还包含Android Library的AAR和相关依赖。因为没有单独的”app under test”,所以androidTest任务只安装/卸载Test APK。
当合并多个Manifest文件时,Gradle按照默认的优先级顺序把library的manifest合并到APP的manifest。
AAR文件的后缀名是.aar,且在Maven中的类型也是aar。AAR文件本身是一个zip文件,包括下面内容:
•/AndroidManifest.xml
•/classes.jar
•/res/
•/R.txt
•/public.txt
通常AAR文件可能包含下面的一个或多个可选文件
•/assets/
•/libs/name.jar
•/jni/abi_name/name.so ( abi_name 是Android 支持的一种ABI)
•/proguard.txt
•/lint.jar