Flutter Flavor配置指南:为不同的部署环境定制你的APP

5,974 阅读3分钟
2.png 2.png 2.png 2.png

概述

Flavor是一种在Flutter应用程序中创建和管理多个变体的方法。它允许开发人员使用同一代码库构建具有不同设置、功能和外观的多个应用程序。通过使用Flavor,开发人员可以轻松地创建适用于不同环境、不同客户或不同市场的应用程序变体。

每个Flavor代表一个独立的应用程序变体,其特征可能包括不同的应用程序标识符、名称、图标、主题、颜色方案、配置和环境变量等。使用Flavor,可以根据特定需求为每个变体定制应用程序的外观和行为。

Flavor的使用场景包括:

  1. 多个环境:在开发、测试和生产环境中使用不同的配置和API端点。

  2. 多个客户:为不同的客户或品牌创建定制的应用程序变体,包括不同的名称、图标和品牌元素。

  3. 多个市场:根据不同的市场需求创建应用程序的不同版本,例如根据语言、法律要求或文化习惯进行定制。

使用Flavor的好处包括:

  1. 代码复用:通过使用同一代码库构建多个变体,可以最大程度地复用代码,并减少重复工作。

  2. 维护简化:通过将不同变体的设置和配置集中管理,可以更轻松地进行维护和更新。

  3. 定制化:根据不同需求为每个变体提供定制的外观、功能和设置。

  4. 灵活性:可以根据需要轻松切换或构建不同的变体。

要使用Flutter Flavor,需要进行一些设置和配置,包括创建不同的构建配置文件、定义Flavor-specific的环境变量和资源,以及处理Flavor-specific的代码逻辑。

总而言之,Flavor可帮助开发人员管理和构建多个应用程序变体。它提供了灵活性和定制性,使开发人员能够轻松地适应不同的需求和场景。通过合理使用Flavor,可以提高开发效率并提供更好的用户体验。

环境

我的操作环境是:macOS, Android Studio Flamingo | 2022.2.1, Xcode Version 14.2

创建和配置 Flavor

配置Flavor涉及了三个平台:AndroidiOS,以及Flutter

接下来我们看看如何在原生平台分别配置FlavorFlutter中如何运行Flavor,以及Flutter中如何保持和原生端的Flavor同步。

Android

  1. 打开**android/app/build.gradle**

  2. android {}中创建flavorDimensions,例如代表了我们要请求的不同环境的API Host:env

  3. 接着添加productFlavors对象,在对象中添加你期望的针对不同环境的Flavor, 并给他们都指定纬度dimension "env"

  1. flavor中可以定义很多Gradle DSL配置选项,

例如manifestPlaceholdersAndroid清单文件(AndroidManifest.xml)中添加占位符,

resValue:用于在构建过程中动态生成资源值(Resource Values),

applicationIdSuffix:applicationId后缀,

buildConfigFieldBuildConfig类添加自定义字段,可以在代码中通过BuildConfig.API_HOST,来动态判断当前APP的Flavor

这部分详细内容可以参考官网:developer.android.com/build/build…

forDev {
    manifestPlaceholders = [app_icon: "@drawable/ic_launcher"]
    resValue "string", "app_name", "Will Dev"
    applicationIdSuffix ".dev"
    buildConfigField "int", "API_HOST", "${API_DEV}"
    dimension "env"
}

这一步Andorid端的Flavor配置就完成了。

iOS

  1. 添加Configurations: 打开Flutter项目中的iOS工程, 点击左侧目录中的Runner,再点击PROJECT下的Runner,添加对应FlavorConfiguations,每个Flavor都分别添加Debug-[FlavorName], Release-[FlavorName]俩套配置,后续用于创建Scheme时用于配置DebugArchive

  1. 创建Scheme

Xcode顶部的导航栏中,找到并点击Runner > New Scheme

输入我们定义的Flavor名称

点击Edit Scheme

选择左侧菜单中的Target:RunArchive,分别给他们勾选对应DebugRelease的构建配置(Build Configuration)

Flutter

Run with Flavor

  1. 现在原生端已经配置好了Flavor,在命令行输入flutter run --flavor forDev就可以运行对应Flavor的APP到机器上。

如果这时候你运行flutter run,不指定flavor的话,会出现报错

  1. 如果你用的IDE是Android Studio,可以通过配置Android Studio的Run Configurations来运行Flavor

点击头部导航栏中的Edit Configurations

