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

时间:2014-01-05 19:34:35

标签: android maven gradle android-gradle

简短表单:为AAR组织代码/ POM有哪些方法,例如使用该AAR的应用程序只有他们实际需要的依赖项?

长篇

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

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

  • L可能包含本地API Level 11片段的Fragment实现,反向移植的片段和ActionBarSherlock风格的片段

  • L可能包含Activity常规活动的实施,FragmentActivityActionBarActivity和ActionBarSherlock风格的活动

  • L可以通过LocalBroadcastManager,Square's Otto和greenrobot的EventBus

  • 举办活动
  • 等等

这些案例有两个主要的共性,正如我所看到的那样:

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

  2. 如果AAR是回购中的工件,则应用程序不会关心构建AAR所需的所有可能的上游依赖项。例如,使用本机API Level 11片段的应用程序不需要support-v4actionbarsherlock,即使AAR本身需要它们来构建AAR

  3. 如果我们使用JAR而不是AAR并转储依赖关系管理,这是相当简单的。构建JAR将具有编译时依赖性(例如,support-v4)。但是,使用该JAR的应用程序可以跳过这些依赖项,只要这些应用程序不使用真正需要这些依赖项的类,生活就会很好。

    但是,我很难看到如何使用build.gradle文件中指定的AAR和Maven工件完成相同的操作。如果L有一个dependencies块引用上游依赖项,那么当应用程序依赖于L时,应用程序将依次下载这些依赖项。

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

    • L1,包含本机API Level 11版本的片段的实现,以及其他场景所需的任何公共代码。该库没有上游依赖项。

    • L2,其中包含使用Android Support包的片段backport的实现。 L2会依赖于L1和support-v4

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

    然后,应用程序将选择是依赖于L1,L2还是L3,因此只会获得必要的上游依赖项(如果有的话)。

    我的问题是:这是最好的解决方案吗?或者Gradle for Android,AAR和Maven风格的工件世界还有什么东西可以让应用程序依赖单个L?我担心库的组合爆炸可能会处理各种上游依赖关系。我也关注实际需要多个实现的奇怪的应用程序,以及我们是否可以可靠地指定那些依赖项(例如,一个应用程序取决于L1和L2,因为这是该应用程序的作者认为应用需要)。

    我知道应用程序有一些方法可以阻止 排除依赖关系(请参阅Joseph Earl对语法的回答),因此应用程序可能依赖于L但是然后阻止actionbarsherlock上游依赖项(如果不需要)。虽然这可行,但对于我是L的作者的情况,我宁愿采用L1 / L2 / L3方法,因为这似乎更清晰。

    还有其他建议吗?

3 个答案:

答案 0 :(得分:6)

在您的应用程序项目中,可以在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)来压缩和删除未使用的代码。

Maven做的

Gradle doesn't yet support marking dependencies as optional(可以在图书馆项目中使用)。

答案 1 :(得分:6)

我不知道任何有助于此的依赖管理功能。

拥有一个具有许多依赖项的单个库并且能够删除不需要的依赖项可能会有效,但是会出现一些问题:

  • 您必须依赖L的用户来删除正确的依赖关系。
  • 您将在图书馆中拥有使用Proguard轻松剥离的课程。 Proguard不会删除任何扩展Fragment / Activity / etc的内容,L应该提供一个proguard规则文件,不要删除扩展支持Fragment / Activity / etc的类......这样就很难删除不需要的类。
  • 某些实施可能有额外的资源,现在我们无法删除不需要的资源。

我认为拆分库是正确的做法,但是在我们在图书馆项目中有风味之前要做到这一点很复杂。一旦我们有了这个,我认为处理起来会容易得多。你不会有基础L1和L2 / L3扩展它。相反,您将拥有一个生成不同变体的库,每个变体都有自己的依赖项。

对于风味尺寸,您可以处理支持库与事件库组合,但如果添加更多尺寸,您肯定会遇到一些爆炸。

多变量库的优点是,在不引入更多子库的情况下,跨变体子集共享代码要容易得多。您还可以在主代码和风格之间进行双向引用,而L2 / L3则不具备这些参考,具体取决于L1。

至于支持Ant / Eclipse,这肯定会变得复杂。我肯定会无视Ant。如果有人只关心命令行构建,他们应该已经转移到Gradle。 至于Eclipse,我们在某些时候会得到Gradle的支持,但我知道你是否等不及了。

答案 2 :(得分:0)

嗯,我首先要提到的是Gradle配置实际上是Ivy配置的反映:部署到某个存储库的模块可以有不同的配置,每个配置可能有自己的一组依赖项。 http://www.gradle.org/docs/current/userguide/dependency_management.html#ssub:multi_artifact_dependencies

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

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