概述
Flavor是一种在Flutter应用程序中创建和管理多个变体的方法。它允许开发人员使用同一代码库构建具有不同设置、功能和外观的多个应用程序。通过使用Flavor,开发人员可以轻松地创建适用于不同环境、不同客户或不同市场的应用程序变体。
每个Flavor代表一个独立的应用程序变体,其特征可能包括不同的应用程序标识符、名称、图标、主题、颜色方案、配置和环境变量等。使用Flavor,可以根据特定需求为每个变体定制应用程序的外观和行为。
Flavor的使用场景包括:
-
多个环境:在开发、测试和生产环境中使用不同的配置和API端点。
-
多个客户:为不同的客户或品牌创建定制的应用程序变体,包括不同的名称、图标和品牌元素。
-
多个市场:根据不同的市场需求创建应用程序的不同版本,例如根据语言、法律要求或文化习惯进行定制。
使用Flavor的好处包括:
-
代码复用:通过使用同一代码库构建多个变体,可以最大程度地复用代码,并减少重复工作。
-
维护简化:通过将不同变体的设置和配置集中管理,可以更轻松地进行维护和更新。
-
定制化:根据不同需求为每个变体提供定制的外观、功能和设置。
-
灵活性:可以根据需要轻松切换或构建不同的变体。
要使用Flutter Flavor,需要进行一些设置和配置,包括创建不同的构建配置文件、定义Flavor-specific的环境变量和资源,以及处理Flavor-specific的代码逻辑。
总而言之,Flavor可帮助开发人员管理和构建多个应用程序变体。它提供了灵活性和定制性,使开发人员能够轻松地适应不同的需求和场景。通过合理使用Flavor,可以提高开发效率并提供更好的用户体验。
环境
我的操作环境是:macOS, Android Studio Flamingo | 2022.2.1, Xcode Version 14.2
创建和配置 Flavor
配置Flavor涉及了三个平台:Android,iOS,以及Flutter
接下来我们看看如何在原生平台分别配置Flavor,Flutter中如何运行Flavor,以及Flutter中如何保持和原生端的Flavor同步。
Android
-
打开**
android/app/build.gradle** -
在
android {}中创建flavorDimensions,例如代表了我们要请求的不同环境的API Host:env -
接着添加
productFlavors对象,在对象中添加你期望的针对不同环境的Flavor, 并给他们都指定纬度dimension "env"
flavor中可以定义很多Gradle DSL配置选项,
例如manifestPlaceholders:Android清单文件(AndroidManifest.xml)中添加占位符,
resValue:用于在构建过程中动态生成资源值(Resource Values),
applicationIdSuffix:applicationId后缀,
buildConfigField:BuildConfig类添加自定义字段,可以在代码中通过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
- 添加
Configurations: 打开Flutter项目中的iOS工程, 点击左侧目录中的Runner,再点击PROJECT下的Runner,添加对应Flavor的Configuations,每个Flavor都分别添加Debug-[FlavorName], Release-[FlavorName]俩套配置,后续用于创建Scheme时用于配置Debug和Archive。
- 创建
Scheme:
在Xcode顶部的导航栏中,找到并点击Runner > New Scheme
输入我们定义的Flavor名称
点击Edit Scheme
选择左侧菜单中的Target:Run和Archive,分别给他们勾选对应Debug和Release的构建配置(Build Configuration)
Flutter
Run with Flavor
- 现在原生端已经配置好了
Flavor,在命令行输入flutter run --flavor forDev就可以运行对应Flavor的APP到机器上。
如果这时候你运行flutter run,不指定flavor的话,会出现报错
- 如果你用的IDE是Android Studio,可以通过配置Android Studio的
Run Configurations来运行Flavor
点击头部导航栏中的Edit Configurations
通过Copy的方式拷贝一份运行配置,重命名,然后指定Build flavor,点击OK
这样我们就可以通过切换不同Flavor的Run Configuration来运行期望的APP了
Flavor Sync in Flutter
所以到目前,原生端Android,iOS已经分别配置了我们用来区分环境的Flavor,接下来还有一个问题就是Flutter端如何保持和原生的Flavor同步,也就是和原生端的环境同步,
例如原生端请求的接口是开发环境https://willdev.com/api/native ,Flutter当然也要保持接口是开发环境的https://willdev.com/api/flutter , 下面我列举几个可以实现的方案。
- 通过命令行增加额外的运行参数
--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中
- 创建不同的入口文件
lib/main.dart来区分Flavor
创建lib/main_dev.dart, 在main_dev.dart中设置Flavor为dev
运行时输入--target lib/main_dev.dart来指定入口文件
flutter run --flavor forDev --target lib/main_dev.dart
除了命令行中指定,IDE为Android Studio时,也可以在dev的Run Configuration中配置入口文件为main_dev.dart
- 如果觉得上面两种方式要添加额外的构建命令,也可以根据原生端不同的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;
}
}
- 通过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,享受更好的部署和管理体验吧!