Gradle Android依赖项产品风格

7
我希望了解一个根项目是否能够在其依赖项中定义/注入一些属性。更具体地说,我遇到的问题是,在运行组装/编译任务之前,库项目必须知道是否要使用“免费”或“专业”Java源和其他资源。有点像为继承自其父项目的库项目指定产品风味,但这不受Gradle Android插件的支持。更改库项目结构,即创建“免费”和“专业”库,不是一个选项。
编辑: 到目前为止,我最成功的做法类似于这样:
根:build.gradle
android {
    ...

    productFlavors {
        free, pro
    }

    sourceSets {
        free {
            project(':..:lib') {
                groupFreePro = 'free'
                // java.srcDirs = ['src', 'free/src']
             }
        }

        pro {
            project(':..:lib') {
                groupFreePro = 'pro'
                // java.srcDirs = ['src', 'pro/src']
            }
        }
    ...
    }
}

library: gradle.build

android {
    ...
    sourceSets {
        main {
                  java.srcDirs = [groupFreePro + '/src']
                  res.srcDirs = [groupFreePro + '/res']
             }
        }
    ...
    }
}

这样我就可以将 groupFreePro 变量注入到 lib 项目中。但是这种方法存在一个问题:

当 lib 项目到达它的 android -> sourceSets 任务时,groupFreePro 总是设置为 "pro"。我认为这是因为根项目中读取了所有 sourceSets(而不仅仅是我想要构建的一个变体;例如 "free")因此最后一个 set/task 始终会覆盖先前设置的任何 groupFreePro 的值。

如果我尝试以其他方式设置 groupFreePro 的值,它要么被覆盖(如上述情况),要么我不知道应该在哪个任务/时间/地点调用此变量注入操作以将变量设置为所需的值。取消注释根项目中的 java.srcDirs 也没有帮助。

我曾试图自己解决这些问题,但我对 Gradle 还很陌生,而且缺乏适当的文档(至少对于 Android 部分)常常让我猜测该做什么,因此我做了很多尝试和错误(但现在我有点卡住了)。


你尝试过将“library”项目变成普通项目吗?Gradle的依赖管理意味着你可以将任何项目几乎像库项目一样使用。 - Saad Farooq
我曾经尝试过,但是在构建过程中遇到了其他问题。我认为问题出在其他库以普通项目的形式构建后,生成的 APK 文件无法被构建系统(或者说是我)包含到主项目/APK 中。不过我可能会再试一次,看看能否用不同的方式解决这个问题。 - croc
你能分享一下那个设置的代码吗? - Saad Farooq
您想让我分享哪个设置的代码?是那个将库构建为项目的设置吗? - croc
抱歉回复晚了... 我的意思是你使用标准项目依赖而不是库依赖的代码。我认为很明显这在库中是不可能实现的。我用 ant 做过类似的事情,但需要研究一下 gradle 的实现。 - Saad Farooq
显示剩余3条评论
4个回答

6
这是我目前解决问题的方法。虽然不是完美的解决方案,但现在足够好了。

更新!

我已经更新答案,包括最新0.9.2 Gradle插件及其新特性(主要更新了库构建脚本)。

根目录:gradle.build

// global variables
ext {
    // can be set to default values or blank
    groupFreePro = "free"
}

// start parameters
println "Start parametes: tasks = " + gradle.startParameter.getTaskNames()

gradle.startParameter.getTaskNames().each { task ->
    if (task.contains("Free") || task.contains("F")) {
        groupFreePro = "free"
    } else if (task.contains("Pro") || task.contains("P")) {
        groupFreePro = "pro"
    }
    println "groupFreePro = " + groupFreePro
}

android {
...
}

task.contains("F") 是用来处理缩写版本或运行任务的(如果我们想要将脚本作为 gradle aFD 运行)。

ext 下的全局变量可以设置默认值。在这种情况下,即使没有在任务名称中指定 "Free/Pro",运行脚本也应该正常工作。默认值的缺点是,如果未正确设置,则构建可能不会崩溃(如果希望仅在任务名称中指定了 "Free/Pro" 时才能使构建正常工作)。

库: gradle.build

android {
...
    defaultPublishConfig groupFreePro + groupDebugRelease.capitalize()

    productFlavors {
        free
        pro
    }

    ...
    sourceSets {
        main {
            java.srcDirs = ['/src']
            res.srcDirs = ['/res']
        }

        free {
            java.srcDirs = ["free/src"]
            res.srcDirs = ["free/res"]
        }

        pro {
            java.srcDirs = ["pro/src"]
            res.srcDirs = ["pro/res"]
        }
    }
    ...
}

