【翻译】Android Studio - 创建 Android Library

原文:Create an Android Library
https://developer.android.com/studio/projects/android-library.html

Android library 结构上与 Android 应用模块(app module) 相同。它可以包含构建应用所必需的一切,包括源码(source code)、资源文件(resource files)和清单(Android manifest)。然而 Android library 可以被编译成 AAR(Android Archive) 文件被 Android 应用模块 依赖,却不能被编译成APK在设备上运行。

库模块(library module)在下列情况下有用:

  1. 当你创建的多个应用使用了相同组件,比如 activities、services、UI layouts。
  2. 当你创建的一个应用存在多个需要相同核心组件的APK版本,比如免费版与付费版。

这两种情况下,简单的移动你想重用的文件到一个库模块中然后添加这个库模块作为各个应用模块的依赖。本文将教你怎样做。

创建一个库模块

  1. 点击 File > New > New Module.
  2. Create New Module 窗口中,点击 Android Library,然后点击 Next
    另一选择是创建一个 Java Library ,它会构建一个传统的 JAR 文件。
    JAR 文件对许多项目有用,特别是当你想在不同的平台分享代码时,但它不能包含对 Android 项目代码重用有益的资源或清单(manifest)文件。
    所以这个指南重点在创建 Android Libraries.
  3. 给你的 Library 命名并选择一个最小的 SDK 版本,然后点击 Finish

一旦 Gradle 项目同步完成,库模块将出现在左边的 Project 面板中。如果你没看到新模块文件夹,请确保 Android view 已显示.

将 应用模块 转换成 库模块

如果你有想重用代码的应用模块,可以把它转换成一个库模块,如下所述:

  1. 打开现有应用模块的 build.gradle 文件,在顶部,你可以看到:

    1
    apply plugin:'com.android.application'
  2. 更改插件赋值为如下所示:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    apply plugin:'com.android.library'
    ```
    3. 点击 **Sync Project with Gradle Files**.
    就这样,这个模块的整个结构保持不变,但它现在是作为一个 Android library 且构建将创建一个 AAR 文件而非 APK 文件.
    ## 添加你的 Library 作为依赖
    在应用模块中使用 Android Library 代码,过程如下:
    1. 将 Library 添加到项目中有2种方法(如果创建的库模块在同一个项目中,可跳过这步)
    - 添加已编译的AAR或JAR文件:
    1. 点击 **File > New Module**
    2. 点击 **Import .JAR/.AAR Package**,然后点击 **Next**
    3. 输入 AAR 或者 JAR 文件的位置,然后点击 **Finish**
    - 导入库模块到项目中:
    1. 点击 **File > New > Import Module**
    2. 输入库模块文件的位置,然后点击 **Finish**
    库模块已经复制到你的项目中,因此你能够编辑 Library 代码。如果你想保持 Library 代码的唯一版本,那么这可能不是你想要的,你应该导入编译好的 AAR 文件.
    2. 确保 Library 列在 settings.gradle 文件里,这里显示为一个名字为 "my-library-module"Library:
    ``` groovy
    include ':app', ':my-library-module'
  1. 打开应用模块的build.gradle文件,在dependencies块中添加如下代码:
    1
    2
    3
    dependencies {
    compile project(":my-library-module")
    }
  1. 点击 Sync Project with Gradle Files

在上面这个例子中,名为my-library-module的 Android Library 模块成为build.gradle文件所在模块的构建依赖.

现在可以在你的应用模块中访问任何 Android library 的代码和资源,并且库的 AAR 文件会在构建时打包到你的 APK。

然而,如果你想单独分享你的 AAR 文件,你可以在project-name/module-name/build/outputs/aar/找到它,也可以通过点击 Build > Make Project 重新产生。

选择资源公开

库里的资源默认是公开的(public)。要让所有资源为隐式私有(private),你必须定义至少一个具体的公开属性(attribute as public)。资源包括你的项目res/目录中的所有文件,比如图像。要阻止你的库用户访问仅供内部使用的资源,你应该使用这种声明一个以上公开资源的自动化私有指定机制。

公开资源需要添加声明到你的库的public.xml文件。如果你之前没有添加过公开资源,那你需要在你的库的/res/values目录创建public.xml文件。

以下示例代码创建了两个名为 mylib_app_namemylib_public_string 的公开字符串资源:

1
2
3
4
<resources>
<public name="mylib_app_name" type="string"/>
<public name="mylib_public_string" type="string"/>
</resources>

任何你希望对使用你的库的开发者可见的资源都应该公开。例如,虽然 v7 appcompat library 的大部分资源都是私有的,但控制 Toolbar 组件以支持 material design 的属性是公开的。

