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

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 configurationDeprecated configuration
implementationcompile
apicompile
compileOnlyprovided
runtimeOnlyapk

引用

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/390212.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

第一阶段:前端开发_Mysql——表与表之间的关系

2018-06-26 表与表之间的关系 一、一对多关系&#xff1a; 常见实例&#xff1a;分类和商品&#xff0c;部门和员工一对多建表原则&#xff1a;在从表&#xff08;多方&#xff09;创建一个字段&#xff0c;字段作为外键指向主表&#xff08;一方&#xff09;的一方      …

89. Gray Code - LeetCode

为什么80%的码农都做不了架构师&#xff1f;>>> Question 89. Gray Code Solution 思路&#xff1a; n 0 0 n 1 0 1 n 2 00 01 10 11 n 3 000 001 010 011 100 101 110 111 Java实现&#xff1a; public List<Integer> grayCode(int n) {List&…

这份NLP研究进展汇总请收好,GitHub连续3天最火的都是它

最近&#xff0c;有一份自然语言处理 (NLP) 进展合辑&#xff0c;一发布就受到了同性交友网站用户的疯狂标星&#xff0c;已经连续3天高居GitHub热门榜首位。 合集里面包括&#xff0c;20多种NLP任务前赴后继的研究成果&#xff0c;以及用到的数据集。 这是来自爱尔兰的Sebasti…

最近用.NET实现DHT爬虫,全.NET实现

最近用.NET实现DHT爬虫&#xff0c;全.NET实现&#xff0c;大家可以加我QQ交流下 309159808 转载于:https://www.cnblogs.com/oshoh/p/9236186.html

C++贪吃蛇

动画链接 GitHub链接&#xff1a;https://github.com/yanpeng1314/Snake 1 #include "Snake.h"2 3 int iScore 0;4 int iGrade 1;5 6 //蛇头蛇尾初始位置7 int x_head 1, y_head 3;8 int x_tail 1, y_tail 1;9 10 //地图坐标11 int i_Map 1, j_Map 1;12 13 /…

10分钟腾讯云配置免费https

腾讯云免费证书申请地址&#xff1a; https://console.cloud.tencent... 填写相关信息 域名身份验证 文件验证 将fileauth.text 创建在网站访问根目录的 .well-known/pki-validation/目录使得 www.**.com/.well-known/pki-validation/fileauth.text 能够访问详情 等待5分钟左右…

web前端【第十一篇】jQuery属性相关操作

知识点总结 1、属性 属性&#xff08;如果你的选择器选出了多个对象&#xff0c;那么默认只会返回出第一个属性&#xff09;、 attr(属性名|属性值) - 一个参数是获取属性的值&#xff0c;两个参数是设置属性值 - 点击加载图片示例 re…

85. 最大矩形

85. 最大矩形 给定一个仅包含 0 和 1 、大小为 rows x cols 的二维二进制矩阵&#xff0c;找出只包含 1 的最大矩形&#xff0c;并返回其面积。 示例 1&#xff1a; 输入&#xff1a;matrix [[“1”,“0”,“1”,“0”,“0”],[“1”,“0”,“1”,“1”,“1”],[“1”,“1”…

html单行元素居中显示,多行元素居左显示

有很多的业务需要元素或者文字如果单行&#xff0c;居中显示&#xff0c;如果数据增多&#xff0c;居中显示代码&#xff08;直接复制到编辑器可用&#xff09;&#xff1a;<!DOCTYPE html> <html lang"en"> <head> <meta charset"UTF-8&q…

怎样在减少数据中心成本的同时不牺牲性能?

2019独角兽企业重金招聘Python工程师标准>>> 导读虽然组织对数据中心提出了更高的要求&#xff0c;但IT管理人员确实有办法在严格的预算内展开工作。如今&#xff0c;组织认为即使性能预期不断提高&#xff0c;其数据中心预算也在缩减。尽管2018年IT支出总体预计增长…