通过Copy的方式拷贝一份运行配置,重命名,然后指定Build flavor,点击OK

这样我们就可以通过切换不同FlavorRun Configuration来运行期望的APP了

Flavor Sync in Flutter

所以到目前,原生端AndroidiOS已经分别配置了我们用来区分环境的Flavor,接下来还有一个问题就是Flutter端如何保持和原生的Flavor同步,也就是和原生端的环境同步,

例如原生端请求的接口是开发环境https://willdev.com/api/native ,Flutter当然也要保持接口是开发环境的https://willdev.com/api/flutter , 下面我列举几个可以实现的方案。

  1. 通过命令行增加额外的运行参数 --dart-define=env=dev

flutter run --flavor forDev --dart-define=env=dev

然后我们在代码中通过String.fromEnvironment('env');去获取对应的环境参数, 接着通过参数进一步获取需要的API host.

class GlobalConstants {

  static Flavor getFlavor() {
    var host = const String.fromEnvironment('env');
    switch (host) {
      case "dev":
        return Flavor.dev;
      case "test":
        return Flavor.test;
      case "gray":
        return Flavor.gray;
      default:
        return Flavor.prod;
    }
  }
}

enum Flavor {
  dev(apiHost: 'https://willdev.com'),
  test(apiHost: 'https://willtest.com'),
  gray(apiHost: 'https://willgray.com'),
  prod(apiHost: 'https://will.com');

  const Flavor({
    required this.apiHost,
  });

  final String apiHost;
}

IDE为Android Studio时,可以在Run Configuration中配置环境参数到Additional run args

  1. 创建不同的入口文件lib/main.dart来区分Flavor

创建lib/main_dev.dart, 在main_dev.dart中设置Flavordev

运行时输入--target lib/main_dev.dart来指定入口文件

flutter run --flavor forDev --target lib/main_dev.dart

除了命令行中指定,IDE为Android Studio时,也可以在dev的Run Configuration中配置入口文件为main_dev.dart

  1. 如果觉得上面两种方式要添加额外的构建命令,也可以根据原生端不同的Flavor构建的不同配置来区分,比如包名(Android中的ApplicationId, iOS中的BundleId)

首先原生端给不同的Flavor配置不同的包名

productFlavors {

    forDev {
        manifestPlaceholders = [app_icon: "@mipmap/ic_launcher"]
        resValue "string", "app_name", "Will Dev"
        applicationIdSuffix ".dev"
        buildConfigField "int", "API_HOST", "${API_DEV}"
        dimension "env"
    }
    forTest{
        manifestPlaceholders = [app_icon: "@mipmap/ic_launcher"]
        resValue "string", "app_name", "Will Test"
        applicationIdSuffix ".test"
        buildConfigField "int", "API_HOST", "${API_TEST}"
        dimension "env"
    }
    forGray {
        manifestPlaceholders = [app_icon: "@mipmap/ic_launcher"]
        resValue "string", "app_name", "Will Gray"
        applicationIdSuffix ".gray"
        buildConfigField "int", "API_HOST", "${API_GRAY}"
        dimension "env"
    }
    forProduct {
        manifestPlaceholders = [app_icon: "@mipmap/ic_launcher"]
        resValue "string", "app_name", "Will Pro"
        buildConfigField "int", "API_HOST", "${API_PRODUCT}"
        dimension "env"
    }
}

然后在Flutter中获取包名,根据不同的包名判断当前的环境Flavor

static Future<Flavor> getFlavorByPackageName() async {
  var packageInfo = await PackageInfo.fromPlatform();
  var packageName = packageInfo.packageName;
  if (packageName.endsWith(".dev")) {
    return Flavor.dev;
  } else if (packageName.endsWith(".test")) {
    return Flavor.test;
  } else if (packageName.endsWith(".gray")) {
    return Flavor.gray;
  } else {
    return Flavor.prod;
  }
}
  1. 通过MethodChannel和原生平台通信来获取Flavor信息
const methodChannel = MethodChannel('com.will.dev');

Future<String?> getFlavor() async {
  final String? result =
  await methodChannel.invokeMethod<String>("getFlavor");
  return result;
}

结尾

希望这篇博客能够帮助你了解如何在Android、iOS和Flutter中配置Flavor,并为不同的部署环境定制你的应用程序。无论是开发人员还是团队,使用Flavor都是一个重要的工具,可以简化开发流程并提供更好的灵活性和可定制性。开始使用Flavor,享受更好的部署和管理体验吧!