173

请注意:答案在 Xavier 的回答之后编辑

我正在尝试为 Android Studio 中的同一个应用程序项目使用不同的构建风格。但是,我似乎很难将其配置为正常工作。

脚步:

  1. 创建一个名为“Test”的新 Android Studio 项目。
  2. 打开 build.gradle* 并添加以下行:

    productFlavors {
    flavor1 {
        packageName 'com.android.studio.test.flavor1'
        }
    flavor2 {
        packageName 'com.android.studio.test.flavor2'
        }
    }
    
  3. 重新启动 Android Studio 后,我现在在 Build Variants 部分下看到了4 个构建变体。这意味着到目前为止,我们成功地设置了产品口味。**
  4. 为flavor1创建了一个新的 Source 文件夹;但是,我不确定我是否以正确的方式进行操作。我是这样做的:

    • 请记住,我的这个项目的包名称是:com.foo.test
    • 右键单击src文件夹,对于 flavor1,我实际上在资源管理器中创建了各个文件夹,其结构为src/flavor1/java/com/foo/test/MainActivity.java.
    • 上面的工作很好,因为“java”文件夹是蓝色的,这意味着 IDE 知道它是一个活动的源目录。此外,包是自动创建的。尽管如此,我还是收到了发现重复类的警告。请参阅此处的屏幕截图。
    • 对于flavor2,我尝试手动创建包,但是flavor2的'src'文件夹似乎不是蓝色的,因此右键单击时选项不同,并且我无法使用'New Package'。在此处查看图片。
    • 请注意,对于flavor1,我还创建了一个“res”目录,它确实变成了蓝色,但尽管如此,它不提供创建Android资源文件或Andorid资源目录的能力,以防我想使用不同的不同口味的资源。

难道我做错了什么?还是我错过了什么?如果您需要更多信息,请告诉我。

*我的项目似乎有两个build.gradle 文件。一个位于项目文件夹的根目录 (\GradleTest),这个是空的。第二个位于 \GradleTest 子文件夹的根目录,也标记为“GradleTest”(GradleTest-GradleTest),这是打开时已经有代码的那个;因此,那是我编辑的那个。

** 我检查了 gradle 设置,显然已经启用了使用自动导入。尽管如此,对 build.gradle 文件进行更改并不会自动更新构建变体。注意:我也尝试过使用 Build - Rebuild Project 和/或 Build - Make Project,不行。我仍然必须关闭项目,然后重新打开才能使更改生效。

4

7 回答 7

225

如果您进入 Studio 首选项,在 Gradle 部分下,您可以为您的项目启用自动导入(稍后我们将默认启用此功能)。这将使 Studio 在您编辑时重新导入您的 build.gradle。

创建风味并不意味着您将为它们使用自定义代码,因此我们不创建文件夹。您确实需要自己创建它们。

如果您查看我的 IO 演讲,您会看到我们如何将风味和构建类型中的值混合在一起以创建变体。

对于 Java 源代码:

src/main/java
src/flavor1/java
src/debug/java

都是 3 用于创建单个输出。这意味着他们不能定义同一个类。

如果您想在两种风格中拥有同一类的不同版本,则需要在两种风格中创建它。

src/flavor1/java/com/foo/A.java
src/flavor2/java/com/foo/A.java

然后你在 src/main/java 中的代码就可以了

import com.foo.A

根据选择的风味,使用正确版本的 com.foo.A。

这也意味着 A 的两个版本必须具有相同的 API(至少对于 src/main/java/... 中的类使用的 API 而言)

编辑以匹配修改后的问题

此外,重要的是仅将相同的 A 类放在互斥的源文件夹中。在这种情况下 src/flavor1/java 和 src/flavor2/java 永远不会一起选择,但 main 和 flavor1 是。

如果你想以不同的风格提供不同版本的活动,请不要将它放在 src/main/java 中。

请注意,如果您有 3 种风味,并且只希望为风味 1 定制一个风味,而风味 2 和风味 3 共享相同的活动,您可以为这两个其他活动创建一个公共源文件夹。您可以完全灵活地创建新的源文件夹和配置源集以使用它们。

关于你的其他观点:

2nd flavor source 文件夹不是蓝色是正常的。您需要切换到 2nd flavor 来启用它,然后您就可以在其中创建包和类。在此之前,Studio 不会将其视为源文件夹。我们希望在未来改进这一点,使 IDE 能够识别那些不活动的源文件夹。

我认为在 res 文件夹中不能创建资源文件也是正常的。菜单系统尚未更新以处理所有这些额外的资源文件夹。这将在稍后出现。

于 2013-05-25T05:30:07.430 回答
19

