Create an Android library


创建 Android 库

[Create an Android library]
Android 库在结构上与 Android app module 相同。它可以提供构建应用所需的一切内容,包括源代码、资源文件和 Android 清单。不过,Android 库将编译到您可以用作 Android app module 依赖项的 Android Archive(AAR) 文件,而不是在设备上运行的 APK。与 JAR 文件不同,AAR 文件可以包含 Android 资源和一个清单文件,这样,除了 Java 类与方法外,您还可以共享 layouts and drawables 等资源。

库模块在以下情况下非常有用:
  • 构建使用某些相同组件[components]的多个应用,例如 activities, services, or UI layouts。
  • 构建存在多个 APK 变体的应用并且需要在多种版本中使用相同的核心组件。

在任何一种情况下,只需要将您希望重用的文件移动到库模块中,然后以 dependency 的形式为每个应用模块添加库。本页面将说明如何执行这两个操作。

创建库模块

要在您的项目中创建一个新的库模块,请按以下步骤操作:
  • 点击 File > New > New Module。
  • 在出现的 Create New Module 窗口中,依次点击 Android Library 和 Next。
还存在一个用于创建 Java 库的选项,可以构建传统的 JAR 文件。尽管 JAR 文件在大多数项目中都非常实用(尤其在您希望与其他平台共享代码时),但这种文件不允许您包含 Android 资源或清单文件,而后者对于 Android 项目中的代码重用非常有用。因此,本指南将侧重论述创建 Android 库。
1
1
 
1
还存在一个用于创建 Java 库的选项,可以构建传统的 JAR 文件。尽管 JAR 文件在大多数项目中都非常实用(尤其在您希望与其他平台共享代码时),但这种文件不允许您包含 Android 资源或清单文件,而后者对于 Android 项目中的代码重用非常有用。因此,本指南将侧重论述创建 Android 库。
  • 为您的库命名,并为库中代码选择一个最低的 SDK 版本,然后点击 Finish。
在 Gradle 项目同步完成后,库模块将显示左侧的 Project 面板中。如果您未看到新模块文件夹,请确保将视图切换为 Android 视图。

将应用模块转换为库模块

[Convert an app module to a library module]

PS:以下为官方文档中的内容,我感觉说的和笼统,能让新手根本不知道如何操作(甚至有些描述明显是错的),所以建议仅供参考。
如果您现有的应用模块包含您希望重用的所有代码,则可以按照以下步骤将其转换为库模块:
1、打开现有应用模块的 build.gradle 文件。删除 applicationId 的行。 只有Android app模块才能定义此功能。
2、您应在顶部看到以下内容:【apply plugin: ‘com.android.application‘】,将其改成下面的样式:【apply plugin: ‘com.android.library‘】,点击 Sync Project with Gradle Files。
就这么简单。模块的整个结构仍然相同,但是现在它将作为 Android 库,构建也将创建一个 AAR 文件,而不是 APK。
如果要构建AAR文件,请在 Project 窗口中选择库模块,然后单击 Build > Build APK 

简单明了的步骤:
1、创建一个新的普通android工程(New Project 而不是 New Module)
2、修改module层的build.gradle文件,删除 applicationId,将apply plugin: ‘com.android.application‘】改成【apply plugin: ‘com.android.library‘】,然后同步
3、执行 gradle 命令,或者按下图所示点击 app/build/assembleRelease,或者点击 Build > Make Project
Create an Android library  Create an Android library
4、执行完以后可以看到 project-name/module-name/build/outputs/aar/ 文件夹下生成了.aar文件
Create an Android library
修改该.aar文件的后缀名为.zip,解压后,可以看到里面有 classes.jar、AndroidManifest.xml、layout、drawable等各种库中包含的文件
另外,在module层的 intermediates 文件夹下,也生成了二十几个文件夹,你也可以直接用这里生成的(例如.jar文件):
Create an Android library

补充:创建并发布aar到Github仓库

第一步:在Github上创建一个仓库存放aar等文件,例如:
https://github.com/baiqiantao/aartest.git
 
1
https://github.com/baiqiantao/aartest.git

第二步:把仓库clone到本地,并在此目录中创建你的库,编写你的代码,例如目录为:
D:\aartest
1
D:\aartest

第三步:在项目中要打包为aar的build.gradle末尾添加以下代码:
//**********************************************************************   打包发布
apply plugin: ‘maven‘

