본문 바로가기
프로그래밍/Flutter

[Flutter] Flavor 처리(New Version)

by YuminK 2022. 6. 20.

Flutter Flavor 처리(Old version)

https://kymworld.tistory.com/70

 

Flavor 처리를 적용하다

Flutter에서 Flavor 시스템을 구축하는 방법에 대해서 조사를 했고 실제로 Android에서는 Flavor, IOS에서는 scheme 정보를 추가하여 flutter의 --flavor 명령어를 사용하여 정상적으로 동작하는 것을 확인했습니다.

 

이러한 방식은 다음 블로그의 내용을 참고하여 작업을 했으며 BuildConfig에 대한 다트 코드 및 main문에 대한 분기 처리를 제외하고는 동일한 방식으로 개발이 되었습니다.

 

기존 Flavor 처리의 문제점

하지만, 이러한 시스템을 그대로 사용하기에는 관리적인 측면에서 심각한 문제가 있었습니다.

저희 프로젝트에서는 SI 사업을 하고 있어 회사마다 flavor정보를 분리하여 사용을 하고 있습니다. 

각 flavor는 웹 주소, 업데이트 여부, 커스텀 처리에 필요한 값 등이 포함이 되어 있는데요.

 

이러한 Flavor가 무려 22개로 분리가 되어 있었습니다.

 

Android에서는 Flavor를 native 사이드에서 하고 어떤 Flavor에 대한 정보인지 다트코드 내에서 받아서  BuildConfig 클래스를 만들고 이러한 처리를 분기하여 관리하면 됩니다. 

applicationId, Icon, versionCode, versionName 등 딱히 문제가 될 부분이 없었습니다. 

 

하지만 IOS에서는 심각한 문제가 발생을 했는데...  scheme 처리에서 너무 많은 분기가 발생했습니다. 

위 블로그 글에서 가져온 이미지를 보시면, scheme으로 관리하는 부분이 그렇게 많지는 않습니다.

dev, production 버전 둘로 나뉘고 있는데 이 정도면 크게 문제가 될 여지가 없어 보입니다. 

 

다만, 저희 프로젝트에서는... 22개나 되는 flavor에 맞게 Debug, Release 버전으로 분리를 하다보니....  너무 많은 스킴 정보가 필요했고 IOS개발에서는 이러한 스킴 정보를 토대로 사용할 라이브러리(?) 정보를 설정한다고 하여 이 방식으로 관리하는 것은 불가능하다고 판단했습니다.

차라리, Flutter 프로젝트를 여러 개를 만들어서 관리하지.
스킴이 이렇게 많으면 관리 못 한다.
- 민수 대리

 

새로운 Flavor 방식에 대한 테스트

flavor를 직접적으로 사용하지 않으면서 여러 flavor를 관리하는 방식을 조사했고 하나의 주옥같은 글을 찾았습니다. 

 

Flutter 1.17 — no more Flavors, no more iOS Schemas. Command argument that changes everything

Environment configuration with Compile-time variables in Flutter projects for Dart, iOS and Android...

itnext.io

 

직접적인 Flavor를 사용하지 않으면서 각 Native에서 applicationId(BundleId)나 App Name을 교체할 수 있는 방법을 제공합니다. 

 

--dart-define=CONFIG_NAME=CONFIG_VALUE 형태의 명령어를 작성하여 커맨드 라인에 넘겨주면 각 Native 사이드에서 이러한 Config값을 이용하는 방식입니다. (build apk 처리에도 적용할 수 있음)

 

프로젝트가 시작할 때 Native 사이드에서 로고 이미지를 출력하다가 MethodChannel을 이용하여 화면을 끄고 Dart내 로고화면을 출력하는 화면으로 연결이 되는 까닭에 Splash이미지를 flavor에 따라 분기할 필요가 있었고 

 

원본 예제에서는 Icon에 대한 처리는 제공되어 있지 않았습니다.

 

추가적으로 필요했던 것:

Icon, Splash 이미지, dart 코드 내에서도 splash이미지가 필요

그 외에도 각 Native에서 사용할 Config값 (ApplicationId, scheme, versionCode, versionName ...)

 

따라서 Icon에 대한 처리 방식 및 Splash이미지에 대한 해결 방안을 고민을 해본 결과 2가지 방식이 존재했습니다.

1. 미리 이미지에 대한 정보를 넣어놓고 코드내에서 분기 처리를 하는 방식 or UI상에서 분기 처리

2. 기존에 있던 리소스를 완전히 덮어씌우는 방식

 

1번을 골랐을 때의 문제점은 다음과 같았습니다.

현재 안드로이드의 리소스 분기 처리는 flavor를 토대로 합니다. 즉, flavor 시스템을 사용하지 않는 경우에는 default 경로에 있는 아이콘 이미지를 바꿀 수 밖에 없다.

 

또한 IOS Xcode 내에서 ios/Runner/Assets.xcassets 폴더를 보시면 기본 아이콘에 대한 정보가 있는데 이 키워드인 AppIcon이라는 정보를 프로젝트에서 검색해보면 proj 설정에서 사용하는 것을 알 수 있습니다. (이 값을 바꾸고 다른 아이콘을 적용할 수 있었습니다.)

 