dependencies {
    freeCompile fileTree(dir: 'free/lib', include: '*.jar')
}

更新:该库现在包含defaultPublishConfig,因此我不需要指定。
        java.srcDirs = ["src", groupFreePro + "/src"]
        res.srcDirs = [groupFreePro + "/res"]

现在可以使用定制的编译风格,例如在“dependencies”块中使用flavor1Compile。写入compile project(path: ':project', configuration: 'flavor1Debug')选项在“dependencies”块中并不能真正地为我们工作,因为你必须通过依赖项传递这些选项,如果你有多个风味组/维度,这意味着几乎所有的风味组合都必须在“非最后”依赖项中处理(即具有其他依赖项(具有多个风味))。 println行只是为了查看并确保正确的参数被传递。
这种解决方案的好处(与Varun相比)是你只需要运行一个(原始)任务。这也意味着它可以在Android Studio中无问题地工作(或者至少应该可以)。
这种解决方案的缺点是,如果你想使用gradle assemble命令(或类似命令)构建所有变体,那么它就不起作用了(或缺少任务的Free部分)。我猜也可以处理,但我现在不做那个,因为当前的解决方案对我来说已经足够好了(尽管如果我改进当前的解决方案,我可能会更新这个答案)。
通过使用gradle.taskGraph.whenReady也可以有其他解决方案,但我不知道如何正确设置依赖项的srcDirs(特别是)。欢迎提出建议。

@croc 谢谢你的发布。 :D 让事情变得更容易了。 - Varun
我稍微更新了答案,包括新的0.9.2 Gradle插件可能的更改。欢迎提出建议/意见。 - croc

3

在 Android 的 Gradle 插件版本 0.9 之后,该功能现已可用。

请参阅此处:http://tools.android.com/tech-docs/new-build-system/migrating_to_09

以下是复制的内容:

库项目的 DSL 现在与应用程序项目相同。这意味着您可以创建更多的构建类型和口味。
- 您可以在 buildTypes {...} 容器中创建/配置更多的构建类型。
- 您可以使用 productFlavors {...} 容器创建产品口味。
- 您可以使用 signingConfigs {...} 容器创建签名配置。

例如,如果您的库中有:

android {
    debug {
    }
    release {
    }
    debugSigningConfig {
    }
}

您需要将其替换为:

您需要用以下内容进行替换:

android {
    buildTypes {
        debug {
        }
        release {
        }
    }
    signingConfigs {
        debug {
        }
    }
}

我知道,我正在研究它。 - croc

3

这里LibraryVariant这里ApkVariant

由上述的DSL可以看出,LibraryVariant类型不支持多个productFlavors

如果你的免费版/专业版没有太大变化,您可以为专业版和免费版分别创建一个aar文件,并根据需要将它们用作依赖项。

更新:

我在GitHub上有一些代码。它能工作,但需要在实际构建/组装应用程序任务之前调用另一个任务。 https://github.com/varunkochar/Trying-Android-Gradle/tree/master/FakeLibraryProductFlavors

更新:

使用最新的Android Gradle插件v0.9.0,LibraryProject现在也支持与ApplicationProject相同的DSL。因此,您可以使用最新版本并使用库项目的内置功能来构建自定义风格。 来源:http://tools.android.com/tech-docs/new-build-system


请看我的编辑,我已经扩展了我的问题。很遗憾,你的建议不足以带给我一个可行的解决方案。你能否提供一个build.gradle脚本的工作示例? - croc
1
@croc 看看这里。https://groups.google.com/forum/#!topic/adt-dev/wjH5M7dPo-0 看起来有人已经向adt-dev团队提出了这个问题。希望将来能够支持这个功能。 - Varun
1
@croc 我已经将一些代码上传到 GitHub。https://github.com/varunkochar/Trying-Android-Gradle/tree/master/FakeLibraryProductFlavors。这是一个可行但不够好的解决方法。在编译应用程序代码之前需要调用额外的 gradle 任务。 - Varun
1
@croc 我有很多积分。 :) 只是想帮助解决这个问题,因为许多其他开发人员可能会面临同样的问题。你可能可以等一下再标记我的答案为已接受,因为其他人可能会提出更好的方法。 - Varun
1
我知道 :P 我曾经考虑过这个问题,但既然你帮了我而且还有悬赏,我觉得把奖励也给你是公平的 :) 至于答案,如果有人提出更好的解决方案,我仍然可以接受那个答案。 - croc
显示剩余7条评论

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接