uploadArchives {
    def GITHUB_REPO_PATH = "D:\\aartest"  // 从Github上clone下来的项目的本地地址,也是要保存的生成的aar目录的地址
    repositories.mavenDeployer {
        repository(url: "file://${file(GITHUB_REPO_PATH).absolutePath}")
        pom.project {  //引用时的格式为【implementation ‘com.bqt.aartest:blibrary:1.0.0‘】
            groupId ‘com.bqt.aartest‘
            artifactId ‘blibrary‘
            version ‘1.0.0‘
        }
    }
}

// 和源代码一起打包
task androidSourcesJar(type: Jar) {
    classifier = ‘sources‘
    from android.sourceSets.main.java.sourceFiles
}
artifacts {
    archives androidSourcesJar
}
 
1
//**********************************************************************   打包发布
2
apply plugin: ‘maven‘
3
4
uploadArchives {
5
    def GITHUB_REPO_PATH = "D:\\aartest"  // 从Github上clone下来的项目的本地地址,也是要保存的生成的aar目录的地址
6
    repositories.mavenDeployer {
7
        repository(url: "file://${file(GITHUB_REPO_PATH).absolutePath}")
8
        pom.project {  //引用时的格式为【implementation ‘com.bqt.aartest:blibrary:1.0.0‘】
9
            groupId ‘com.bqt.aartest‘
10
            artifactId ‘blibrary‘
11
            version ‘1.0.0‘
12
        }
13
    }
14
}
15
16
// 和源代码一起打包
17
task androidSourcesJar(type: Jar) {
18
    classifier = ‘sources‘
19
    from android.sourceSets.main.java.sourceFiles
20
}
21
artifacts {
22
    archives androidSourcesJar
23
}

第四步:构建并上传
在 Gradle > app > Tasks > upload > 双击 uploadArchives
Create an Android library
或者使用命令行进入到项目的根目录后,执行以下命令:
gradlew uploadArchives
x
1
gradlew uploadArchives
然后等待编译完成:
Executing tasks: [uploadArchives]
...
BUILD SUCCESSFUL in 6s
26 actionable tasks: 23 executed, 3 up-to-date
16:18:38: Task execution finished ‘uploadArchives‘.
x
6
1
Executing tasks: [uploadArchives]
2
...
3
BUILD SUCCESSFUL in 6s
4
26 actionable tasks: 23 executed, 3 up-to-date
5
16:18:38: Task execution finished ‘uploadArchives‘.

步:上传源码及生成的文件
编译完成后会在如下目录生成以下一些文件:
Create an Android library
我们将整个目录 add 到 github 仓库,然后提交(项目源码也可以一起提交)。

步:使用此aar
在需要使用此库的 project 的 build.gradle 中添加一下代码:
allprojects {
    repositories {
        ...
        maven { url "https://raw.githubusercontent.com/baiqiantao/aartest/master" } //baiqiantao 为用户名,aartest为项目名,其他为固定值
    }
}
 
1
allprojects {
2
    repositories {
3
        ...
4
        maven { url "https://raw.githubusercontent.com/baiqiantao/aartest/master" } //baiqiantao 为用户名,aartest为项目名,其他为固定值
5
    }
6
}
需要使用此库的 module 的 build.gradle 中添加如下依赖:
implementation ‘com.bqt.aartest:blibrary:1.0.0‘
 
1
implementation ‘com.bqt.aartest:blibrary:1.0.0‘
然后就可以愉快的使用库中的各种资源了:
startActivity(new Intent(this, AARActivity.class));//库中的组件
AARUtils.showToast(this, "库中的方法");
imageView.setImageResource(R.drawable.icon_aar);//库中的资源
x
 
1
startActivity(new Intent(this, AARActivity.class));//库中的组件
2
AARUtils.showToast(this, "库中的方法");
3
imageView.setImageResource(R.drawable.icon_aar);//库中的资源

以依赖项形式添加您的库

[Add your library as a dependency]
要在另一个应用模块中使用您的 Android 库的代码,请按以下步骤操作:
1、通过两种方式之一将库添加到您的项目(如果您是在相同项目中创建的库模块,则该模块已经存在,您可以跳过此步骤):
  • 点击 File > New > New Module > Import .JAR/.AAR Package > Next > 输入或选择 AAR/JAR 文件的位置,设置名称 >  Finish
  • 点击 File > New > Import Module > 输入库模块目录的位置,然后点击 Finish。
    • 通过这种方式添加的库模块将复制到您的项目中,因此您可以尽管编辑库代码。
    • 如果您希望维护一固定个版本[a single version]的库代码,则此方法可能不是您想要的,您应按照上文所述导入编译的 AAR 文件。

2、确保库列在您 settings.gradle 文件的顶部,如下面名为“my-library-module”的库所示:
include ‘:app‘, ‘:my-library-module‘
1
1
 
1
include ‘:app‘, ‘:my-library-module‘

