关于建立Android Library所需要知道的一切

关于建立Android Library所需要知道的一切

Android 库(Library)在结构上与 Android 应用模块一样。应用模块所可以包括的东西。在库中都赞成存在,包括代码文件、资源文件和manifest文件等。css

应用模块编译后生成的是一个apk文件,可以直接在设备上执行,但是,库模块编译后生成的是一个Android Archive文件,简称AARhtml

AAR文件没法像apk文件同样直接在设备上执行,咱们通常用它做为Android app的依赖。java

普通JAR文件仅仅能包括代码文件和清单文件,而ARR文件不只可以包括代码文件。还可以包括Android的资源文件和manifest文件。这样。咱们就可以把资源文件像布局文件、图片文件等和Java代码文件一块儿分享出去。可以说ARR文件是真正专属于Android的“JAR”包。android

库模块在下面状况下很是实用:git

  • 建立多个app。这些app需要使用多个一样的组件。像activity、service或UI 布局等。
  • 建立一个app。而这个app可能需要依据需要编译成多个APK版本号,比方免费版和付费版,而两个版本号都需要使用到一样的组件。

在不论什么一种状况下,你仅仅需要将要重用的文件放到库模块中,而后以依赖项的形式为每个应用模块加入库就能够。github

建立库模块

在你的工程中,建立一个新的库模块。可以遵循例如如下的步骤:json

  1. 点击 File > New > New Module.
  2. 在Create New Module的窗体中。选择Android Library。并点击下一步(Next)。
    在该窗体中还有一个选项用于建立一个Java Library,Java Library就是咱们所知的传统的JAR文件。JAR文件在很是多工程中十分实用,尤为当你想分享代码给其它工程的时候。但是JAR文件并不一样意包括Android资源文件和manifest文件,而资源文件在Android项目中对代码重用具备很是大的帮助。因此本篇主要对Android库做介绍。
  3. 为你的库命名并选择最低SDK版本号号,而后点击Finish,完毕建立。

仅仅要Gradle同步完毕后,库模块就会出现左边的工程面板中。android-studio

应用模块转成库模块

假设你有一个已经存在的应用模块。并想重用它的所有代码。你可以把它转成一个库模块:bash

1.打开属于该应用模块下的build.gradle文件,在最顶部,你可以看见例如如下的显示:markdown

java apply plugin: 'com.android.application'

2.把应用的插件改为库的插件:

java apply plugin: 'com.android.library'

3.点击Sync Project with Gradle Files.

处理完上面这些,整个模块的结构不会被改变,但是该模块已经变为了库模块,编译后生成的是AAR文件而再也不是APK文件了。

加入库做为应用的依赖

为了在应用模块中使用库模块。你需要做例如如下的处理:

1.加入库到工程中有两种方式(假设你是在一样项目中建立的库模块,则该模块已经存在,您可以跳过此步骤)

  • 加入编译后的ARR(或JAR)文件:
    1.点击 File > New Module.
    2.在Create New Module的窗体中,点击 Import .JAR/.AAR Package 而后点击 Next.
    3.输入ARR或JAR文件所在的路径。并点击Finish。建立后例如如下所看到的:
    image_1b3etje011peq1s2ruono51uqb9.png-17.3kB

  • 导入外部库模块到工程中:
    1.点击 File > New > Import Module.
    2.输入Library模块所在的路径,并点击Finish。建立后例如如下所看到的:
    image_1b3etmks81d4ld061fcigc517411g.png-19.7kB


这两种引入库的方式有所不一样。假设直接引入的是库模块,你可以对库的代码进行编辑。

但是假设导入的是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文件夹,专门用于存放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的模块下才干被识别。

生成AAR文件

咱们可以经过点击Build > Make Project生成aar文件,aar文件会在project-name/module-name/build/outputs/aar/ 下生成。普通状况下会有两个aar文件,一个debug版本号。一个release版本号。

当咱们拿到后aar文件后。就可以把它公布出去。其它小伙伴就可以利用上面的方式引入aar文件到工程中了。

AAR文件解刨

AAR 文件的文件扩展名为 .aar,该文件自己就是一个zip文件,必需要包括下面内容:

  • /AndroidManifest.xml
  • /classes.jar
  • /res/
  • /R.txt (由R.java转换而来)

