728x90

플러터 환경을 새로 준비하다보면 이전에 맛보지(?) 못했던 다양한 에러를 만나곤 합니다. 특히 Java의 버전이 달라진 경우에 이같은 문제가 더 자주 발생합니다. 새로운 애플실리콘 M1 Mac 환경에서 플러터 개발 환경을 새로 셋업하다 만난 Java 에러에 대하여 해결 방법을 정리해 봅니다.


플러터 환경설치시 활용하게 되는 닥터(doctor)는 부족한 환경 설정을 쉽게 진단해주고 어떤 대응을 해야 하는지 알려주는 도구입니다. 문제는 가끔 여기서 알려준 대응 방법을 실행하는 것 자체가 문제가 되는 경우입니다. 오늘 겪은 이슈는 새롭게 플러터 환경 설정시 필요한 안드로이드 라이센스에 대한 동의 과정에서 발생했습니다. 

플러터 닥터의 메세지 살펴보기

안드로이드 스튜디오, 플러터 SDK를 설치한 후 flutter doctor를 수행하여 추가로 진행해야 하는 작업을 살펴보았습니다. 안드로이드 라이센스에 대한 동의가 필요하다고 하여 이 부분에 대한 안내에 따라 명령을 수행했습니다. 이전에 다른 노트북에서도 큰 문제 없이 안내된 명령을 복붙하는 것으로 충분했기에 안내된 명령을 실행했습니다. 그런데...

flutter doctor 의 안내 메세지

%  flutter doctor --android-licenses
Exception in thread "main" java.lang.NoClassDefFoundError: javax/xml/bind/annotation/XmlSchema
	at com.android.repository.api.SchemaModule$SchemaModuleVersion.<init>(SchemaModule.java:156)
	at com.android.repository.api.SchemaModule.<init>(SchemaModule.java:75)
	at com.android.sdklib.repository.AndroidSdkHandler.<clinit>(AndroidSdkHandler.java:81)
	at com.android.sdklib.tool.sdkmanager.SdkManagerCli.main(SdkManagerCli.java:73)
	at com.android.sdklib.tool.sdkmanager.SdkManagerCli.main(SdkManagerCli.java:48)
Caused by: java.lang.ClassNotFoundException: javax.xml.bind.annotation.XmlSchema
	at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:581)
	at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
	at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522)
	... 5 more

 

이전에 만나보지 못했던 새로운 경험... 그것도 굉장히 기본적인 문제가 있는 것처럼 보이는 에러가 똬악 나타났습니다. Java 익셉션이라니... 더 이상의 안내가 없었기 때문에 구글링을 열심히 하여 몇 가지 단서를 찾았고 그 중 하나는 "안드로이드 SDK 커맨드라인 도구"의 설치 부재시 발생할 수 있다는 것이었습니다. 

안드로이드 SDK의 커맨드라인 툴킷 설치하기

안드로이드 SDK의 커맨드라인 툴킷을 설치하는 가장 간단한 방법은 안드로이드 스튜디오의 셋팅 메뉴를 이용하는 방법입니다. 안드로이드 스튜디오를 실행하고 왼쪽 <Customize> 메뉴를 선택하면 아랫쪽에 <All settings...> 메뉴가 보입니다. 메뉴를 선택합니다.

설정 화면이 열리면 <Appearance & Behavior> - <System Settings> - <Android SDK>메뉴를 선택하고 우측의 탭에서 <SDK Tools>를 선택합니다. 예상대로 커맨드라인 툴킷이 설치되어 있지 않은 것이 보입니다. 체크후 설치를 진행해 봅니다. 

 

안드로이드 라이센스 동의 작업 다시 해보기

100MB 정도 되는 패키지를 다운로드하고 설치하는 과정은 금세 끝납니다. 설치가 완료되었다면 다시 터미널 화면으로 이동하여 플러터 닥터를 이용해 안드로이드 라이센스 동의를 해보니 문제 없이 수행이 됩니다. 참고로 간혹 특정한 동의가 자동으로 되지 않는 경우가 있는데 라이센스 동의 명령을 이용시 상세 내용을 조회하면서 동의를 해주면 모든 라이센스에 동의가 진행됩니다. 

%  flutter doctor --android-licenses
All SDK package licenses accepted.======] 100% Computing updates...

이제 다시 한 번 플러터 닥터를 수행하여 필요한 절차를 살펴보겠습니다. 에러가 표시되던 Android toolchain 항목에 그린라이트가 들어온 것이 확인되네요!

 


 

플러터(Flutter), 안드로이드 스튜디오로 개발환경 만들기

플러터 개발환경을 안드로이드 스튜디오에 구성해 보도록 하겠습니다. 기억하실지 모르겠지만 비주얼 스튜디오 코드 Visual Studio Code 에 환경을 구성하는 법을 잠깐 소개드렸었죠? 어쩌다보니 그