隐式地让属性私有不仅能阻止你的库的用户感知到内部库资源(通过代码完成推荐),还允许你去重命名或移除私有资源的同时不破坏库的客户(clients of library)。私有资源可以被代码完成和 theme editor 筛选出来,Lint 会在你尝试使用私有资源时警告你。

开发者需要考虑的内容

当你开发library moduledependent apps,你应该注意到下列行为和限制:

一旦你将library module的引用添加到Android app module,就可以设置它们的优先级(relative priority)。在构建时,所有库根据优先级从低到高依次与应用合并.

  1. 资源合并冲突

    构建工具合并库模块的资源到dependent app module。如果给定的资源ID在这两个模块中都有定义,使用 app 的资源。

    如果冲突发生在多个 AAR library 中,则使用从依赖列表中先列出的库的资源。

    为了避免相同ID资源的冲突,考虑用一个前缀或者其它一致性命名方案以在模块(或所有项目)中保持唯一。

  2. 库模块可以包含 JAR library

    你可以开发包含 JAR library 的库模块,但是,你需要手动编辑 dependent app module 的构建路径,并添加 JAR 文件的路径。

  3. 库模块可以依赖外部 JAR library

    你可以开发依赖外部 JAR library 的库模块(比如 Maps 库)。这种情况下,dependent app必须建立对应包含外部库的目标(比如 Google APIs Add-On)。 注意,库模块和 dependent app 必须在它们清单(manifest)文件的 <uses-library> 元素中中声明外部库。

  4. 库模块不能包括 raw assets

    工具不支持在库模块中使用 raw asset 文件(保存在 assets/ 目录中)。app 使用的任意 asset 资源必须存储在自身模块的 assets/ 目录中.

  5. 应用模块的minSdkVersion必须大于或等于其在库中的定义

    库被编译为 dependent app module 的一部分,所以库模块中使用的 APIs 必须与app module支持的平台版本兼容。

  6. 每个库模块都创建它自己的R类

    当你建立有依赖的应用模块,库模块被编译到 AAR 文件然后被添加到应用模块。因此,每个库都有根据自身包名命名的R类。由主模块与库模块生成的R类被创建于被需要的所有模块的包,

  7. 库模块可以包含自己的 ProGuard 配置文件

    你可以对库启用代码压缩,通过添加一个包含 ProGuard 指令的 ProGuard 配置文件到你的库中。构建工具将这个文件嵌入库模块生成的 AAR 文件中。当你添加库到一个应用模块,库的 ProGuard 文件将被追加到应用模块的 ProGuard 配置文件中(proguard.txt)。

    将 ProGuard 文件嵌入库模块,使你能确保依赖你的库的应用模块就不需要手动更新它们的 ProGuard 文件就能使用你的库。当 Android 应用模块运行 ProGuard 时,它会同时使用应用模块与库模块的指令所以你不需要单独对库运行 ProGuard。

    在你的库的 build.gradle 文件的 defaultConfig 块内使用 consumerProguardFiles 方法指定配置文件名称。例如,以下代码片段设置 lib-proguard-rules.txt 为库的 ProGuard 配置文件:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    android {
    defaultConfig {
    consumerProguardFiles 'lib-proguard-rules.txt'
    }
    ...
    }
    ```
    默认情况下,应用模块引用库使用 `release` 构建,即使应用模块使用 `debug` 构建类型。要对库使用不同的构建类型,你必须添加依赖到应用模块 `build.gradle` 文件的 `dependencies` 块同时在库模块的 `build.gradle` 文件中设置 `publishNonDefault` 为 `true` 。例如,下列代码段置于应用的 `build.gradle` 文件中使得应用在 `debug` 模式构建时库使用 `debug` 构建类型,应用在 `release` 模式构建时库使用 `release` 构建类型:
    ``` groovy
    dependencies {
    debugCompile project(path: ':library', configuration: 'debug')
    releaseCompile project(path: ':library', configuration: 'release')
    }

你还须要在库的 build.gradle 文件添加下列代码,对使用它的项目暴露库的 non-release 配置:

1
2
3
4
android {
...
publishNonDefault true
}

注意:publishNonDefault 会增加构建时间。

要确保你的库的 ProGuard 规则不对应用模块产生多余的压缩副作用,包含的规则需要禁用对你的库无用的 ProGuard 特性。这些规则帮助开发者处理与应用模块中现存代码的冲突。举个例子,你的库的 ProGuard 文件可以在应用模块压缩指定什么代码需要被保留

注意: Jack toolchain 仅支持 ProGuard 的压缩(shrinking)和混淆(obfuscation)选项。

欢迎打赏,谢谢支持~