【问题标题】:Replace Java file from main in just one product flavor仅在一种产品风格中替换 main 中的 Java 文件
【发布时间】:2019-04-03 01:46:20
【问题描述】:

我正在尝试为 Android 配置构建。该项目有多种风格,在一种风格中,我想替换 main 中的一些类。结构是这样的:

main - MyClass.java

flavorA, flavorB... flavorF 使用 main 的 MyClass.java,没有覆盖

flavorG 需要自己的 MyClass.java

我不想将 MyClass.java 复制到每个风味的目录中并从 main 中完全删除它,那将是不可维护的。有没有办法使用排除命令来完成这个?比如……

 + src
   + main
     + java
       MyClass.java
       other common files
     AndroidManifest.xml
   + flavorA
     + java
       other flavor-specific files
     AndroidManifest.xml
   + flavorG
     + java
        MyClass.java
        other flavor-specific files
     AndroidManifest.xml

使用这样的 gradle 设置...

productFlavors {
    flavora {
    }
    ...
    flavorg {
    }
}

sourceSources {
    flavora {
    }
    flavorb {
    }
    ...
    flavorg {
       main.java {
          exclude 'com/myapp/mypackage/MyClass.java'
       }
    }
}

以上不起作用,我做错了什么吗?还有其他选择吗?

【问题讨论】:

    标签: android gradle dagger-2


    【解决方案1】:

    您可以使用以下符号来控制 JAR 清单(特别是“Main-Class”属性)

    jar {
        manifest {
            attributes 'Main-Class': 'com.example.MyMain'
        }
    }
    

    与 Gradle 中的所有内容一样,它是一个 groovy 脚本,因此您可以使用条件包装其中的一部分,以根据您的需要分叉行为。

    假设您将风味作为 -P 标志传递(请参阅Gradle properties and system properties),例如gradle build -Pflavor=flavorg 以下应该可以工作:

    jar {
        manifest {
            if (flavor == "flavorg") {
                 attributes 'Main-Class': 'com.example.FlavoredMain'
            } else {
                 attributes 'Main-Class': 'com.example.GenericMain'
            }
        }
    }
    

    P.S,请记住,上述 Jar 闭包是在配置时评估的,而不是执行时间,这意味着主类条件是在评估任务之前决定的(参见 Build lifecycle)。


    安卓

    根据@Opals 评论(抱歉没有注意到)。要解决 Android 中的相同问题,最快的选择是为每个 flavorg 设置一个 AndroidManifest.xml,其余的

    android {
        sourceSets {
            main {
                manifest.srcFile 'main/AndroidManifest.xml'
            }
            flavorg {
                manifest.srcFile 'main/other/AndroidManifest.xml'
            }
        }
    }
    

    在 AndroidManifest.xml 中定义了主要活动。

    更好的选择是确保您遵守正确的文件夹结构

    + src
        + main
            + java 
            + res
            + AndroidManifest.xml
        + flavorg
            + java
            + res
            + AndroidManifest.xml
    

    flavorg 中的 AndroidManifest.xml 应该只包含与主 AndroidManifest.xml 的差异(即主活动更改),它们将根据选择的风格进行合并

    我建议您查看以下Merge multiple manifest filesGradle flavors for android with custom source sets - what should the gradle files look like?


    Android - 修改后的问题

    我会改为使用工厂模式,根据激活的风格返回正确的“MyClass”实例:

    productFlavors {
        main {
           buildConfigField "string", "APP_FLAVOR", "main"
        }
        flavorg {
           buildConfigField "string", "APP_FLAVOR", "flavorg"
        }
    }
    

    那么,在工厂就可以使用了:

    if (BuildConfig.APP_FLAVOR.Equals("flavorg") {
       return new FlavorgMyClass();
    } 
    return new MyClass();
    

    请参阅Gradle Tips,特别是“与您的应用代码共享自定义字段和资源值”部分

    【讨论】:

    • 但 OP 询问有关 android 应用程序的问题。它是为 jar 构建的吗?
    • 感谢您的回复。我没有覆盖一个 Activity,而是一个常规的 Java 类——特别是一个用作 Dagger 模块的类,所以它需要在编译时跨风格在同一个包中。我用现有的文件夹结构编辑了问题;为清楚起见,我已经在使用标准的 Android 文件夹布局。没有提供的是从一种风格中覆盖 main 中的 Java 类的能力,这是我试图通过“排除”来完成的。这有意义吗?
    • 嗯,这真的取决于你想要实现什么,你可能可以通过构建找到正确的方法来做到这一点,我的问题是“为什么?为什么要通过构建来解决它?”您在 Java 中有足够的机制来解决代码中的这个问题:您可以“推迟”决定加载哪个类(可能最好不要在同一个包中使用相同的类名)到创建点一个适当的工厂,可以对您构建代码的风格做出反应 - stackoverflow.com/questions/32813776/…
    • 我要切换的是一个 Dagger 模块,它引用了一个类类型作为方法参数,但你从来没有真正实例化这个类,否则是的,我可以很容易地使用一个工厂排序。但 Dagger 为您完成了这一切。根据stackoverflow.com/questions/34046289/… 之类的几个问题,解决方案是将组件移至每种口味,但正如我在顶部所说,我有很多口味,其中大部分都共享这些。试图降低复杂性,因此试图排除流氓风味。
    • 我相信工厂解决方案仍然可以工作,为什么你不能注入工厂而不是你想要的实例,然后从工厂获取它?我不知道你的确切用例,如果你甚至可以自己实例化这个类(虽然我希望你这样做,为了可测试性)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多