결론적으로 아이콘 정보를 미리 추가해놓고 이 AppIcon이라는 키워드를 proj설정에서 바꿔줘야 적용이 된다는 의미입니다. 

 

IOS에서는 다른 아이콘 정보를 분기처리 하는 방식이 존재하고 Android에서는 따로 존재하지 않으니 통일성이 없습니다.

따라서 가장 간단하고 크게 고려할 필요가 없는 2번 방식을 선택했습니다. 

 

실제로 이러한 덮어 씌우는 방식은 과거 안드로이드 프로젝트에서 사용하던 방식인데요.

과거 프로젝트를 열어볼 일이 생겨서 그쪽에서 작업을 했던 적이 있었는데 지금처럼 안드로이드 프로젝트에서 기본적으로 제공되는 flavor에 대한 분기 처리 방식이 존재하지 않았습니다. (리소스별 flavor 이름을 통한 분기)

 

그러면 어떻게 관리를 했느냐? 

각 flavor에 대한 배치파일이 존재해서 아이콘이나 로고 이미지 같은 것을 바꿔주는 스크립트 파일이 있었습니다. 각 flavor에 대한 처리가 필요할 때 배치 파일을 실행해주고 작업하고 다시 default 배치 파일을 돌려놓고 커밋하는 방식입니다.

 

저는 이러한 방식에서 힌트를 얻어서 배치 파일을 만들기로 결정합니다. 

그런데.. 막상 생각을 해보니까 또 다른 이슈(?)가 있었습니다.

 

flutter는 Mac에서도 개발이 되어야 한다.

저는 Window에서 Android Studio를 주로 사용하는데 Flutter 프로젝트를 진행하다보니 어쩔 수 없이 Mac에서도 개발을 하게 됩니다. 이 말은.... 맥에서도 배치 파일이 필요하다.

난감하네...

어쩔 수 없이 윈도우 배치 파일과 맥용 Shell script를 동시에 작업할 수 밖에 없었습니다.

 

처음에는 다음 그림과 같이 shell script와 bat파일을 동시에 작업을 했습니다만, 막상 작업을 하다보니 Config에 있는 텍스트를 읽어서 각 script에서 가져와서 쓰고 싶은데 배치 split처리를 하는 것이 너무 복잡하여... 

 

결국에는 파이썬으로 개발했습니다. (파이썬으로 개발을 하니까 효과적으로 시간을 단축시킬 수 있었습니다. ㅎㅎ;) 

프로젝트의 배치 폴더는 다음과 같습니다.

flavors에는 각 flavor마다 필요한 리소스, Config정보를 담아놓는 파일입니다.

flavor.py는 실행시킬 python script로서 flavor정보를 넘겨주면 해당 폴더에서 정보를 읽어서 아이콘, Config 등을 설정해주는 방식으로 되어 있습니다.

 

 

python코드에는 설정한 config값에 대한 default 값을 선언하는 부분이 있고 

 

script의 실행과 동시에 넘어온 flavor정보와 debug모드 여부를 판단합니다. 또한 해당 정보를 토대로 config.txt 정보를 읽어서 dart define으로 넘길 정보를 업데이트 합니다. 

이미지 정보를 토대로 Icon, Splash로 사용할 이미지를 복사합니다. 

 

마지막에는 위에서 정의한 config정보를 토대로하여 flutter run을 처리합니다. 

(flutter run까지 작업을 해놓은 이유는... Android Studio Configurations쪽 빌드 전 이벤트 등록이 각 Configuration마다 설정이 공유가 되고 있어서 사용할 수 없다고 판단했습니다.)

cmd를 통해 flavor.py코드를 실행시키면, 넣어준 flavor를 토대로 config를 설정하고... 이미지를 설정하여 flutter run까지 실행되는 방식입니다. 이후에 dart 코드에서는 flavor 정보를 받아서 BuildConfig 처리를 위한 값을 정의합니다. 

 

Mac OS에서 스크립트를 실행 시키면서 문제가 발생하는 부분을 수정을 했는데, 절대 경로 문자 '\'에 대한 인식을 못해서 상대 경로 문자 '/'로 모두 수정을 했으며, text 인코딩 방식에 문제가 있어서 명시적으로 선언하여 처리했습니다. (코드에 모두 수정이 되어 있음)

 

위에서 처리한 정보 모두 각 Native의 속성으로 처리가 되어 있는 상태입니다. 

(Android의 build.gradle에 대한 정보, IOS의 info.plist 그리고 dart에서의 BuildConfig 클래스 정의...)

Medium글에 나온 방식 그대로 적용을 했으며 단순히 필요한 Config 정보를 추가하고 더 많은 flavor를 관리하기 위한 script작성, 클래스 구조 설계 작업을 진행했습니다.

 

Android, IOS 어플로 개발을 하다가 Flutter로 이관하는 작업을 하시는 분들께 많은 도움이 되길 바라며, Config 설정이 되어 있는 프로젝트를 샘플로 공유합니다. 

 

https://github.com/Yumin2019/dart-flavor-sample

댓글