Android 开发过程中,我们不可避免地需要引入其他人的工作成果。减少重复“造轮子”的时间,投入到更有意义的核心任务当中。

Android 库模块在结构上与 Android 应用模块相同。提供构建应用所需的一切内容,包括源代码(src)、资源文件(res)和 Android 清单文件(AndroidManifest.xml)。

Android Studio IDE 提供选项创建库模块:

  1. 在项目中创建一个新的库模块(New Module
  2. 将应用模块转换为库模块(因两者结构基本相同)

如果现有的应用模块包含希望重用的所有代码,可以通过修改 build.gradle文件:

// apply plugin: 'com.android.application'
apply plugin: 'com.android.library'
  • Android 库模块编译产物为 AAR,需要作为其他应用模块依赖项使用。
  • Android 应用模块编译产物为 APK,设备上可以直接运行。

Android AAR 类似 Java JAR,除了类文件还可以包含 Android 资源和一个清单配置文件(AndroidManifest.xml)。

导入本地外部模块

导入本地的外部模块(e.g. Project B b module)到当前主项目中(e.g. Project A)。
Project B b module 通常为库模块,我们需要在另一个 Project A 应用模块中使用它。

Android Studio IDE 提供选项以依赖项形式来添加库:

  1. 添加已编译的 AAR(或 JAR)文件(Import .JAR/.AAR Package
  2. 将库模块导入到您的项目中(Import Module

两者区别如下:

  • 库模块导入方式,将会复制代码到其他项目:
    Project A 目录下出现 Project B b module 的拷贝
  • 库模块导入之后允许编辑库代码,但是修改只对当前项目生效:
    Project A 目录下修改 b module 不会影响到 Project B b module

在现实开发过程中,我们希望维护一个统一版本的库模块,这样一来库模块的更新就会同步给所有依赖于它的项目:
Project A、Project C、Project D 都依赖于 Project B b module,库模块 b 的修改会同步到各个项目。

  • 库模块导入方式显然无法完成任务,因为其是通过拷贝方式导入。
  • 添加已编译的 AAR(或 JAR)文件可以完成任务,但是依然需要人工切换项目点选操作。

解决方案:
配置 gradle 通过本地相对路径指定库模块文件夹,实现本地外部模块导入。

打开主项目 settings.gradle 文件导入库:

include ':my-library-module'
project(':my-library-module').projectDir = new File(settingsDir, '../my-library-module')

打开主项目应用模块的 build.gradle 文件,并向 dependencies 块中添加依赖:

dependencies {compile project(":my-library-module")
}

库模块开发注意事项

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

资源合并冲突

  • 当库模块与应用模块均定义了相同资源 ID,默认使用应用模块的资源,e.g. @string/app_name
  • 多个 AAR 库之间发生资源 ID 冲突,根据依赖项列表顺序,优先使用 dependencies 块顶部模块的资源

避免常用资源 ID 冲突的有效办法,是在各个模块中使用具有唯一性的前缀命名规范。

AndroidManifest 合并冲突

考虑到兼容性问题,应用模块的 minSdkVersion 必须大于或等于库定义的版本。
库模块中如若使用到仅高版本 SDK 支持的 API,将会导致应用模块编译失败。
Android 在切换到 Gradle 作为构建系统之前,通过 Manifest 设置 minSdkVersion,之后其值会被 build.gradle 文件中的值覆盖。

Android 应用的 APK 文件中只能包含一个 AndroidManifest.xml,不过 Android Studio 项目可以包含多个该文件(来自主应用模块及各个库模块)。因此,在构建应用时,Gradle 构建会将所有清单文件(AndroidManifest.xml)合并。清单文件按照优先级从低到高合并,遵循特定规则合并各个清单文件中的所有 XML 元素 。

清单文件优先级由高到低的顺序:

  1. 清单文件构建变体
  2. 应用模块的主清单文件
  3. 所包括库中的清单文件

多个库存在时,则其清单优先级与依赖顺序即 dependencies 块中的顺序匹配。

Manifest merger failed 示例:
android:theme 在多个 AndroidManifest.xml 被定义且值不同,造成合并冲突。

Project A 主项目 AndroidManifest.xml

<applicationandroid:allowBackup="true"android:icon="@mipmap/ic_launcher"android:label="@string/app_name"android:roundIcon="@mipmap/ic_launcher_round"android:supportsRtl="true"android:theme="@style/AppTheme">
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">

Project B b Library Module AndroidManifest.xml

<applicationandroid:theme="Theme.AppCompat.Light.DarkActionBar">

遇到 Manifest 冲突参考 Gradle Console 给出的错误日志和提示,解决冲突。
例如使用 tools:replace 方式避免属性冲突,借助 tools 域名空间(xmlns:tools="http://schemas.android.com/tools")设置 Manifest 的合并优先级。明确表示合并时移除低优先级 library module 中的相关属性,使用高优先级 application module 中定义的对应属性内容。

Project A 主项目 AndroidManifest.xml

<applicationandroid:allowBackup="true"android:icon="@mipmap/ic_launcher"android:label="@string/app_name"android:roundIcon="@mipmap/ic_launcher_round"android:supportsRtl="true"android:theme="@style/AppTheme"tools:replace="android:theme">

模块依赖分析

考虑到多重嵌套依赖问题,Gradle 类似 Maven 支持传递依赖,即库本身依赖于其他库,由此需要解决依赖之间的版本问题。

复杂的依赖关系很可能导致重复引入包,例如:support-v4support-v7 包,从而发生冲突。

多个模块之间存在相同依赖并且发生冲突,可以通过 exclude 语法过滤相同依赖:

// helloworld build.gradle
...
compile ('com.example.helloworld:my-library-module:1.0.0') {exclude group: 'com.android.support', module: 'support-v4'exclude group: 'com.android.support', module: 'support-v7'
}

上述方法是在主项目引入其他库模块时进行过滤依赖,作为库模块开发者我们也应该考虑到其他用户的使用情况。

provided 语法在创建 Android 库模块时非常有用,将依赖项添加到编译过程中,但不会添加到编译输出中。这样一来减少最终 APK、AAR 产物大小,同时避免添加不必要依赖项。

注意:需要告知用户此依赖项存在,由其如何决定引入依赖。

// my-library-module build.gradle
...
ext.supportLibVersion = '26.1.0'dependencies {implementation fileTree(dir: 'libs', include: ['*.jar'])provided "com.android.support:appcompat-v7:${supportLibVersion}"
}

Project A 依赖 a、b、c module,同时 a、b module 又依赖于 d module,且 a、b 各自依赖的 d module 版本(version)不一致,不同 version 的 d module 中 API 接口如若发生改变,Project A Build/Sync 将会失败。 例如 version 1.0 中的方法 method1,在 version 2.0 被移除将会遇到 java.lang.NoSuchMethodError

建议尽可能保持依赖项 d module version 一致,或者使用不同 version 但是差异不大,起码做到 API 能够通用。

通过 ./gradlew dependencies 命令可以查看依赖关系,附加参数可以查看指定类型、模块依赖关系:

./gradlew my-library-module:dependencies --configuration archives
archives - Configuration for archive artifacts.
+--- com.android.support:recyclerview-v7:26.1.0
|    +--- com.android.support:support-annotations:26.1.0
|    +--- com.android.support:support-compat:26.1.0
|    |    +--- com.android.support:support-annotations:26.1.0
|    |    \--- android.arch.lifecycle:runtime:1.0.0
|    |         +--- android.arch.lifecycle:common:1.0.0
|    |         \--- android.arch.core:common:1.0.0
|    \--- com.android.support:support-core-ui:26.1.0
|         +--- com.android.support:support-annotations:26.1.0
|         \--- com.android.support:support-compat:26.1.0 (*)

另外 Android 项目可以使用 ./gradlew androidDependencies


另外,考虑到构建问题,库模块使用的 gradle 插件与应用模块尽量保持一致。
Android Gradle Plugin 版本不一致可能会影响到依赖项配置语法:

New configuration Deprecated configuration
implementation compile
api compile
compileOnly provided
runtimeOnly apk

引用

创建 Android 库
Add build dependencies
合并多个清单文件

Android 开发使用 Gradle 配置构建库模块的工作方式相关推荐

  1. Android开发:gradle配置

    implement.api 指令解释 简单解释: A模块通过Implementation的方式依赖B模块,B模块通过Implementation的方式依赖C模块 那么: A不能调用C模块中公开的接口, ...

  2. Android Studio build.gradle配置详解

    Android Studio是采用gradle来构建项目的,gradle是基于groovy语言的,如果只是用它构建普通Android项目的话,是可以不去学groovy的.当我们创建一个Android项 ...

  3. Android开发环境简单配置

    为什么80%的码农都做不了架构师?>>>    ·         Android开发环境简单配置 写这个系列的原因也是因为自己对android比较感兴趣,而网上多数教程都是直接参照 ...

  4. 泰凌微ble mesh蓝牙模组天猫精灵学习之旅④如何在Android开发低功耗蓝牙ble控制 TB-02 模块,代码工程全部开源!(附带Demo)

    本<泰凌微ble mesh蓝牙模组天猫精灵学习之旅>系列博客学习由半颗心脏 潜心所力所写,仅仅做个人技术交流分享,不做任何商业用途.如有不对之处,请留言,本人及时更改. 1.小白也痴迷,如 ...

  5. Android开发--环境的配置

    Android开发--环境的配置 一 Android开发环境:JDK.eclipse ADT.海马模拟器或者夜神模拟器.配置之前先保证运行内存足够大,不然会导致运行卡. 二 JDK(不用安装) 1.j ...

  6. Ubuntu Linux环境下的Android开发环境的配置

    在Android底层开发中需要用到的工具有:JDK6或以上版本:Eclipse3.4或以上版本:ADT;CDT;Android SDK:Android NDK:交叉编译环境:Linux内核源代码:An ...

  7. MTK6735 android开发记录 编译配置(一)

    MTK6735 android开发记录 编译配置(一) 指导文件:环境建立,编译,配置GPIO等: :YYW_M_6735相关文档\YYW-M-6735-Support.pdf 里面有什么不懂的,比如 ...

  8. Android开发中怎样调用系统Email发送邮件(多种调用方式)

    在Android中调用其他程序进行相关处理,几乎都是使用的Intent,所以,Email也不例外,所谓的调用Email,只是说Email可以接收Intent并做这些事情 我们都知道,在Android中 ...

  9. android中资源文件的两种访问方式,在android开发中进行数据存储与访问的多种方式介绍...

    在android开发中进行数据存储与访问的多种方式介绍 更新时间:2013年06月07日 16:24:23   作者: 很多时候我们的软件需要对处理后的数据进行存储或再次访问,Android为数据存储 ...

最新文章

  1. formatData
  2. SAP MM 采购发票上的金额小差异
  3. vsnprintf的作用和使用
  4. 浅谈.Net异步编程的前世今生----异步函数篇(完结)
  5. wamp 配置 mysql_PHPWAMP配置应该如何修改,Web服务器、php、mysql的具体配置修改
  6. android源码编译jar,在android源码编译中导入第三方jar包
  7. Android 系统(226)---Android 阿拉伯语适配
  8. 20190509杂题选讲
  9. (转载)Fiddler 教程
  10. (11)数据分析-TableOne工具
  11. 微信小程序前端【订阅消息】遇到的问题及总结
  12. 青岛飞阳计算机学校,青岛通济实验学校:综艺比赛 青春飞扬
  13. 【小白渗透入门系列】补充:信息搜集工具
  14. 信息安全工程07875 自考软件工程 助学班复习纲要
  15. 初识深度信念网络DBN
  16. RUNA WFE,workflow environment based on JBoss' JBPM engine
  17. 高中数学向量巨难题型四心问题解题技巧
  18. 奉劝那些想涨工资的程序员,这些 IT 大神们都在用的网站,你越早知道越好(建议收藏)!!...
  19. 网格平滑基础算法总结
  20. MySQL 数据库(包括基础和进阶CURD、事务和索引)

热门文章

  1. a letter and a number(一封信和一个数字)
  2. python数据存储用什么_Python的小数据存储,用什么格式更有逼格?
  3. java wed登录面 代码_JavaWeb实现用户登录注册功能实例代码(基于Servlet+JSP+JavaBean模式)...
  4. 680. 验证回文字符串 Ⅱ golang
  5. go语言 函数相关1:实参到形参的传递永远是值拷贝
  6. C++Primer学习笔记:第8章 IO库
  7. makefile通用版本
  8. java支付模块架构,涨薪7K!
  9. 安卓开发面试题!带着问题深入学习Handler,进阶学习资料!
  10. c语言程序改频率,求问。这个fft c语言程序 采样的声音频率为多少?