Android 上的“产品风味”

有时我被问到如何使用不同的主机、图标甚至包名称,这取决于同一应用程序的不同版本。

这样做的原因有很多,而且有一种简单的方法:产品风味。

你可以在你的 build.gradle 脚本中定义我之前描述过的这些东西。

产品风味 本文的一部分是对产品风味的思考,那么,它们是什么?关于Android文档:

产品风格定义了项目构建的应用程序的定制版本。单个项目可以有不同的风格,这些风格会改变生成的应用程序。

你如何定义它们?你必须在你的 build.gradle 上写下你想要定义的风格:

productFlavors {  
        ...
        devel {
            ...
        }

        prod {
            ...
        }
    }

现在,我们将拥有两种不同风格的应用程序。您也可以在 Android Studio 的 Build Variants 选项卡中查看它

构建变体

多个包名

如果您想在手机上安装一个处于开发状态的应用程序和一个用于生产状态的应用程序怎么办。您可能知道,您只能安装一个具有相同软件包名称的应用程序(如果您尝试安装一些与手机上安装的相同的新 APK,它会尝试更新它)。

您唯一需要做的就是在每种产品风味上定义它:

android {  
    productFlavors {
        devel {
            applicationId "zuul.com.android.devel"
        }
        prod {
            applicationId "zuul.com.android"
        }
    }
}

根据风味向多个主机发送请求和以前一样,您必须在产品风味配置字段中包含一些参数。

android {  
    productFlavors {
        devel {
            applicationId "zuul.com.android.devel"
            buildConfigField 'String', 'HOST', '"http://192.168.1.34:3000"'

        }

        prod {
            applicationId "zuul.com.android"
               buildConfigField 'String', 'HOST', '"http://api.zuul.com"'

        }
    }
}

作为示例,我们将尝试向您展示如何将其与 Retrofit 集成以将请求发送到适当的服务器,而无需根据风格处理您指向的服务器。在这种情况下,这是 Zuul android 应用程序的摘录:

public class RetrofitModule {

    public ZuulService getRestAdapter() {
        RestAdapter restAdapter = new RestAdapter.Builder()
                .setEndpoint(BuildConfig.HOST)
                .setLogLevel(RestAdapter.LogLevel.FULL)
                .build();
        return restAdapter.create(ZuulService.class);
    }

}

如您所见,您只需使用 BuildConfig 类来访问您刚刚定义的变量。

任何可通过您的代码获得的变量 HOST 变量并不是您可以在代码中公开的唯一变量。您可以随心所欲地做到这一点:

prod {  
    applicationId "zuul.com.android"
    buildConfigField 'String', 'HOST', '"http://api.zuul.com"'
    buildConfigField 'String', 'FLAVOR', '"prod"'
    buildConfigField "boolean", "REPORT_CRASHES", "true"
}

您可以按如下方式访问它们:

BuildConfig.HOST  
BuildConfig.FLAVOR  
BuildConfig.REPORT_CRASHES  

每种口味不同的图标如果您想每种口味有不同的图标,这样您就可以直观地检测出您正在打开哪个图标(您也可以通过名称来做到这一点......但它不适合空间!),您只需为每种口味定义新的目录结构。

在我刚刚使用的示例中,有两种风格:devel 和 prod。然后,我们可以定义两个新的目录结构,这样我们就可以定义我们想要的资源:

结构体

这适用于其他类型的资源strings.xml, integers.xml, arrays.xml,例如 等。

配置签名设置

要使用 Gradle 构建配置为您的发布构建类型手动配置签名配置:

1.创建一个密钥库。密钥库是包含一组私钥的二进制文件。您必须将密钥库保存在安全可靠的地方。2.创建私钥。私钥表示要通过应用程序标识的实体,例如个人或公司。3.将签名配置添加到模块级的build.gradle文件中:

android {
...
defaultConfig {...}
signingConfigs {
    release {
        storeFile file("myreleasekey.keystore")
        storePassword "password"
        keyAlias "MyReleaseKey"
        keyPassword "password"
    }
}
buildTypes {
    release {
        ...
        signingConfig signingConfigs.release
    }
}

}

生成签名的 APK:

要生成签名 APK,请从主菜单中选择 Build > Generate Signed APK。app/build/apk/app-release.apk 中的包现在已使用您的发布密钥进行签名。

参考:https ://developer.android.com/studio/build/build-variants.html#signing,http://blog.brainattica.com/how-to-work-with-flavours-on-android/

于 2016-08-04T12:02:36.353 回答
7

似乎您需要build.gradle. 之后,您将在“构建变体”视图中看到 4 个构建变体(您可以从窗口的左边缘访问它)。

