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

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

 

안드로이드 스튜디오에서 플러터 프로젝트를 생성하고 기본 샘플 앱을 가상 안드로이드 기기로 실행했을때 발생한 에러 화면입니다. 뭔가 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
728x90

iOS 의 경우 Mac 과 함께 디버깅 하기 위한 궁합 및 도구가 편리하게 제공되고 있어서 어렵지 않게 Wireshark 로 기기의 패킷을 캡쳐할 수 있었습니다. 하지만 안드로이드 운영체제는 가상 인터페이스로 붙이는 방법이 없는 것처럼 보였고, 단말을 루팅하여 tcpdump 를 돌리는 것과 같은 방식들이 제안되고 있었습니다.

시험 기기로 확보한 기기가 삼성의 단말이고 제 소유가 아니다보니 루팅을 하는 것도 좀 꺼려지더군요. 그래서 찾아본 것이 바로 NOX Player 였습니다. 게임을 즐기는 사람들이면 안써본 사람이 없다는 NOX Player. 저는 게임을 하기 위해서도 아니고 안드로이드 기기의 패킷을 확인하기 위해서 NOX Player 를 처음 사용하게 되다니...


adb 를 통해 구동중인 NOX Player 의 안드로이드에 연결하기

우선 NOX Player 를 이용하여 적당한 안드로이드 이미지를 구동시킵니다. 기본적으로 Virtual Box 이지만 구동할 수 있는 이미지와 안드로이드 버전이 제한적인 것 같아 좀 아쉬웠습니다. API 버전이 안드로이드 운영체제 버전마다 차이가 있고, 이 차이가 실제 앱 구동에도 영향을 주는 것으로 알고 있습니다.

여튼, 안드로이드 운영체제가 잘 구동되면 NOX Player 로 62001 포트를 이용하여 연결이 가능해 집니다. 터미널에서 adb 를 이용하여 로컬호스트의 62001 포트로 연결을 맺어보겠습니다. 아래와 같은 명령을 사용하시면 되며, 정상적으로 연결된 경우 connected to 127.0.0.1:62001 이라는 메세지를 볼 수 있습니다. 

% adb connect 127.0.0.1:62001
adb server version (32) doesn't match this client (41); killing...
* daemon started successfully
connected to 127.0.0.1:62001

물론 iOS X Mac 과 달리 이렇게 연결했다 하여 바로 쉽게 Wireshark 로 직접 패킷을 볼 수 있는 것은 아닙니다. NOX Player 를 통해 TCP 덤프를 캡쳐해 줄 tcpdump 와 네트워크로 파일 내용을 전송해줄 netcat 을 복사하여 사용해야 합니다. 이 파일들을 이용하여 1) 파일로 떨군뒤 로컬 환경으로 복사하여 분석하거나 2) netcat 으로 전송 포트를 열어 adb 를 경유하여 wireshark 로 실시간으로 덤프를 보는 방법의 두가지 옵션을 쓸 수 있게 됩니다. 

 

안드로이드 기기로 tcpdump 와 netcat 파일 전송

우선 안드로이드 기기에서 구동되는 tcpdump 와 netcat 바이너리를 찾아야 합니다. 유통되는 왠만한 버전을 사용하는 것은 별 문제 없을거라 생각합니다. tcpdump 와 netcat 은 아래의 각 사이트에서 최근 버전을 다운로드 받으시기 바랍니다. (TCPDUMP : www.androidtcpdump.com/android-tcpdump/downloads, netcat : 실행파일만 받는게 좋은데... 경로를 잊어버렸습니다 ;; 찾는대로 다시 업데이트 해두겠습니다. )

안드로이드에서 사용할 유틸리티 2종이 준비되면 adb 의 push 명령을 이용하여 바이너리 파일을 NOX Player 의 안드로이드로 전송하도록 하겠습니다. 아래와 같이 가상 sdcard 의 경로 하위의 Download 폴더로 파일을 전송했습니다. 

% adb push netcat /sdcard/Download && adb push tcpdump /sdcard/Download
netcat: 1 file pushed. 27.1 MB/s (92156 bytes in 0.003s)
tcpdump: 1 file pushed. 48.3 MB/s (1889632 bytes in 0.037s)

