Android 开发过程当中,咱们不可避免地须要引入其余人的工做成果。减小重复“造轮子”的时间,投入到更有意义的核心任务当中。
Android 库模块在结构上与 Android 应用模块相同。提供构建应用所需的一切内容,包括源代码(src
)、资源文件(res
)和 Android 清单文件(AndroidManifest.xml
)。java
Android Studio IDE 提供选项建立库模块:android
若是现有的应用模块包含但愿重用的全部代码,能够经过修改 build.gradle
文件:api
// apply plugin: 'com.android.application' apply plugin: 'com.android.library'
Android AAR 相似 Java JAR,除了类文件还能够包含 Android 资源和一个清单配置文件(AndroidManifest.xml
)。app
导入本地的外部模块(e.g. Project B b module)到当前主项目中(e.g. Project A)。
Project B b module 一般为库模块,咱们须要在另外一个 Project A 应用模块中使用它。ide
Android Studio IDE 提供选项以依赖项形式来添加库:gradle
二者区别以下:ui
在现实开发过程当中,咱们但愿维护一个统一版本的库模块,这样一来库模块的更新就会同步给全部依赖于它的项目:
Project A、Project C、Project D 都依赖于 Project B b module,库模块 b 的修改会同步到各个项目。插件
解决方案:
配置 gradle 经过本地相对路径指定库模块文件夹,实现本地外部模块导入。日志
打开主项目 settings.gradle
文件导入库:code
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 冲突的有效办法,是在各个模块中使用具备惟一性的前缀命名规范。
考虑到兼容性问题,应用模块的 minSdkVersion
必须大于或等于库定义的版本。
库模块中如若使用到仅高版本 SDK 支持的 API,将会致使应用模块编译失败。
Android 在切换到 Gradle 做为构建系统以前,经过 Manifest 设置 minSdkVersion
,以后其值会被 build.gradle
文件中的值覆盖。
Android 应用的 APK 文件中只能包含一个 AndroidManifest.xml
,不过 Android Studio 项目能够包含多个该文件(来自主应用模块及各个库模块)。所以,在构建应用时,Gradle 构建会将全部清单文件(AndroidManifest.xml
)合并。清单文件按照优先级从低到高合并,遵循特定规则合并各个清单文件中的全部 XML 元素 。
清单文件优先级由高到低的顺序:
多个库存在时,则其清单优先级与依赖顺序即 dependencies 块中的顺序匹配。
Manifest merger failed 示例: android:theme
在多个 AndroidManifest.xml
被定义且值不一样,形成合并冲突。
Project A 主项目 AndroidManifest.xml
<application android: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
<application android: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
<application android: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-v4
、support-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 |