ondemand.tistory.com

 

플러터(Flutter), 안드로이드 스튜디오 Unable to locate ADB 에러와 시뮬레이터가 안보이는 현상 해결하

새로운 개발환경은 늘 어색합니다. 플러터(Flutter)를 안드로이드 스튜디오 환경에서 다시 공부하기 시작하면서 매일매일 새로운 느낌으로 시행착오를 겪고 있습니다. Mac 운영체제의 Big Sir의 업

ondemand.tistory.com

 

728x90
728x90

새로운 개발환경은 늘 어색합니다. 플러터(Flutter)를 안드로이드 스튜디오 환경에서 다시 공부하기 시작하면서 매일매일 새로운 느낌으로 시행착오를 겪고 있습니다. Mac 운영체제의 Big Sir의 업데이트 때문에 설치후 재기동을 하고 난 뒤 안드로이드 스튜디오에서 겪은 문제에 대한 이야기입니다.

운영체제 업데이트전까지 아무런 문제 없이 안드로이드 스튜디오에서 플러터로 코드를 만들고 안드로이드 시뮬레이터를 이용해 디버깅을 하고 있었습니다. 그런데 업데이트 설치후에 갑자기 안드로이드 스튜디오가 시뮬레이터에서 앱을 실행하지 못하고 에러를 토하는 현상을 맞딱들였습니다. 

집나간 시뮬레이터들... 아빠가 잘못했다, 어서 돌라오렴!

안드로이드 스튜디오를 여러번 재기동해도 시뮬레이터의 목록이 보이지 않았습니다. 안드로이드 스튜디오에서 코드를 실행하면 시뮬레이터가 기동은 되었지만 (왜지...) 디버거가 연결이 안되고 앱이 배포되지 않았습니다. 안드로이드 시뮬레이터를 관리하는 AVD Manager 를 이용해 만들어 둔 이미지를 개별적으로 실행하면 <Unable to locate adb>라는 에러 메세지가 출력되었습니다. 

 

AVD Manager 의 에러 : Unable to locate adb

 

구글에서 검색을 해보니 이 현상이 일어나는 원인중 대표적인 것이 안드로이드 디버거인 adb 의 경로가 제대로 설정되지 않아 실행되지 않는 경우라는 이야기가 많았습니다. 안타깝게도 제 경우에는 터미널에서 adb 가 아주아주 원활히 잘 실행되고 있었기 때문에 환경변수에서 path 설정이 잘못된 것으로는 생각되지 않았습니다. 

SDK 설정을 보려면 File > Project Structure 메뉴를 사용합니다.

 

그러던 중 <Project Structure> 에서 SDK 설정이 제대로 되지 않았거나 삭제된 경우 (아마도 업데이트의 여파?) 비슷한 문제를 겪었다는 글을 발견할 수 있었습니다. 밑져야 본전, 정말로 SDK 설정이 <갑자기> 사라진 것인지 확인해 보기로 했습니다. 설마 안드로이스 스튜디오가 그런 일을 저질렀겠냐는 생각을 하던 바로 그 순간...

헐... No SDK 라니...

 

저는 제 눈을 의심해야 했습니다. Project 의 SDK가 <No SDK>를 가리키고 있었습니다. 누가 이런 짓을 한 걸까요? 그건 아무도 모릅니다. 며느리도 모릅니다. 다만, SDK 설정이 사라졌다는 사실이 중요한 것이고 이것을 바로 잡아 문제가 해소되는지 확인해야 했습니다. 

 

드롭다운 리스트를 열고 로컬 환경에 설치된 안드로이드 SDK중 28버전의 API 를 다시 선택했습니다. 그리고 창을 닫고 기도를 했습니다. 집나간 시뮬레이터가 어서 돌아오게 해주세요. 모든걸 용서하겠다고...

집에 돌아온 시뮬레이터

 

오오오오.. 아무 것도 없던 디바이스 선택 드롭다운 리스트에 만들어둔 시뮬레이터가 똬악하고 보였습니다. 프로젝트를 실행해보니 디버거 연결도 잘 되고 앱도 정상적으로 배포되는 것을 확인할 수 있었습니다. 왜 이런일이 일어난 것인지는 알아낼 수 없었지만 유사한 현상이 발생헀을 때, 이제 당황하지 않고 문제를 처리할 수 있을 것 같은 자신감이 샘솟았습니다. :-)

728x90
728x90

안드로이드 스튜디오의 셋업이 끝났으니 이제 플러터 프로젝트를 만들고 자동 생성되는 기본 구조를 살펴보겠습니다. 프로젝트가 생성되면 조금 복잡해 보이는 디렉토리 구조와 프로젝트에 필요한 기본 파일들이 생성됩니다. 

 