3、打开应用模块的 build.gradle 文件,并向 dependencies 块中添加一行新代码,如下面的片段所示:
implementation project(":my-library-module")
1
1
 
1
implementation project(":my-library-module")
点击 Sync Project with Gradle Files。
ps:可能你会遇到类似如下错误提示:
Manifest merger failed : Attribute application@icon value=(@drawable/icon) from AndroidManifest.xml:6:9-38
	is also present at [:testaar] AndroidManifest.xml:13:9-43 value=(@mipmap/ic_launcher).
	Suggestion: add ‘tools:replace="android:icon"‘ to <application> element at AndroidManifest.xml:5:5-17:19 to override.
这个原因就是合并清单文件时 merger 冲突,按照提示修改即可。
5
5
 
1
ps:可能你会遇到类似如下错误提示:
2
Manifest merger failed : Attribute application@icon value=(@drawable/icon) from AndroidManifest.xml:6:9-38
3
    is also present at [:testaar] AndroidManifest.xml:13:9-43 value=(@mipmap/ic_launcher).
4
    Suggestion: add ‘tools:replace="android:icon"‘ to <application> element at AndroidManifest.xml:5:5-17:19 to override.
5
这个原因就是合并清单文件时 merger 冲突,按照提示修改即可。

在上面的示例中,名为 my-library- module 的 Android 库模块成为 build.gradle 文件所在模块的构建依赖项。
您的应用模块现在可以访问 Android 库中的任何代码和资源,库 AAR 文件在构建时已捆绑到您的 APK 中。

选择要设为公开的资源

[Choose resources to make public]
库中的所有资源在默认情况下均处于公开状态。要将所有资源隐式设为私有,您必须至少将一个特定的属性定义为公开。资源包括您项目的 res/ 目录中的所有文件,例如图像。要阻止您的库用户访问仅供内部使用的资源,您应通过声明一个或多个公开资源的方式来使用这种自动私有标识机制[automatic private designation mechanism]。或者,您可以通过添加一个空的 <public /> 标记来将所有资源设为私有,该标记不会将任何内容标记为公共标记,从而使其他所有资源都设为私密。

要删除某个公开资源,请将一个 <public> 声明添加到您的库的 public.xml 文件中。如果您之前尚未添加公开资源,则需要在您的库的 res/values/ 目录中创建 public.xml 文件。

下面的示例代码可以创建两个名称分别为 mylib_app_name 和 mylib_public_string 的公开字符串资源:
<resources>
    <public name="mylib_app_name" type="string"/>
    <public name="mylib_public_string" type="string"/>
</resources>
4
4
 
1
<resources>
2
    <public name="mylib_app_name" type="string"/>
3
    <public name="mylib_public_string" type="string"/>
4
</resources>
如果希望任何资源保持对使用您的库的开发者可见[remain visible],您应当将其设为公开。例如,尽管 v7 appcompat 库中的大多数资源都是私有资源,但是为了支持 Material Design,控制工具栏小部件的属性被设为公开。

将属性隐式设为私有不仅可以阻止您的库用户从内部库资源获得代码自动完成建议[code completion suggestions],还让您能够在不中断您的库客户端的情况下重命名或移除私有资源。私有资源不在代码自动完成和 Theme Editor 的作用范围内,并且如果您尝试引用私有资源,Lint 将显示警告。

开发注意事项

[Development considerations]
在开发您的库模块和相关应用时,请注意以下行为和限制[behaviors and limitations]。
将库模块引用添加至您的 Android 应用模块后,您可以设置它们的相对优先级。构建时,库会按照一次一个的方式与应用合并,并按照从低到高的优先级顺序。

1、资源合并冲突[Resource merge conflicts]
  • 构建工具会将库模块中的资源与相关 app 模块的资源合并。如果在两个模块中均定义了给定资源 ID,将使用 app 中的资源。
  • 如果多个 AAR 库之间发生冲突,将使用依赖项列表首先列出(位于 dependencies 块顶部)的库中的资源。
  • 为了避免常用资源 ID 的资源冲突,请在模块(或在所有项目模块)中使用具有唯一性的前缀或其他一致的命名方案。

2、库模块可以包含 JAR 库[A library module can include a JAR library]
您可以开发一个自身包含 JAR 库的库模块;不过,您需要手动编辑相关应用模块的构建路径,并添加 JAR 文件的路径[manually edit the dependent app modules‘s build path and add a path to the JAR file]。

3、库模块可以依赖外部 JAR 库[A library module can depend on an external JAR library]
您可以开发一个依赖于外部库(例如 Maps 外部库)的库模块。在这种情况下,相关应用必须针对包含外部库的目标构建[the dependent app must build against a target that includes the external library]。另外也要注意,库模块和相关应用都必须在其清单文件的 <uses- library> 元素中声明外部库。