此外,AAR文件可能包括下面可选条目中的一个或多个:

  • /assets/
  • /libs/name.jar
  • /jni/abi_name/name.so(当中 abi_name 是 Android 支持的 ABI 之中的一个)
  • /proguard.txt
  • /lint.jar

库的私有资源

默认状况下库中的所有资源都是公开状态。也就是说赞成应用模块直接訪问。但是假设你想让库中的资源仅供内部使用,而不想暴露给外部。您应经过声明一个或多个公开资源的方式来使用这样的本身主动私有标识机制。资源包括您项目的 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点的方式进行提示的。这也为了避免暴露私有资源的一种手段。假设你强制使用了该资源,编译器会发出警告:

1e12a2b6-bb40-4054-94d0-5e8f65ead49d.png-9.9kB

从上面可以看出。lib_main_layout和mylib_public_string资源都可以直接使用的,而未定义的都为私有资源,外部依赖使用的时候,编译器会发出警告信息。

但是这里有一点需要注意,使用私有资源并不会发生不论什么错误。应用模块可以正常的使用这些私有资源。之因此提供这样的机制,是为了告诉你。库模块并不想把这些资源暴露给你,可能这些资源有特殊用途之类的。假设你真想使用私有资源。并且不想编译器发出如上的警告,你可以把私有资源拷到本身的应用模块下。

隐私的赋予资源私有属性不只可以必定程度上防止外部使用,并且还赞成你重命名或删除私有资源时,不会影响到使用到该库的应用模块。私有资源不在代码本身主动完毕和 Theme Editor 的做用范围内,并且假设您尝试引用私有资源,Lint 将显示警告。

库开发注意事项

将库模块引用加入至您的Android 应用模块后,库模块会依据优先级的顺序与应用模块进行合并。

资源合并冲突

  1. 构建工具会将库模块中的资源与相关应用模块的资源合并。

    假设在两个模块中均定义了一样的资源 ID,那就默认使用应用模块的资源。

  2. 假设多个 AAR 库之间发生冲突,将使用依赖项列表首先列出(位于 dependencies 块顶部)的库中的资源。

为了不常用资源 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=0x7f02000一、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文件:

e1c93a61-d052-4265-b73f-31fa34034906.png-6.5kB

当中第一个是库合并过来后的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模块中存在私有资源,假设应用模块资源名和私有资源名冲突了,编译器会发出警告:

89572d52-d118-4238-90e0-aba61a4a44e5.png-10.1kB

当咱们在应用中使用该资源时,也会发出该警告:

3603b9a9-76da-45ba-bf55-3f3fd2fedac2.png-7.5kB

尽管咱们使用该资源时用的是应用模块的资源。但是库已经把test_one标为私有资源,为了规范化。我可以採取例如如下措施:

  1. 在应用模块中更换不一样的资源名。不要与库中的资源名同样。

  2. 假设真的要使用同名资源,使用tools标记为重写状态:
<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>

此方式并没有法取消私此资源是私有资源的状态,仅仅只是取消了资源文件里的警告而已。

asserts合并冲突

当应用依赖库时,应用的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。它赞成你以简单的字节流的形式打开和读取和应用程序绑定在一块儿的原始资源文件。

应用模块的 minSdkVersion 必须大于或等于库定义的版本号

库做为相关应用模块的一部分编译,所以。库模块中使用的 API 必须与应用模块支持的平台版本号兼容。

每个库模块都会建立本身的 R 类

在您构建相关应用模块时,库模块将先编译到 AAR 文件里。而后再加入到应用模块中。所以,每个库都有其本身的 R 类,并依据库的软件包名称命名。

从主模块和库模块生成的 R 类会在所需的所有软件包(包括主模块的软件包和库的软件包)中建立。

库模块可能包括本身的 ProGuard 配置文件

经过将 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 的部分压缩和模糊选项

參考文档

https://developer.android.com/studio/projects/android-library.html#aar-contents
http://www.jianshu.com/p/59efa895589e
http://tikitoo.github.io/2016/05/26/android-studio-gradle-build-run-faster/
http://blog.csdn.net/z1074971432/article/details/38912747

相关文章
相关标签/搜索