建議使用 flutter_flavor 實(shí)現(xiàn)。
多環(huán)境構(gòu)建配置,在實(shí)際的開發(fā)工作中是很有必要的漂彤。但是 Flutter 沒有類似 .env 的配置,所以,只能是另辟蹊徑洞渔。本文是總結(jié)網(wǎng)上一堆經(jīng)驗(yàn)的一次實(shí)踐,上手相對(duì)簡(jiǎn)單缚态。
Production 模式 | Development 模式 |
一磁椒、基本操作步驟
- 安裝 Provider 依賴;
- 拆分原有的
main.dart
為 2 個(gè)部分玫芦,一部分為main()
浆熔,一部分為App()
MaterialApp 組件; - 建立對(duì)應(yīng)各個(gè)環(huán)境的入口文件桥帆,如:
main_prod.dart
医增、main_dev.dart
慎皱; - 建立環(huán)境配置類
class Env()
,給定默認(rèn)參數(shù)叶骨,并支持傳入新的配置參數(shù)茫多; - 建立狀態(tài)管理類
class StateEnv with ChangeNotifier
; - 在對(duì)應(yīng)的入口中使用 Provider 掛載應(yīng)用忽刽,并指定為對(duì)應(yīng)的環(huán)境模式天揖;
- 在頁(yè)面中使用
Provider.of<StateEnv>(context)
的方式獲取"環(huán)境變量"; - 啟動(dòng)調(diào)試跪帝;
二宝剖、詳細(xì)步驟
以下是詳細(xì)操作步驟:
2.1 安裝 Provider 依賴
Provider 是 flutter 開發(fā)常用的一個(gè)狀態(tài)管理庫(kù),參考官方的安裝教程安裝歉甚。
2.2 拆分原有的 main.dart
為了減少冗余代碼万细,我們將拆分原有的 main.dart
為 2 個(gè)部分:一部分為 main()
方法,一部分為 App()
MaterialApp 組件纸泄;
// 拆分后的 ./lib/main.dart
// import 略···
// 這里 import 我們拆分后的 app.dart
import 'app.dart';
void main() {
runApp(App());
}
// 新建 ./lib/app.dart赖钞,并粘貼原來實(shí)現(xiàn) MaterialApp 的代碼
// import 略···
class App extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
// 組件內(nèi)容略 ···
);
}
}
2.3 建立對(duì)應(yīng)各個(gè)環(huán)境的入口文件
為不同的構(gòu)建環(huán)境創(chuàng)建不同的入口文件,這里暫先創(chuàng)建 2 個(gè)入口聘裁,分別為 main_prod.dart
雪营、main_dev.dart
,直接復(fù)制原來 main.dart
的內(nèi)容到新建的兩個(gè)文件衡便。
// ./lib/main_dev.dart
// import 略···
// 這里 import 我們拆分后的 app.dart
import 'app.dart';
void main() {
runApp(App());
}
main_prod.dart
的文件內(nèi)容同上献起。
2.4 建立環(huán)境配置類 class Env()
我們需要建立一個(gè)通用配置文件,如:class Env
镣陕,并根據(jù)不同的環(huán)境實(shí)例化它谴餐,如:開發(fā)環(huán)境 new Env( mode: 'dev' )
,生產(chǎn)環(huán)境 new Env( mode: 'prod' )
等呆抑。同時(shí)岂嗓,為了統(tǒng)一管理,我還建立了一個(gè)環(huán)境枚舉 EnvMode
鹊碍。./lib/utils/env.dart
是我們的環(huán)境配置類厌殉,具體文件內(nèi)容如下:
// ./lib/utils/env.dart
// 環(huán)境變量配置
// 環(huán)境標(biāo)識(shí)
enum EnvMode {
PRODUCTION, // 生產(chǎn)環(huán)境
DEVELOPMENT, // 開發(fā)環(huán)境
TEST, // 測(cè)試環(huán)境
UAT, // 預(yù)發(fā)布環(huán)境
}
class Env {
// 環(huán)境標(biāo)識(shí)
final EnvMode mode;
// 接口參數(shù)
final String api;
// 應(yīng)用基礎(chǔ)配置
final String appName;
Env({
this.mode = EnvMode.PRODUCTION,
this.api = '',
this.appName = 'Flutter 學(xué)習(xí)',
}) : super();
}
-
mode
是當(dāng)前環(huán)境標(biāo)識(shí),可以使用類似Env.mode == EnvMode.DEVELOPMENT
的方式判斷當(dāng)前構(gòu)建模式侈咕; -
api
是當(dāng)前模式使用的數(shù)據(jù)請(qǐng)求接口公罕; -
appName
是一個(gè)演示變量;
實(shí)際開發(fā)中耀销,我們需要根據(jù)環(huán)境配置的內(nèi)容可遠(yuǎn)不止這么多楼眷。
2.5 建立狀態(tài)管理類
Provider 需要一個(gè)支持狀態(tài)響應(yīng)的類,建立一個(gè) StateEnv
類,內(nèi)容如下:
// ./lib/state/state_env.dart
// 環(huán)境狀態(tài)配置
// import 略 ···
class StateEnv with ChangeNotifier {
// 環(huán)境配置
final Env config;
StateEnv({this.config}) : super();
// 獲取環(huán)境模式
EnvMode get mode => this.config.mode;
// 獲取接口配置
String get api => this.config.api;
// 獲取應(yīng)用名稱
String get appName => this.config.appName;
}
2.6 在對(duì)應(yīng)的入口中使用 Provider 掛載應(yīng)用摩桶;
接下來修改我們的入口文件桥状,按照 Provider 的語(yǔ)法初始化即可帽揪。
// ./lib/main_dev.dart
void main() {
// 實(shí)例化應(yīng)用
runApp(
// 支持多個(gè)狀態(tài)管理
MultiProvider(
providers: [
// 環(huán)境配置
ChangeNotifierProvider(
create: (BuildContext context) => StateEnv(
config: Env(
mode: EnvMode.DEVELOPMENT, // 使用開發(fā)環(huán)境
api: 'http://127.0.0.1:3000', // 指定該環(huán)境對(duì)應(yīng)的數(shù)據(jù)請(qǐng)求接口
),
),
),
],
child: App(), // App 掛載
),
);
}
2.7 在頁(yè)面中讀取配置
其他頁(yè)面可以使用 Provider.of<StateEnv>(context, listen: false)
訪問狀態(tài)中的值硝清,如:
// 偽代碼
appBar: AppBar(
title: Text(Provider.of<StateEnv>(context, listen: false).appName),
)
// ./lib/app.dart
class App extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: Provider.of<StateEnv>(context, listen: false).appName,
debugShowCheckedModeBanner: Provider.of<StateEnv>(context).mode == EnvMode.DEVELOPMENT, // 是否顯示右上角 debug 徽標(biāo)
home: HomePage(),
);
}
}
2.8 啟動(dòng)調(diào)試
以 IntelliJ IDEA 為例,只需要為不同的入口建立運(yùn)行配置即可转晰。