关于其他源目录,您似乎需要手动创建它们 :src/flavor1/javasrc/flavor2/java. 您将看到在“Build Variants”视图中更改风味将更改当前活动的源目录(当它是活动源目录时,该目录为蓝色)

最后,“gradle 将为您的新风格创建新的 sourceSets”意味着 gradle 将创建对象android.sourceSets.flavor1android.sourceSets.flavor2并且您可以在 build.gradle 脚本中使用它们。但是这些对象是动态创建的,这就是为什么你看不到它们的原因build.gradle(我建议你阅读这个:http ://www.gradle.org/docs/current/userguide/tutorial_using_tasks.html特别是 6.6:它解释了创建动态任务。gradle脚本是一个groovy脚本,所以我建议你也熟悉groovy)

于 2013-05-24T15:19:56.393 回答
2

当我将项目迁移到 Gradle 时,我遇到了同样的问题。问题是构建没有找到正确的资源文件夹。我通过在 build.gradle 的 android 元素下添加它来修复它:

sourceSets {
        main {
            res.srcDirs = ['myProject/res']
        }
    }
于 2015-03-03T14:44:31.477 回答
0

在您的 gradle 中配置风味后,为了允许 react-native 查看项目文件夹根目录中的自定义 .env 文件,您必须添加到 android/app/build.gradle

在我的示例中,我使用相同的代码库为 android 设备创建了两个应用程序,一个用于 group1,一个用于 group2

//将此添加到您的第3行app/build.gradle

project.ext.envConfigFiles = [
projecta: ".env.development.android.projecta",
projectb: ".env.development.android.projectb",
]

//不要忘记添加

android {
compileSdkVersion rootProject.ext.compileSdkVersion
flavorDimensions “default” // add this line
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8

}

然后将此数组中的键与您的产品风格相匹配

  productFlavors {
    project1 {
        minSdkVersion rootProject.ext.minSdkVersion
        applicationId 'com.nativeapp.project1'
        targetSdkVersion rootProject.ext.targetSdkVersion
        resValue "string", "build_config_package", "com.nativeapp"
    }
    project2 {
        minSdkVersion rootProject.ext.minSdkVersion
        applicationId 'com.nativeapp.staff'
        targetSdkVersion rootProject.ext.targetSdkVersion
        resValue "string", "build_config_package", "com.nativeapp"
    }
}

还要确保 applicationId 和 resValue 以您的应用程序包名称开头

就我而言,它是“nativeapp”,但您可以在 MainActivity.java 文件中找到您的。

如果你深入 android/app/main/java/com/ 目录,你可以找到这个。

在此之后,您可以在需要时配置您的脚本,使其看起来像这样

"scripts": {
"android:project1": "ENVFILE=.env.development.candidate react-native run-android --variant=projectaDebug --appIdSuffix=projecta",
"android:staff": "ENVFILE=.env.development.staff.android react-native run-android --variant=projectbDebug --appIdSuffix=projectb",}

注意:添加脚本时,变体必须是风味名称,例如 'project2' 后跟 'Debug' = 'projectb' 因为这是您的默认 buildType

还要确保在 android/app/src/ 中为每种风味创建了相关文件夹。

就我而言

android/app/src/projecta/
android/app/src/projecta/

如果一切设置正确,当您使用您创建的脚本进行构建时,它应该创建正确的 res 文件夹和 android 清单文件。

如果要更改每个应用程序实例的名称,请更改res/values目录中的 strings.xml。

<resources>
<string name="app_name">Project1</string> //this will be the name of your app when its built in your emulator
</resources>
于 2020-10-16T04:03:37.807 回答
0

重要并阻止了我很长一段时间的事情是需要匹配包的风味名称,而不是 gradle 中风味定义中定义的包。例如:

src/flavor1/java/com/foo/A.java

将匹配

productFlavors {
  flavor1 {
    packageName 'com.android.studio.test.foobar'
  }
}

src/foobar/java/com/foo/A.java不会用于 flavor1 构建。

于 2015-11-09T03:37:22.207 回答
-1

在毕业典礼上:

对于构建类型,您只需要:

buildTypes {
   release{
    //proguard, signing etc.
   }
   debug {
    //development
   }
  }
}

然后对于口味,您可以添加您需要的口味

productFlavors {
    pro {
        applicationIdSuffix '.paid'
        buildConfigField 'boolean', 'PRO', 'true'
    }
    free {
        applicationIdSuffix '.free'
        buildConfigField 'boolean', 'PRO', 'false'
    }
}
于 2016-06-29T16:40:09.660 回答