안드로이드와 iOS를 모두 지원하는 앱을 만들어야 하기 때문에 android, ios 이름을 갖고 있는 폴더가 먼저 눈에 띕니다. 우리가 직접 코드를 만들어 지지고 볶는 곳은 main.dart 파일이 포함된 lib 디렉토리라고 합니다. 그럼 main.dart 를 한 번 열어보겠습니다. 보물상자를 여는 기분으로다...

 

복잡해 보이는 main.dart 파일이지만 코드 블럭을 접어서 보면 크게 위의 다섯가지 부분 정도로 나뉩니다. 모듈이나 라이브러리를 불러오기 위해 사용하는 import 가 가장 먼저 눈에 띕니다. 그리고 자바나 C, C# 등에서 익숙하게 봤을 main() 함수가 어플리케이션의 진입점이 된다는 것을 눈치챌 수 있었습니다.

main() 에 자동 생성된 코드가 거의 없을 거라는 것을 예상하셨겠지만, 정말로 들어 있는 내용이 없습니다 ^^;; main() 함수는 7번 행부터 정의하고 있는 실제 플러터 어플리케이션의 시작이라 할 수 있는 <위젯>을 호출하는 역할만 수행하고 있습니다. 샘플 프로젝트에는 MyApp 이라는 클래스가 StatelessWidget 을 상속받아 생성되고 있습니다. 

 

<위젯>은 플러터에서 UI의 컴포넌트나 화면 단위를 만드는 단위입니다. 오래된 사람인 저는 컨트롤이라는 용어가 익숙합니다만 이제 <위젯>이라는 단어에 스스로를 맞춰보도록 하겠습니다 ^^;; 

 

위젯은 크게 상태 값이 보존되는 위젯과 상태 값이 보존되지 않는 위젯으로 나뉜다고 합니다. MyApp 과 MyHomePage 클래스가 상속 받고 있는 StatelessWidget 과 StatefulWidget 이 정의하고 있는 위젯 클래스의 목적을 나타내주고 있습니다. 자세한건 저도 아직 잘 몰라서 천천히 좋은 감정으로 알아가 보도록 하겠습니다. ㅋ

 

샘플 프로젝트를 생성했을 때 이 프로젝트는 완전히 빈 깡통 프로젝트는 아닙니다. 간단하게 StatelessWidget과 StatefulWidget의 차이를 알아볼 수 있는 카운트 앱이 샘플 프로젝트에 담겨 있습니다. MyApp 과 MyHomePage 클래스에 들어 있는 코드를 자세히 볼까요?

 

최초 샘플 프로젝트 생성시에는 엄청난 양의 주석이 같이 있습니다. 주석을 모두 제거하면 두 클래스의 코드는 몇 줄 되지 않습니다. MyApp 클래스는 어플리케이션의 윤곽을 나타내기 위한 위젯을 리턴하는 코드가 전부입니다. 코드 내에서 다시 MyHomePage 클래스를 사용하여 `Flutter Demo Home Page`라는 타이틀을 가진 StatefulWidget 을 만들고 있습니다.

MyHomePage 위젯도 코드가 무척 단순합니다. 클래스의 인스턴스가 만들어 질 때 매개변수로 타이틀을 받아서 멤버 변수에 저장하고 _MyHomePageState 클래스 형식으로 createState() 함수를 호출해 위젯의 상태를 저장할 객체를 생성하게 됩니다. 

 

마지막으로 _MyHomePageState 클래스입니다. 주석이 많이 생기기 때문에 주석을 삭제하면 내용을 한 눈에 알아보기 더 쉽습니다. 물론 주석에 자세한 설명들이 있기 때문에 공부하는 동안에는 한 번 읽어보는 것도 도움이 될 것 같긴합니다. 

멤버 변수로 _counter 를 갖고 있으며 앱이 수행되는 동안 카운터 된 숫자를 기억하기 위해 사용하는 변수입니다. 앱을 실행하면 더하기 floatingActionButton 이 하나 화면에 나오고, 버튼을 누를때마다 _counter 의 값을 1씩 증가시킵니다. 내장 함수인 _incrementCounter() 에 증감연산자를 사용해 _conuter++ 를 실행하는 코드가 보입니다. 

이처럼 플러터는 값의 저장, 보존이 필요한 경우 StatefulWidget 과 State 를 사용하고 그렇지 않은 경우 StatelessWidget 을 사용한다는 점을 기억하고 익숙해져야 할 것 같네요!


 

 

플러터(Flutter), 안드로이드 스튜디오로 개발환경 만들기

