带有子项目的 Android Gradle 构建

Posted

技术标签:

【中文标题】带有子项目的 Android Gradle 构建【英文标题】:Android Gradle build with sub projects 【发布时间】:2013-06-03 00:13:40 【问题描述】:

我目前正在将我们的一个项目从 maven 转换为 Gradle。文件夹结构如下:

gitRoot
    settings.gradle
    build.gradle
    ProjectA
        build.gradle
        src/main/java
    Libraries
        SomeLib (git submodule)
        ProjectBRoot (git submodule)
            settings.gradle
            build.gradle
            ProjectB
                build.gradle
                src/main/java
            Libraries
                FacebookSDK/facebook
                    build.gradle
                    src

所以看起来已经很复杂了。但这个想法是 ProjectB 是一个库项目,它应该能够单独构建和打包,这就是它有自己的 settings.gradle 的原因,据我所知,它似乎工作正常,我有它构建并且它找到 facebook 就好了。

ProjectB/build.gradle 包含这一行

compile project(':libraries:facebook-android-sdk:facebook')

ProjectBRoot/settings.gradle 包含这一行

include ':ProjectB', ':libraries:facebook-android-sdk:facebook'

gitRoot/settings.gradle 包含这一行

include ':ProjectA', ':Libraries:ProjectBRoot:ProjectB'

ProjectA/build.gradle 包含这一行

compile project(':Libraries:ProjectBRoot:ProjectB')

当我运行构建时,我得到了这个错误

The TaskContainer.add() method has been deprecated and is scheduled to be removed in Gradle 2.0. Please use the create() method instead.

FAILURE: Build failed with an exception.

* Where:
Build file '/gitRoot/Libraries/ProjectBRoot/ProjectB/build.gradle' line: 17

* What went wrong:
A problem occurred evaluating project ':Libraries:ProjectBRoot:ProjectB'.
> Project with path ':libraries:facebook-android-sdk:facebook' could not be found in project ':Libraries:ProjectBRoot:ProjectB'.

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.

BUILD FAILED

Total time: 4.652 secs

所以我的猜测是,facebook 不在 ProjectB 的直接子文件夹中……但在 ProjectBRoot 中构建时,这并不重要。这可能是由于我直接引用 ProjectB 而不是通过 ProjectBRoot/gradle.build 的面孔,但我尝试过它也没有工作。有人可以帮帮我吗,我已经查看了文档,它没有谈论多个项目都有自己的 settings.gradle 文件,我认为这就是让我感到困惑的事情。

更新:

所以我按照 Xav 的回答,现在可以使用命令行进行构建,但是我无法使用 android studio 导入/构建。我知道问题仍然出在 facebook 项目上。我得到的错误是它无法配置 ProjectB。

 Gradle: A problem occurred configuring project ':ProjectA'.
   > Failed to notify project evaluation listener.
     > A problem occurred configuring project ':Libraries:ProjectBRoot:ProjectB'.
       > Failed to notify project evaluation listener.
         > Configuration with name 'default' not found.

错误是由线路引起的

 compile project(':facebook-sdk')

在 ProjectB/build.gradle 中

【问题讨论】:

【参考方案1】:

遇到同样的问题,就我而言,我只是忘记在settings.gradle 中添加项目。之后就成功了

【讨论】:

【参考方案2】:

我终于设法构建了项目(没有 gradle 错误)。 Xavier 的回答非常有帮助。

我花了将近 3 天时间尝试设置我的项目,我知道我非常接近完成,但在 gradle 构建过程 (dexDebug) 的最后一步出现了 UNEXPECTED TOP-LEVEL EXCEPTION。

我的项目设置与 Stoyan 的非常相似,但是我有多个引用 android-support 库的 android-library 项目。我建议如果你在编译你的***根项目时遇到问题(错误说已经添加了支持 android),那么你需要将 jar 移动到单独的 android 库项目中(分解/分离成独立实例)。

例子

--| ProjectARoot
--| ProjectA (where main/java etc are)
  --| build.gradle
