Gradle 根据构建风格交换 jniLibs 资源

Gradle swap jniLibs resources based on build flavor

我正在尝试根据 release buildTypedebug buildType 文件夹交换 res/raw 文件夹和 jniLibs/armeabi 文件夹中的一些资源。我目前也有两种产品口味。

build.gradle 文件:

apply plugin: 'com.android.application'

android {
    dexOptions {
        preDexLibraries = false
    }

    compileSdkVersion 21
    buildToolsVersion "22.0.1"

    defaultConfig {
        applicationId "com.example.test"
        minSdkVersion 17
        targetSdkVersion 22
        compileOptions {
            sourceCompatibility JavaVersion.VERSION_1_7
            targetCompatibility JavaVersion.VERSION_1_7
        }
    }

    productFlavors{
        phone{
            applicationId "com.example.testPhone"
        }
        tablet{
            applicationId "com.example.testTablet"
        }
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
        }
    }

    sourceSets{
        release{
            res.srcDirs = ['androidRelease/res/raw']
        }
    }
}

dependencies {
    compile project(':facebook')

}

使用 sourceSet 的方法是否正确?如果是,应该创建什么文件夹,以便它仅根据 buildType 交换适当的资源,而不考虑 productFlavors?

编辑:是否可以交换 jniLibsraw 文件夹资源?

文件夹结构:

src/main/jniLibs/armeabi
phoneRelease/jniLibs/armeabi
tabletRelease/jniLibs/armeabi 

文件夹结构是否正确?

编辑 2: 根据 Xavier 的回答,gradle 应该是这样的:

android {

      sourcesets {
        phone {
          jniLibs.srcDirs = ['phoneRelease/jniLibs/']
          res.srcDirs = ['androidRelease/res/raw']
        }
        tablet {
          jniLibs.srcDirs = ['tabletRelease/jniLibs/']
          res.srcDirs = ['androidRelease/res/raw']
        }
      }
    }

我一直在阅读很多相互矛盾的答案,其中一些提到您只需要基于构建变体的单独文件夹,还有一些提到必须使用 sourceSet? 谢谢!

要使用风格来改变源集,

productFlavors{
    phone{
    }
    tablet{
    }
}

现在构建你的代码,

src
  main
  phone
  tablet

main 中的代码在两种风格之间是通用的,但 phonetablet 中的代码仅在构建各自的风格时包含。就是这样,你不需要做任何其他事情。

phonetablet 下的结构与 main 下的相同(resjava 等)。也可以在flavor目录下自定义AndroidManifest.xml。 Gradle 尝试将 flavor 的 AndroidManifest.xml 与 main 中的合并。在某些情况下,您必须提供有关如何合并的规则。

通常在 src/main/ 下的任何内容都可以放在不同的文件夹中:

src/<element>/AndroidManifest.xml
src/<element>/java
src/<element>/res
src/<element>/assets
src/<element>/resources
src/<element>/jni
src/<element>/jniLibs
src/<element>/aidl
src/<element>/rs

其中 elementbuild typeproduct flavor 的名称。如果您的变体包含这样的元素(构建类型或风格),那么除了 src/main

之外,还会使用该源集

请注意,如果您配置了位置,则该位置确实无关紧要。 重要的是有一个 android.sourcesets.main 元素包含所有变体共有的源,每个变体都有一组源集。

例如,如果您有一种风格 phoneRelease,它实际上使用了以下资源集:

android.sourcesets.main
android.sourcesets.phone
android.sourcesets.release
android.sourcesets.phoneRelease

如果您有另一个变体 tabletRelease,它将使用以下内容:

android.sourcesets.main
android.sourcesets.tablet
android.sourcesets.release
android.sourcesets.phoneRelease

所以 phone/tablet 源集是不同的,它是你放置变体特定源的地方,除非你想更具体并使用 phoneRelease/ tabletRelease sourcesets(尽管这些通常较少使用。)默认情况下,这些将是 src/phone/...src/tablet/...(或 src/phoneRelease/...),但您可以根据需要更改它,只要因为它连接到 android.sourcesets.* 个对象,所以没问题。

例如,做:

android {
  sourcesets {
    phone {
      jniLibs.srcDirs = ['phoneRelease/jniLibs/']
    }
    tablet {
      jniLibs.srcDirs = ['tabletRelease/jniLibs/']
    }
  }
}

很好。但请注意,您只更改了 jniLibs 文件夹,而没有更改其他源元素(java、res 等...)

如果您保留 main 源集的默认位置,我会将所有内容保留在 src/

您可以在此处查看有关源集以及多个源集如何组合的更多信息:http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Sourcesets-and-Dependencies

some of them mention that you just need separate folders based on build variant and some mention about having to use sourceSet?

Gradle/Gradle for Android 具有预期的源集结构:

  • Android 资源在 res/
  • Java java/
  • 中的源代码树
  • jniLibs/
  • 中的预编译 JNI 库
  • 资产在assets/
  • 等等

sourceSets 闭包发挥作用的地方是,对于给定的源集,您想要一个不同的结构:

  • Android 资源位于 foo/
  • Java bar/
  • 中的源代码树
  • ickyNativeStuff/
  • 中的预编译 JNI 库
  • 资产在assetsBecauseThatSeemsLikeADecentName/
  • 等等

每个构建类型、产品风格和构建变体都可以有一个单独的源集(androidTest 可以用于仪器测试),与 main 一起使用。它们的名称与构建 type/product flavor/build 变体相同。这些将在库存结构中,除非您使用 sourceSets 进行更改。

所以,一路滚回:

I am trying to swap some resources in the res/raw folder and the jniLibs/armeabi folder based on whether its a release buildType or a debug buildType

在资源的情况下,其他源集覆盖 main。因此,如果您有 src/main/res/...src/main/debug/... 以及 src/main/release/...,并且您正在进行 debug 构建,则 src/main/release/... 中的任何内容都将被忽略(因为我们没有t 做 release) 并且 src/main/res/...src/main/debug/... 中的任何内容都将被使用。如果两者(src/main/res/raw/boom.oggsrc/debug/res/raw/boom.ogg)中有相同的资源,则 debug 胜过 main

我还没有尝试通过构建变体来改变 jniLibs/。我的猜测是它的行为更像 Java 代码,其中构建变体的源集中的内容与 main 中的内容不会有冲突,但这只是一个猜测。因此,您可以在 src/debug/jniLibs/ 中获得已编译 JNI 代码的调试版本,在 src/release/jniLibs/ 中获得已编译 JNI 代码的发布版本。只有 src/main/jniLibs/ 中没有变化的库。话虽这么说,正如我提到的,我还没有尝试过这个,所以这里可能会有问题。

所以,我希望您在 build.gradle 中没有 sourcesets 闭包,并且只使用 stock sourcesets 结构,用于您的各种位:

src/
  main/
    ...
  debug/
    jniLibs/
    res/
      raw/
  release
    jniLibs/
    res/
      raw/