/sdcard/Download 폴더로 전송한 파일을 다시 /system/xbin 경로로 이동시키도록 하겠습니다. 이 작업을 위해서는 adb 를 이용해 안드로이드 쉘에 접근해야 합니다. 아래와 같이 adb shell 명령을 입력하면 62001 포트를 통해 안드로이드 쉘에 접근할 수 있습니다. 일반적인 터미널에서처럼 cp 명령으로 파일을 옮기고, chmod 를 통해 실행 권한을 부여하도록 하겠습니다. chmod u+x 해도 무방합니다.

% adb shell
dream2lte:/ # cp /sdcard/Download/netcat /system/xbin/
dream2lte:/ # cp /sdcard/Download/tcpdump /system/xbin/
dream2lte:/ #
dream2lte:/ # chmod 755 /system/xbin/netcat
dream2lte:/ # chmod 755 /system/xbin/tcpdump

 

tcpdump 를 실행하여 pcap 파일로 패킷을 캡쳐하자

이제 패킷 덤프를 뜰 준비가 되었습니다. 일반적으로 사용하는 tcpdump 명령들을 대부분 사용할 수 있기 때문에 필요에 따라 옵션을 조합하시면 되겠습니다. 안드로이드의 모든 인터페이스로 들어오는 패킷을 캡쳐하여 /sdcard/Download 경로에 pcap 파일로 떨구는 명령의 예제는 아래와 같습니다. 캡쳐를 중지하려면 ctrl-c 등으로 중지 시그널을 보내시면 됩니다. 참 쉽죠?

dream2lte:/ # tcpdump -i any -n -s 0 -w /sdcard/Download/1557.pcap
tcpdump: listening on any, link-type LINUX_SLL (Linux cooked), capture size 262144 bytes
^C73886 packets captured
88490 packets received by filter
1864 packets dropped by kernel

 

캡쳐한 pcap 파일을 로컬로 전송하여 분석해보자

이제 adb 의 옵션중 pull 을 이용하여 파일을 안드로이드 환경에서 로컬 환경으로 복사해 오도록 하겠습니다. . 소스, 목적지의 순서로 파라메터를 넣으면 되겠죠? 아래는 그 예제입니다. 캡쳐를 오랫동안 하지 않았지만 포트에 상관없이 모든 패킷을 캡쳐하다보니 양이 많습니다.

안드로이드 시뮬레이터의 성능에 영향을 줄 수 있으니 로컬 환경에서와 달리 tcpdump 를 사용할 때는 포트와 같은 조건을 꼼꼼히 넣어주시는 것이 좋습니다. 캡쳐된 pcap 파일이 로컬 환경으로 복사가 완료되면 wireshark 를 이용하여 파일을 열고 패킷을 분석하시면 됩니다. 

% adb pull /sdcard/Download/1557.pcap ./
/sdcard/Download/1557.pcap: 1 file pulled. 22.1 MB/s (96239260 bytes in 4.150s)

 

netcat 을 이용하여 실시간으로 패킷 분석하기

파일로 이용하여 패킷을 분석하는 것은 왠지 절차가 좀 복잡해 보입니다. 그리고 실시간으로 변화를 관찰할 수 없어 캡쳐가 잘못된 경우 다시 동일한 과정을 반복해야 합니다. 정상적인 사람인 우리들은 이런 불편함을 참을수가 없습니다 ㅎㅎ 이때는 netcat 을 이용해서 캡쳐되는 파일들을 특정 포트로 노출시켜 wireshark 가 받도록 하는 방법을 사용할 수 있습니다. 

1) 우선 터미널을 두개 띄웁니다. 하나는 adb shell 로 안드로이드에서 tcpdump 를 실행하는 목적이고, 다른 하나는 adb forward 로 로컬 환경의 wireshark 로 데이터를 보내는 목적입니다.

2) 1번 터미널 - 조금전과 마찬가지로 안드로이드 쉘에서 tcpdump 를 실행해야 합니다. 이때, 캡쳐된 내용을 파일로 떨구지 말고 파이프(|)를 사용하여 netcat 이 내용을 전달 받도록 하겠습니다. netcat 는 특정 포트 (아래에서는 12345) 로 전달 받은 내용을 전송하게 됩니다. tcpdump 에서 이 포트의 트래픽은 캡쳐하지 않도록 not port 12345 를 파라메터에 넣었다는 점도 참고해 주세요!