赛普拉斯 12864_如何使用赛普拉斯自动化辅助功能测试

赛普拉斯 12864In my previous post, I covered how to add screenshot testing in Cypress to ensure components dont unintentionally change over time. 在上一篇文章中 &#xff0c;我介绍了如何在赛普拉斯中添加屏幕截图测试&#xff0c;以确保组件不会随时间变化。 Now…

Android App 的主角:Activity

Android App 程序主要由4种类型组成&#xff1a; 1.Activity&#xff08;活动&#xff09;&#xff1a;主要负责屏幕显示画面&#xff0c;并处理与用户的互动。每个Android App至少都会有一个Activity&#xff0c;在程序一启动时显示主画面供用户操作。 2.Service&#xff08;后…

通过构建Paint App学习React Hooks

According to people in the know, React Hooks are hot, hot, hot. In this article, we follow Christian Jensens 14-part tutorial to find out about the basics of this new feature of React. Follow along to find out more! 据知情人士称&#xff0c;React Hooks很热&…

Npoi导出excel整理(附源码)

前些日子做了一个简单的winform程序&#xff0c;需要导出的功能&#xff0c;刚开始省事直接使用微软的组件&#xff0c;但是导出之后发现效率极其低下&#xff0c;绝对像web那样使用npoi组件&#xff0c;因此简单的进行了整理&#xff0c;包括直接根据DataTable导出excel及Data…

入库成本与目标成本对比报表中我学到的东西

1、SQL方面&#xff1a; &#xff08;1&#xff09;、用DECODE函数解决除数为零的情况 具体语法&#xff1a; DECODE&#xff08;参数&#xff0c;0&#xff0c;1&#xff0c;参数&#xff09; ->DECODE(TAB1.A8&#xff0c;0&#xff0c;1&#xff0c;TAB1.A8) &#xff08…

【小摘抄】关于C++11下 string各类用法(持续更新)

http://blog.csdn.net/autocyz/article/details/42391155 提供了最简单的详解 下列对本人近期开发中的一些心得体会进行摘抄 1.string按照字符进行截取 示例代码&#xff1a; string teststring "#12313#kajlkfdsa";//通讯消息示例&#xff0c;结合string的内置函数…

【VMware vSAN 6.6】5.5.Update Manager:vSAN硬件服务器解决方案

目录 1. 简介 1.1.适用于HCI的企业级存储2. 体系结构 2.1.带有本地存储的服务器2.2.存储控制器虚拟系统套装的缺点2.3.vSAN在vSphere Hypervisor中自带2.4.集群类型2.5.硬件部署选项3. 启用vSAN 3.1.启用vSAN3.2.轻松安装3.3.主动测试4. 可用性 4.1.对象和组件安置4.2.重新构建…

32位JDK和64位JDK

32位和64位系统在计算机领域中常常提及&#xff0c;但是仍然很多人不知道32位和64位的区别&#xff0c;所以本人在网上整理了一些资料&#xff0c;并希望可以与大家一起分享。对于32位和64位之分&#xff0c;本文将分别从处理器&#xff0c;操作系统&#xff0c;JVM进行讲解。 …

中小企业如何选择OA协同办公产品?最全的对比都在这里了

对于中小企业来说&#xff0c;传统的OA 产品&#xff0c;如泛微、蓝凌、致远、华天动力等存在价格高、使用成本高、二次开发难等特点&#xff0c;并不适合企业的协同管理。 国内OA市场也出现了一批轻便、低价的OA产品&#xff0c;本文针对以下几款适合中小企业的OA产品在功能、…

Elasticsearch学习(2)—— 常见术语

为什么80%的码农都做不了架构师&#xff1f;>>> cluster (集群)&#xff1a;一个或多个拥有同一个集群名称的节点组成了一个集群。每个集群都会自动选出一个主节点&#xff0c;如果该主节点故障&#xff0c;则集群会自动选出新的主节点来替换故障节点。 node (节点…