根据构建参数更改我的来源

Changing my sources according on the build parameters

TL;DR:根据传递给 gradle 的参数更改我的来源的干净方法是什么?


我正在构建一个 Android 应用程序,它依赖于库 A。我希望能够支持 A 的多个版本(假设我想同时支持 v1v2)。我的意思是我希望能够构建 myapp-withAv1.apkmyapp-withAv2.apk.

我发现在编译时很容易 select 我想要的 A 版本(例如,我可以在 build.gradle 的变量中引用这个版本文件,然后使用 ./gradlew -PversionOfA=v1 build).

启动构建

但是另一个困难是 A 可以更改它的 public API 所以我需要根据我正在构建的版本更改我的代码。如果我使用 C++ 或 C# 会很容易(感谢 #ifdef),但我一直无法找到一种方法来做到这一点而无需过多的代码重复,如果你能指出我,我会很高兴一种实现它的方法。

(请注意,尝试用 if(version == v1) 之类的东西来隔离代码分支是行不通的,因为它会导致代码分支调用 A 的方法,但该方法不可用,所以构建会失败)

我 运行 遇到过类似的问题,答案是 productFlavors in android 或 sourceSets for a generic jar。基本上你需要在每个源集中指定一个接口的实现。

# define the interface in the main
/src/main/java/com/me/IMyInterface.java
# create a v1 and v2 sourceset with the implementation, note paths are the same
/src/v1/java/com/me/MyImplementation.java
/src/v2/java/com/me/MyImplementation.java

现在在您的 gradle 中定义 productFlavors

android {
    productFlavors {
        v1 {
            buildConfigField 'string', 'FLAVOR', 'v1'
        }
        v2 {
            buildConfigField 'string', 'FLAVOR', 'v2'
        }
    }
    //...
}

现在,当您引用实现时,您将获得定义为产品风味名称的版本的 sourceSet

// since the package is the same we are unaware of which we are calling
// now we can treat them as the same regardless of the underlying
// implementation differences between v1/v2

import com.me.MyImplementation;

public String doSomethingWithImplementation() {

    MyImplementation impl = new MyImplementation();

    // here if we are executing in the productFlavor v1
    // apk we get the code from the v1 folder, same for v2 apk
    return impl.doSomething()
}

我在 2002 年为 J2ME 开发时也有类似的需求,所以开发了 a preprocessor, today it has support for maven,gradle and ant, you can try it for android, a test android project which can be used as sample can be found in the project repository 对于预处理器,Java sources look like that