适用于Android的Gradle,AAR和条件依赖项

简而言之 :组织AAR代码/ POM的一些方法是什么,使得使用该AAR的应用程序只具有实际需要的依赖关系?

长forms

假设我们有一个应用程序依赖于打包为AAR(L)的Android库项目。

L包含类的混合,任何给定的应用程序(如A)将只使用这些类的一个子集。 例如:

  • L可以包含用于本地API级别11片段的Fragment实现,反向端口片段和ActionBarSherlock风味片段

  • L可以包含常规活动, FragmentActivityActionBarActivity和ActionBarSherlock风味活动的Activity实现

  • L可以通过LocalBroadcastManager ,Square的Otto和greenrobot的EventBus来引发事件

  • 等等

这些案件有两个主要的共同点,正如我所看到的:

  1. 应用程序通常只关心一些类。 例如,使用Otto的应用程序不会关心引用greenrobot的EventBus的代码,或者使用ActionBarActivity的应用程序将不关心ActionBarSherlock。

  2. 如果AAR是repo中的工件,则应用程序将不会关心构buildAAR所需的所有可能的上游依赖关系。 例如,使用本地API级别11片段的应用程序将不需要support-v4actionbarsherlock ,即使AAR本身需要它们来构buildAAR

如果我们要使用JAR而不是AAR来转储依赖关系pipe理,这是非常简单的。 构buildJAR将具有编译时间依赖性(例如, support-v4 )。 但是,使用该JAR的应用程序可以跳过这些依赖关系,只要这些应用程序不使用真正需要这些依赖关系的类,生活就是好的。

但是,我很难看到如何在build.gradle文件中指定的AAR和Maven构件完成同样的事情。 如果L具有引用上游依赖关系的dependencies块,则应用程序将依次在应用程序依赖于L时依次下载这些依赖性。

我相当肯定的解决scheme之一是将L分成几个库。 例如,使用片段场景,我们可以有:

  • L1,其中包含原生API级别11版本的片段的实现,以及其他场景所需的常见代码。 这个库不会有上游的依赖关系。

  • L2,其中包含使用Android支持包的分段backport的实现。 L2将依赖于L1和support-v4

  • L3,其中包含使用Sherlock风格片段的实现。 L3将依赖于L1和actionbarsherlock

然后,应用程序会select是否依赖L1,L2或L3,因此只会获得必要的上游依赖关系(如果有的话)。

我的问题是:这是最好的解决scheme吗? 或者,在Gradle for Android,AAR和Maven风格的工件中,还有其他的东西可以让应用程序依赖于单个的L? 我担心图书馆可能发生的组合爆炸,以处理上游依赖的各种混合。 我也担心奇怪的应用程序实际上需要多个实现,我们是否可以可靠地指定这些依赖(例如,一个应用程序取决于L1和L2,因为这是应用程序的作者认为应用程序需要)。

我知道有一些应用程序阻止 排除依赖的方法(请参阅Joseph Earl对语法的回答),所以应用程序可以依赖L,但是如果不需要,可以阻止actionbarsherlock上游依赖。 虽然这可以起作用,但如果我是L的作者,我宁愿采用L1 / L2 / L3方法,因为这看起来更清洁。

还有其他build议吗?

Solutions Collecting From Web of "适用于Android的Gradle,AAR和条件依赖项"

我不知道任何依赖pipe理function,这将有助于这一点。

拥有一个具有多个依赖关系的库以及删除不需要的依赖关系的function可能会有效,但是会出现一些问题:

  • 你必须依靠L的用户去除正确的依赖关系。
  • 你会在图书馆上课,用Proguard不容易去掉。 Proguard不会删除任何扩展Fragment / Activity / etc的东西,而且L应该提供一个proguard规则文件,以便不移除扩展支持Fragment / Activity /等的类…这会使删除不需要的类变得困难。
  • 一些实现可能有额外的资源,现在我们不能去掉不需要的资源。

我认为分割图书馆是正确的事情,但是直到我们在图书馆项目中有口味之前,这将会变得很复杂。 一旦我们有了这个,我认为这将是更容易处理。 你不会有一个基础L1和L2 / L3扩展它。 相反,你会有一个生成不同变体的库,每个变体都有自己的依赖关系。

有了flavor的大小,你可以处理支持库和事件库组合,尽pipe如果你添加更多的维度,你肯定会得到一些爆炸。

多variables库的优势在于,在不引入更多子库的情况下,跨变体子集共享代码要容易得多。 你也可以在主代码和风味之间有双向的引用,这对L2 / L3来说是不可能的,这取决于L1。

至于支持Ant / Eclipse,这肯定会变得复杂。 我肯定会忽略ant。 如果有人只关心命令行构build,他们应该已经转移到Gradle。 至于Eclipse,我们在某些时候会支持Gradle,但是我明白,如果你不能等。

在你的应用程序项目中可以排除Gradle中的传递依赖(例如,如果你知道它不会被使用,那么排除ActionBarSherlock),例如

  dependencies { compile('org.hibernate:hibernate:3.1') { // Excluding a particular transitive dependency: exclude module: 'cglib' //by artifact name exclude group: 'org.jmock' //by group exclude group: 'org.unwanted', module: 'iAmBuggy' //by both name and group } } 

您也可以使用ProGuard (和DexGuard )来压缩和去除未使用的代码。

Gradle还不支持标记依赖项,就像Maven所做的那样(可以在库项目中使用)。

那么,我想提到的第一件事是Gradleconfiguration实际上是Ivyconfiguration的反映:您部署到某个存储库的模块可以具有不同的configuration,并且每个configuration可能都有自己的一组依赖关系。 http://www.gradle.org/docs/current/userguide/dependency_management.html#ssub:multi_artifact_dependencies

然而,Maven并不适合这种情况,因为在Maven世界中没有configuration。 并且工件分类器不会允许您拥有不同的依赖关系。

我们可以用Maven做什么是从POM中删除编译时间依赖声明或用provided范围标记它们。 AFAIK只能指定仅编译时间依赖的能力将在未来版本的Android Gradle插件中提供。 https://code.google.com/p/android/issues/detail?id=58626