플러터 개발환경을 안드로이드 스튜디오에 구성해 보도록 하겠습니다. 기억하실지 모르겠지만 비주얼 스튜디오 코드 Visual Studio Code 에 환경을 구성하는 법을 잠깐 소개드렸었죠? 어쩌다보니 그

ondemand.tistory.com

 

플러터(Flutter), 샘플앱 실행으로 개발환경 문제점을 파악해보자

지난 포스팅에서 안드로이드 스튜디오를 업데이트하고 플러터 플러그인을 설치해보았습니다. 추가된 플러그인을 통해 샘플 프로젝트를 만들고 실행을 해보았지만 예상대로 문제가 발생했고,

ondemand.tistory.com

 

728x90
728x90

지난 포스팅에서 안드로이드 스튜디오를 업데이트하고 플러터 플러그인을 설치해보았습니다. 추가된 플러그인을 통해 샘플 프로젝트를 만들고 실행을 해보았지만 예상대로 문제가 발생했고, 안드로이드 가상 장치에서 시험을 해볼 수 없었습니다. 무슨 문제가 있었던 것일까요?

 

안드로이드 스튜디오에서 플러터 프로젝트를 생성하고 기본 샘플 앱을 가상 안드로이드 기기로 실행했을때 발생한 에러 화면입니다. 뭔가 SDK와 관련된 라이센스가 제대로 적용이 안된 것 같은 에러메세지입니다. 바로 터미널을 실행하여 플러터 닥터 flutter docter 명령을 통해 문제점을 확인해 보았습니다. 명령은 터미널에서 flutter docter 를 입력하여 수행합니다. 

 

초록색 체크표시가 된 것들은 문제가 없는 부분들입니다. 느낌표로 출력된 내용을 보니 비주얼 스튜디오 코드를 위한 플러터 환경 구성 이후 변경된 것들이 좀 있어 보입니다. 가장먼저 Android toolchain 항목에 대한 명령을 통해 첫번째 문제를 해결해 보겠습니다. 

flutter doctor --android-licenses

 

위의 플러터 닥터 명령은 동의해야 하는 약관, 라이센스에 대한 확인을 해주는 명령입니다. 실행후 나오는 내용을 살펴보고 (영어입니다 -_-;) 동의한다는 의미로 y 키를 몇 번 눌러주면 됩니다. 다시 닥터를 실행해서 처리가 잘 되었는지 보겠습니다. 

오호라. 첫번째 Android toolchain 항목도 이제 초록색 체크로 바뀌었습니다. 플러터로 개발된 코드를 iOS 에서 실행할 수 있도록 하기 위해서는 Xcode 환경도 준비가 되어 있어야 합니다. 지난번에도 CocoaPods 설치하느라 고생했는데... 그래도 다시 한 번 해보았습니다. 

#  sudo gem install cocoapods
Password:
Fetching i18n-1.8.9.gem
Fetching tzinfo-1.2.9.gem
Fetching activesupport-5.2.4.5.gem
Fetching nap-1.1.0.gem
Fetching fuzzy_match-2.0.4.gem
Fetching concurrent-ruby-1.1.8.gem
...
...
Parsing documentation for gh_inspector-1.1.3
Installing ri documentation for gh_inspector-1.1.3
Parsing documentation for ruby-macho-1.4.0
Installing ri documentation for ruby-macho-1.4.0
Parsing documentation for cocoapods-1.10.1
Installing ri documentation for cocoapods-1.10.1
Done installing documentation for concurrent-ruby, i18n, thread_safe, tzinfo, activesupport, nap, fuzzy_match, httpclient, algoliasearch, ffi, ethon, typhoeus, netrc, public_suffix, addressable, cocoapods-core, claide, cocoapods-deintegrate, cocoapods-downloader, cocoapods-plugins, cocoapods-search, cocoapods-trunk, cocoapods-try, molinillo, atomos, CFPropertyList, colored2, nanaimo, xcodeproj, escape, fourflusher, gh_inspector, ruby-macho, cocoapods after 25 seconds
34 gems installed

 

자, 코코아포드 관련한 패키지들의 추가도 끝났으니 다시 flutter docter 를 실행해 봐야겠죠?

 

에러 메세지가 확~ 사라졌습니다. 이제 마지막으로 남은 것은 안드로이드 스튜디오에서 플러그인을 설치하는 일입니다. 에..? 플러그인? 분명히 설치했다고 생각했는데... 무슨 문제일까요? 일단 에러 메세지를 무시하고 코드를 안드로이드 에뮬레이터에서 실행해 보겠습니다. 희안하게도 문제 없이 실행이 됩니다. 

 

어렵지 않죠? 네, 저는 어렵습니다 ㅎㅎ. 일단 동작이 잘 되는 것을 확인했으니, 본격적으로 뭔가를 만들어 봐야겠습니다!

728x90

+ Recent posts