정----말 오랜만에 Flutter로 사이드 프로젝트를 시작했습니다. 한동안 손 놓고 있던 사이에 Flutter 버전은 2.x대에서 3.x대로 훌쩍 업데이트되었고, 그러면서 바뀐 점들도 꽤 있더라고요.
프로젝트를 진행하며 알게 된 몇 가지를 정리해 보려고 합니다. 그 첫 번째 타자가 바로 Flavor! 그럼 시작해 볼까요?
Flavor란?
프로젝트를 진행하거나 출시하다 보면 하나의 소스 코드로 여러 환경에 맞춰 앱을 빌드해야 할 때가 많습니다. 개발, 스테이징, 운영 등등.. 각 환경은 서로 다른 API 주소나 앱 이름, 아이콘을 가져와야 하죠. 만약 이런 설정을 수동으로 변경한다면 개발 서버를 바라봐야 할 앱이 운영 서버를 본다거나 하는 크리티컬한 실수를 피하기 쉽지 않습니다.
Flutter의 Flavor는 이런 문제를 해결하기 위한 공식적인 기능입니다. 다음에 또 허둥댈 저를 위해, 처음부터 끝까지 정리해 보겠습니다!
1단계: 환경별 main 파일 및 설정 파일 생성
가장 먼저 Dart 코드 단에서 각 환경을 구분할 수 있는 파일을 만들어 줍니다.
1. 환경별 진입점, main_ 파일 만들기
lib 폴더 안에 각 환경의 시작점이 될 파일을 생성해 줍니다. 이 파일의 역할은 앱이 어떤 Flavor로 실행되어야 하는지 알려주는 것입니다.
lib/main_dev.dart
import 'package:flutter/material.dart';
import 'flavors.dart';
import 'main.dart'; // 모든 환경이 공통으로 사용할 앱 시작 로직
void main() {
F.appFlavor = Flavor.dev; // 앱 시작 전에 'dev' Flavor라고 알려주기
startApp();
}
(똑같이 main_production.dart 파일도 만들고 F.appFlavor = Flavor.production;으로 설정해 줍니다.)
2. 설정값 관리자, flavors.dart 만들기
환경별로 달라질 앱 제목, API 주소 등의 값을 이곳에서 중앙 관리합니다.
lib/flavors.dart
enum Flavor { dev, production }
class F {
static late final Flavor appFlavor;
static String get title {
switch (appFlavor) {
case Flavor.dev:
return '내 앱 (개발)';
case Flavor.production:
return '내 앱';
}
}
// ... API 주소 등 다른 설정도 여기에 추가!
}
2단계: 민감 정보는 .env로!
API 키처럼 Git에 올리면 절대 안 되는 민감 정보는 .env 파일로 따로 빼서 관리하는 게 안전하겠죠?
1. 패키지 설치 및 파일 생성
flutter pub add flutter_dotenv
프로젝트 최상단에 .env 파일을 만들고 키를 넣어줍니다.
.env
HASURA_ADMIN_SECRET="your_secret_api_key_here"
2. .gitignore에 .env 파일 추가하기 가장 중요한 단계! .gitignore 파일 맨 아래에 .env*를 추가해서 Git이 이 파일을 추적하지 못하게 막아줍니다.
3. 공통 main.dart에서 .env 파일 로드하기
모든 Flavor가 공통으로 사용할 startApp() 함수에서 앱이 실행되기 전에 .env 파일을 로드하도록 코드를 추가합니다.
lib/main.dar
import 'package:flutter/material.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'app.dart'; // MaterialApp 위젯이 있는 파일
Future<void> startApp() async {
// .env 파일을 찾아 변수를 메모리에 로드합니다.
await dotenv.load(fileName: ".env");
// 이제 앱을 실행합니다.
runApp(const MyApp());
}
3단계: 네이티브(Android/iOS) 설정하기
Dart 코드 설정이 끝났다고 방심하면 안 됩니다.
Flutter 앱은 결국 네이티브 앱으로 빌드되기에, Android와 iOS에게도 우리가 만든 Flavor를 알려줘야 합니다.
안그럼 그냥 실행 단축키로 실행했을때 오류가 납니다 ㅠ
실제로 봤던 오류: LateError (LateInitializationError: Field 'appFlavor' has not been initialized.)
1. Android 설정 (build.gradle.kts)
android/app/build.gradle.kts 파일을 열고 아래 내용을 추가해 주세요.
android {
...
flavorDimensions += "app"
productFlors {
create("dev") {
dimension = "app"
// 앱 패키지명에 .dev를 붙여 운영 버전과 같이 설치할 수 있게 함
applicationIdSuffix = ".dev"
// 안드로이드 앱 이름을 변경
resValue("string", "app_name", "내 앱 (개발)")
}
create("production") {
dimension = "app"
resValue("string", "app_name", "내 앱")
}
}
}
2. iOS 설정 (Xcode Schemes)
iOS는 Xcode에서 Scheme을 이용해 Flavor를 설정합니다. 조금 복잡하지만 차근차근 따라 해보세요.
- Xcode 실행: 터미널에서 open ios/Runner.xcworkspace 명령어로 Xcode를 엽니다.
- Configuration 복제: Project 'Runner' > Info > Configurations에서 Debug와 Release를 각각 복제하여 Debug-dev, Release-dev를 만듭니다.
- Scheme 복제: 상단 메뉴 Product > Scheme > Manage Schemes...에서 Runner를 복제하여 Runner-dev를 만듭니다.
- Scheme과 Configuration 연결: Runner-dev의 Edit Scheme... > Build 탭에서 각 단계의 Configuration을 위에서 만든 Debug-dev, Release-dev로 바꿔줍니다.
- 앱 이름, 번들 ID 설정:
- Build Settings에서 + 버튼을 눌러 User-Defined Setting을 추가하고 APP_NAME과 BUNDLE_ID_SUFFIX 변수를 만듭니다.
- Debug-dev 환경에 맞춰 APP_NAME은 내 앱 (개발), BUNDLE_ID_SUFFIX는 .dev로 값을 설정합니다.
- Info.plist 파일을 열어 Bundle display name의 값을 $(APP_NAME)으로, Bundle identifier의 값을 $(PRODUCT_BUNDLE_IDENTIFIER)$(BUNDLE_ID_SUFFIX)로 수정합니다.
## 4단계: VS Code에서 편하게 실행하기 (launch.json)
마지막으로, 매번 긴 명령어를 치는 대신 F5 키로 편하게 디버깅하기 위해 VS Code를 설정해 줍니다.
.vscode/launch.json
{
"version": "0.2.0",
"configurations": [
{
"name": "🚀 DEV",
"request": "launch",
"type": "dart",
"program": "lib/main_dev.dart",
"args": ["--flavor", "dev"]
},
{
"name": "✅ PRODUCTION",
"request": "launch",
"type": "dart",
"program": "lib/main_production.dart",
"args": ["--flavor", "production"]
}
]
}
VS Code의 'Run and Debug' 탭에서 원하는 Flavor를 선택하고 실행하면 끝!
이제 하나의 코드로 여러 환경을 테스트 해볼 수 있는 프로젝트가 되었어요! 역시 버전이 업데이트 되면서 이런저런 기능이 추가되네요. 늘 공부해야되는게 힘들기도 하지만 결론적으로 공식적으로 개발자를 편하게 해주려고 하는거니 열심히 따라가야겠어요 앞으로의 나 화이팅
'FRAMEWORK > FLUTTER' 카테고리의 다른 글
| [Flutter] router reset (0) | 2022.04.19 |
|---|---|
| [Flutter] 누구나 할수있는 플루터에서 url로 파일 다운로드하기 (4) | 2022.04.18 |
| [Flutter] IconButton padding 없애는 방법 (0) | 2022.04.18 |
| Flutter 문자열에서 html tag모두 제거하기 (0) | 2022.04.14 |
| flutter textfield only number (0) | 2022.04.13 |