--| settings.gradle
--| libraries
  --| ProjectBRoot
    --| settings.gradle
    --| ProjectB
    --| libraries
       --| android-supports (android lib project)
         --| libs
           --| android-support-v4.jar
           --| android-support-v13.jar
         --| build.gradle
       --| libA
         --| build.gradle (referencing android-supports)'

libA 引用 android 支持项目的示例构建脚本

buildscript 
  repositories 
      maven  url 'http://repo1.maven.org/maven2' 
  
  dependencies 
      classpath 'com.android.tools.build:gradle:0.4'
  

apply plugin: 'android-library'

dependencies 
  compile project(':android-support')


android 
  compileSdkVersion 17
  buildToolsVersion "17.0.0"

  defaultConfig 
      minSdkVersion 7
      targetSdkVersion 17
  

// ***根设置.gradle

include 'ProjectB', 'android-support', ':ProjectA' (notice Project B is first than android-support and lastly Project A)

project(':android-support').projectDir = new File('libraries/ProjectBRoot/libraries/android-support')
project(':ProjectB').projectDir = new File('libraries/ProjectBRoot/ProjectB')

目前当我运行 gradle build 时出现此错误

:ProjectA:dexDebug

UNEXPECTED TOP-LEVEL EXCEPTION:
java.lang.IllegalArgumentException: already added: Landroid/support/v4/accessibilityservice/AccessibilityServiceInfoCompat;
at com.android.dx.dex.file.ClassDefsSection.add(ClassDefsSection.java:123)
at com.android.dx.dex.file.DexFile.add(DexFile.java:163)
at com.android.dx.command.dexer.Main.processClass(Main.java:490)
at com.android.dx.command.dexer.Main.processFileBytes(Main.java:459)
at com.android.dx.command.dexer.Main.access$400(Main.java:67)
at com.android.dx.command.dexer.Main$1.processFileBytes(Main.java:398)
at com.android.dx.cf.direct.ClassPathOpener.processArchive(ClassPathOpener.java:245)
at com.android.dx.cf.direct.ClassPathOpener.processOne(ClassPathOpener.java:131)
at com.android.dx.cf.direct.ClassPathOpener.process(ClassPathOpener.java:109)
at com.android.dx.command.dexer.Main.processOne(Main.java:422)
at com.android.dx.command.dexer.Main.processAllFiles(Main.java:333)
at com.android.dx.command.dexer.Main.run(Main.java:209)
at com.android.dx.command.dexer.Main.main(Main.java:174)
at com.android.dx.command.Main.main(Main.java:91)
1 error; aborting
:ProjectA:dexDebug FAILED

【讨论】:

第一个 android-support-v13.jar 包含 android-support-v4.jar 中的类(旧的构建系统会同时检测并删除 -v4.jar),因此您应该只使用 -v13。罐。其次,不要直接使用那些罐子。使用我们在“存储库”SDK 组件中发布的新工件。只需编译 'com.android.support:support-v13:13.0.0' 谢谢,用 v13 工件替换 support v4 jar 为我解决了上述问题。 为什么你的settings.gradle不止1个?【参考方案3】:

settings.gradle 必须定义所有模块。它不会加载树中找到的其他 settings.gradle 来加载更多模块。

你必须要么

    在顶层 settings.gradle 中为 facebook SDK 定义一个模块。是的,它与其他 settings.gradle 是多余的。

    以某种方式发布项目 B(以及它的依赖项,因此在本例中为 facebook SDK 库),在某处(例如公司工件存储库)并从项目 A 访问它。

虽然 #1 更好,但它使 ProjectB -> Facebook 依赖项变得棘手,因为路径会根据所使用的 settings.gradle 有所不同。解决此问题的一种方法是将模块名称/路径与其在磁盘上的实际位置分开。这是在 settings.gradle 文件中完成的。

在您的*** settings.gradle 文件中,执行