2) 2번 터미널 - 이제 로컬 쉘에서 adb forward 명령을 이용해 시뮬레이터의 프로토콜:포트를 로컬의 프로토콜:포트로 전달하겠습니다. 맥 환경에서의 netcat 인 nc 명령으로 해당 포트를 수신하고, 파이프를 통해 wireshark 로 수신된 내용을 전달하는 명령입니다. 

// 터미널 #1 (안드로이드 쉘에 접근) - tcpdump 로 패킷 떠서 netcat 으로 내보내기
% adb shell
% # tcpdump -i any -n -s 0 -w - not port 12345 | netcat -l -p 12345
tcpdump: listening on any, link-type LINUX_SLL (Linux cooked), capture size 262144 bytes
^C2606396 packets captured
2779150 packets received by filter
164234 packets dropped by kernel

// 터미널 #2 (로컬 쉘) - netcat 이 내보내는 것 받아서 wireshark 로 넘기기
% adb forward tcp:12345 tcp:12345 && nc 127.0.0.1 12345 | wireshark -k -S -i -

다소 번거롭지만 NOX Player 를 이용하여 안드로이드 기기의 패킷을 캡쳐하고 로컬의 wireshark 로 전달하여 분석하는 두가지 방법을 살펴보았습니다. 기기를 루팅하지 않고 패킷을 캡쳐할 방법이 없기 때문에 시뮬레이터로 부담 없이 패킷을 분석해 보시기 바랍니다. 

 

728x90
728x90

개발을 하던 다른 트러블 슈팅을 하던 기기의 패킷을 추출해야 하는 경우들이 많습니다. Mac 을 사용하는 경우 rvi (Remote Virtual Interface) 를 이용해서 기기를 연결해서 쉽게 와이어샤크 Wireshark 같은 물건으로 패킷을 캡쳐할 수 있습니다. 말 그대로 가상 네트워크 인터페이스로 iOS 기기를 설정하기 때문이죠.

개인 기기로 아이폰을 쓰다보니 안드로이드는 샤오미 홍미4 이후 오랫동안 쓴적이 없었습니다. 그나마도 딸래미 학교 들어가면서 비상연락용 겸 슬랙 서적 집필할 때 화면 캡쳐용으로 산거라 진심을 다해서 써보지도 않았습니다. 허나, 현실에서는 안드로이드 환경의 패킷을 확인해야 하는 일이 종종 생기더군요.


ADB, 안드로이드 디버그 브릿지

이유는 잘 기억나지 않지만 제 Mac 에도 안드로이드 스튜디오 Android Studio 가 이미 설치되어 있었습니다 -_-;; ADB 는 Android SDK 개별 설치 혹은 Android Studio 설치시 SDK 에 딸려서 설치되는 디버그 툴인 것 같습니다. 패킷을 뜨기 위해 기기를 연결할 필요가 있었는데요 (사실은 NOX 로 기기 에뮬레이션해서...) ADB 가 그냥 실행이 되지는 않더군요.

Android Studio 가 정상적으로 동작하고 있다면 ADB 는 어딘가에 잘 설치가 되어 있는 상태입니다. 제 경우에는 아래의 Path 에서 해당 내용을 확인할 수 있었습니다. 아마 대부분 비슷한 경로에 설치가 되어 있을거라 생각합니다. 

% pwd
/Users/nopd/Library/Android/sdk/platform-tools

 

Path 로 경로 잡아주기

보통 SDK 가 설치되면 자동으로 Path 를 설정해 주는 경우가 많은데 Android SDK 는 그러지 않나 봅니다. (혹은 제가 영어로 나온 메세지를 놓친 것일지도... 속닥속닥...) 제 경우 필요한 터미널 환경 설정을 .bash_profile 에 하고 있어서 아래와 같이 Android SDK 의 Platform tools 경로를 추가해 주었습니다. 이렇게 해주고나니 어디서든 adb 를 실행할 수 있게 되었습니다 ㅎㅎ 

# Setting PATH for Android Platform Tools (esp for ADB)
export PATH="${PATH}:/Users/nopd/Library/Android/sdk/platform-tools"

그럼! 즐거운 디버깅 되시길 기원합니다. 이제 저는 NOX 와 씨름하러...

728x90

+ Recent posts