3、库模块不得包含原始资源[Library modules cannot include raw assets]
工具不支持在库模块中使用原始资源文件(保存在 assets/ 目录中)。应用使用的任何原始资源都必须存储在应用模块自身的 assets/ 目录中。

4、应用模块的 minSdkVersion 必须大于或等于库定义的版本[The app module‘s minSdkVersion must be equal to or greater than the version defined by the library]
库作为相关应用模块的一部分编译,因此,库模块中使用的 API 必须与应用模块支持的平台版本兼容。

5、每个库模块都会创建自己的 R 类[Each library module creates its own R class]
在您构建相关应用模块时[When you build the dependent app modules],库模块将先编译到 AAR 文件中[library modules are compiled into an AAR file],然后再添加到应用模块中[then added to the app module]。因此,每个库都有其自己的 R 类,并根据库的软件包名称命名。从主模块和库模块生成的 R 类会在所需的所有软件包(包括主模块的软件包和库的软件包)中创建。

6、库模块可能包含自己的 ProGuard 配置文件[Library modules may include their own ProGuard configuration file]
通过将 ProGuard 配置文件添加到包含其 ProGuard 指令的库,您可以在自己的库上启用代码压缩。构建工具会为库模块将此文件嵌入到生成的 AAR 文件中。在您将库添加到应用模块时,库的 ProGuard 文件将附加[appended to]至应用模块的 ProGuard 配置文件。

通过将 ProGuard 文件嵌入到您的库模块中,您可以确保依赖于此库的应用模块不必手动更新其 ProGuard 文件即可使用库。当 ProGuard 在 Android 应用模块上运行时,它会同时使用来自应用模块和库的指令,因此您不应当只在库上运行 ProGuard。

要指定您的库的配置文件名称,请将其添加到 consumerProguardFiles 方法中,此方法位于您的库的 build.gradle 文件的 defaultConfig 块内。例如,以下片段会将 lib-proguard-rules.txt 设置为 library‘s ProGuard configuration file:
android {
    defaultConfig {
        consumerProguardFiles ‘lib-proguard-rules.txt‘
    }
}
5
5
 
1
android {
2
    defaultConfig {
3
        consumerProguardFiles ‘lib-proguard-rules.txt‘
4
    }
5
}

要确保库的ProGuard规则不会对应用程序模块应用不需要的压缩副作用[unwanted shrinking side effects],请仅在你的库中包含不适用于您库的 disable ProGuard features。试图帮助开发人员的[attempt to aid developers]规则可能与app模块或其他库中的现有代码冲突,因此不应包含在内。 例如,您的库的ProGuard文件可以 指定在应用程序模块缩小期间需要保留的代码

注:Jack工具链[Jack toolchain]仅支持ProGuard中的部分压缩和模糊选项。

7、测试库模块与测试应用程序相同[Testing a library module is the same as testing an app]
主要区别在于库及其依赖项自动包含在测试APK的依赖项中[automatically included as dependencies of the test APK]。这意味着测试APK不仅包括自己的代码,还包括库的AAR及其所有依赖项。 因为没有单独的“app under test”,androidTest任务只安装(和卸载)测试APK。

合并多个清单文件时,Gradle将遵循默认优先级顺序,并将库的清单合并到测试APK的主清单中。

AAR 文件详解

[Anatomy of an AAR file]
AAR 文件的文件扩展名[file extension]为 .aar,Maven 工件类型[artifact type]也应当是 aar。文件本身是一个包含以下强制性条目的 zip 文件:
/AndroidManifest.xml
/classes.jar
/res/
/R.txt
/public.txt
5
5
 
1
/AndroidManifest.xml
2
/classes.jar
3
/res/
4
/R.txt
5
/public.txt
此外,AAR 文件可能包含以下可选条目中的一个或多个:
/assets/
/libs/name.jar
/jni/abi_name/name.so (其中 abi 名称 是 Android 支持的 ABI 之一)
/proguard.txt
/lint.jar
5
5
 
1
/assets/
2
/libs/name.jar
3
/jni/abi_name/name.so (其中 abi 名称  Android 支持的 ABI 之一)
4
/proguard.txt
5
/lint.jar

Content and code samples on this page are subject to the licenses described in the Content License. Java is a registered trademark of Oracle and/or its affiliates.
上次更新日期:四月 25, 2018

2018-7-30

Create an Android library

上一篇:一个不错的Html5 DatePicker控件,主要支持手机端。


下一篇:详解WebApp与Native App的区别