include 'facebook-sdk'
project(':facebook-sdk').projectDir = new File('Libraries/ProjectBRoot/Libraries/FacebookSDK/facebook')

在项目 B 中的 setting.gradle 文件中,对不同的相对路径执行相同操作:

include 'facebook-sdk'
project(':facebook-sdk').projectDir = new File('Libraries/FacebookSDK/facebook')

这使得两个项目设置都定义了位于磁盘上相同绝对位置的相同“facebook-sdk”模块。

依赖于这个模块的所有项目都应该将依赖声明为

compile project(':facebook-sdk') 

【讨论】:

我已经厌倦了包含 'facebook-sdk' 但 gradle 抱怨此错误:What went wrong: A problem occurred evaluating settings 'ProjectA'. > Project with path 'Facebook-sdk' could not be found. 我也尝试过 ':facebook-sdk' (带冒号)但给出完全相同的错误。我试过project(':facebook-sdk').projectDir = new File('...'),但我不确定我应该在括号中指定什么。我真的很感激一个详细的例子。 对此进行了一些调整,以确保支持库以类似的方式工作,并且事情似乎在从命令行运行 assemble 时正常工作,将继续运行,看看是否还有其他问题 感谢您回答这个问题(以及我在网上看到的许多其他问题)。但这仍然成立吗,是否有计划改变这种行为,或者至少添加某种支持以使子项目完全封装自己的依赖项?对于复杂的项目,这似乎是一个非常严重的限制。我什至对为什么/如何选择这条路线感到困惑(要求***项目参考子项目)。 @minsk 您实际上可以在 settings.gradle 中放入一些代码来读取并解析其他 settings.gradle (我认为)。这更像是一个一般的 Gradle 问题。我会在他们的用户论坛上询问 (http://forums.gradle.org) 啊,感谢您指出这一点,我通常不了解什么是 android vs gradle。仅供参考,此链接在单击时以某种方式损坏(冒号在 chrome 中消失)【参考方案4】:

这不是您要寻找的答案,但是...

我花了大约 4 天时间尝试将我的复杂项目结构(实际上很像你的)迁移到 gradle。最后,我放弃了整个子项目的概念(因为在我的情况下,它只是不起作用),我选择使用本地 maven 存储库的方法,如本文所述:http://www.flexlabs.org/2013/06/using-local-aar-android-library-packages-in-gradle-builds

所以,在我的包含子项目的库项目中,我基本上为每个子项目创建了完整的库项目,然后我使用上面的链接将它们发布到 maven 本地存储库。然后在父项目中,我删除了对子项目的所有引用,而在依赖项中,我只是引用了已发布的库。然后在我的主项目中,我删除了对子项目的所有引用,并引用了我的库的已发布 maven 本地版本。

最后,一切都很好,但确实需要一些时间来转换所有内容。我有大约 6 个带有子项目的库项目,那个子项目等等,现在一切正常。

我不喜欢 Gradle 和 Maven 等系统的一点是,它们确实希望您改变构建代码/项目的“方式”。因此,如果您迁移到 Gradle 与从 Gradle 开始,那么这个过程可能会非常令人沮丧。一旦你弄清楚了,下一次就容易多了;)

【讨论】:

假设您没有从不同的约定开始,这是“约定优于定制”。在那种情况下,它几乎只是好运......【参考方案5】:

我只想让应用程序与库都处于同一级别。您仍然可以基于 build.gradle 文件构建和打包每个库。我可能遗漏了一些东西,但结构并不像 build.gradle 文件中的那样重要。您仍然可以让 projectB 依赖于 Facebook,即使它们位于同一文件夹级别。

【讨论】:

以上是关于带有子项目的 Android Gradle 构建的主要内容,如果未能解决你的问题,请参考以下文章

gradle构建聚合工程

Qt 建立带有子项目的工程

Jenkins 使用 gradle 子项目构建

Android Studio的settings.gradle文件

在 Xcode 中指定子项目的配置

如何发布带有远程依赖项 (gradle) 的 Android 库 (aar)?