使用多个模板/渠道构建单一APK

3

能否使用多个产品风味(product flavor)构建apk?

比如: 我有一个项目,包含3个不同的风味(App1 - App2 - App3), 每个应用都有自己的配置,例如applicationId等。

现在,我想要构建不同的模板(不同的XML布局),并且用户应该能够从应用内切换到另一个布局。

我的问题是res文件夹会变得非常庞大,而且很难维护,因此我正在寻找一种将不同布局分离并尽可能保持简洁的方法。

如果可以这样做,那么如何启动或重新启动应用程序以加载其他风味的构建版本?

我还考虑过在主res中构建所有XML文件,并选择不同的限定符,就像我们在创建不同屏幕大小(sm-larg等)时所做的那样,但我找不到添加自定义限定符的方法。

我的Gradle代码如下:

flavorDimensions "default"

    productFlavors {

        demo {
            applicationId "test.demo"
            versionCode 2
            versionName "1.1.2"
            resValue "string", "backage_name_file", "test.demo.fileprovider"
            resValue "string", "bc", "com.demo"
            resValue "string", "bc_e", "extra_data.com.demo"
            resValue "string", "default_hostname", "demo.test.com"
            resValue "string", "default_username", "demo"
            resValue "string", "default_password", "demo"
        }
         AppOne {
            applicationId "test.AppOne"
            versionCode 2
            versionName "1.1.2"
            resValue "string", "backage_name_file", "test.AppOne.fileprovider"
            resValue "string", "bc", "com.AppOne"
            resValue "string", "bc_e", "extra_data.com.AppOne "
            resValue "string", "default_hostname", "AppOne.test.com"
            resValue "string", "default_username", "AppOne"
            resValue "string", "default_password", "AppOne"
        }
          AppTwo {
            applicationId "test.AppTwo"
            versionCode 2
            versionName "1.1.2"
            resValue "string", "backage_name_file", "test.AppTwo.fileprovider"
            resValue "string", "bc", "com.AppTwo"
            resValue "string", "bc_e", "extra_data.com.AppTwo"
            resValue "string", "default_hostname", "demoAppTwotest.com"
            resValue "string", "default_username", "AppTwo"
            resValue "string", "default_password", "AppTwo"
        }
}

在我看来,如果你只是想根据用户输入切换布局,那么你不需要使用产品风味。这可以通过一些 if 语句轻松实现。 - theapache64
我已经在使用Flavors来生成多个APK,而且我不想使用if语句,因为如果我有50个XML文件并且每次想要创建新模板时都要复制粘贴它们,那将会太麻烦了。 - Hossam Hassan
我认为创建一个if语句比创建一个模块来切换布局更好。 - theapache64
好的,但我会遇到一些问题:首先,如果我有两个不同的布局(XML)文件,第一个将被称为mainactivity.xml,第二个模板将被称为mainactivity2,这将导致Java数据绑定出现问题。活动样式也是如此。您认为有更好的解决方案吗? - Hossam Hassan
我发现类似这样的内容 https://dev59.com/KF4c5IYBdhLWcg3wLXrI ,你可以添加子口味,但是在Java中如何调用它? - Hossam Hassan
2个回答

2
您不能使用多个flavour来构建APK,就像您不能同时在debug和release buildTypes中构建一个APK一样。所选的flavour的配置/资源被拉入实际的APK元数据/清单中,因此无法在运行时进行修改。
您需要将所有内容都放在res文件夹中,但有几种方法可以帮助您更轻松地管理。我建议前三个选项,如果您有大量具有不同行为的代码+布局文件,则建议使用第四个选项:
  1. 使用Fragments避免大部分Java/Kotlin代码需要复制。
  2. 包含XML布局而不是每次重新定义所有内容以重用常见元素。
  3. 仔细命名您的文件,例如template1_backgroundtemplate2_background
  4. 使用多个模块,每个“模板”一个模块。然后,您将拥有多个合理的res文件夹。
我能理解为什么flavour可能看起来像是解决方案,但由于您需要在一个应用中使用所有flavour,因此这种方法不幸地行不通。您可能会发现步骤#2将消除几乎所有重复文件,从而完全避免了问题!

使用多个模块听起来不错,但我发现唯一的问题是如何在Java类中调用它,我的意思是在片段/活动类中,如果temp == temp_1,则如何显示来自module_1的xml,如果我有Java类或样式在主src中,我如何在模块内调用它?据我所知,您可以访问模块内部的内容,但模块无法访问外部的内容。 - Hossam Hassan
如果你的app模块依赖于module1module2等,它可以从中调用任何东西(包括布局/Java类)。因此,app模块将控制适当的布局/类的加载。话虽如此,首先尝试步骤1和2是值得的,因为它们更容易(也是良好的实践)。 - Jake Lee
1
如果没有更简单的解决方案,我会先尝试找到一个,否则似乎我将选择使用片段选项。 - Hossam Hassan

0

您可以使用sourceSets命令合并不同flavour的资源。 SourceSet允许您配置buildVariants资源文件夹, 例如,您可以配置App2 flavour以包括App2 res文件夹和App1 res文件夹。 示例代码:

sourceSets {


        App2Debug{
            res.srcDirs = ['src/App1/res', 'src/App2/res']

        }

    }

拥有不同XML名称的多个资源将导致数据绑定问题。 - Hossam Hassan
你说数据库有问题?是什么问题? - OmerCohen1994
为了进行数据绑定,您需要按照以下方式在Java中设置XML:private FragmentHomePageViewBinding binding; binding = DataBindingUtil.inflate(inflater, R.layout.fragment_home_page_view, container, false); 现在,如果您有多个XML文件用于同一个Java类,则需要将第二个数据绑定重命名为binding2,第三个为binding3等等,这意味着当您在布局中设置文本视图或任何内容时,该类中会出现太多的重复。 - Hossam Hassan
我知道。但你还是不明白那引起的问题吗?它不知道布局吗? - OmerCohen1994
问题在于,如果我必须从API设置textview,则必须为每个绑定多次执行此操作,这不是最优的。您可以想象具有许多UI中的ID的类有多么大。 - Hossam Hassan

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