홈시리즈멘토링

© 2026 정기창. All rights reserved.

본 블로그의 콘텐츠는 CC BY-NC-SA 4.0 라이선스를 따릅니다.

☕후원하기소개JSON Formatter러닝 대기질개인정보처리방침이용약관

© 2026 정기창. All rights reserved.

콘텐츠: CC BY-NC-SA 4.0

☕후원하기
소개|JSON Formatter|러닝 대기질|개인정보처리방침|이용약관

adb로 안드로이드 실기기를 원격 조작하며 QA하기

정기창·2026년 7월 28일

「맥에서 Xcode 없이 안드로이드 앱 실기기 테스트하기」 3부작의 완결편입니다. 앞의 2부 「Expo dev-client로 안드로이드 실기기에 앱 올리고 Metro 붙이기」에서 이어집니다.

2부에서 dev-client 빌드를 실기기에 올리고 Metro(8081)까지 붙였습니다. 앱이 기기 위에서 돌기 시작하자, 이번에는 다른 고민이 생겼습니다. 로그인부터 영상 업로드, 결과 확인까지 같은 시나리오를 손으로 몇 번이고 반복해서 눌러보고 있었는데, 이걸 매번 사람이 해야 하나 하는 생각이 들었습니다. scrcpy로 미러링 창을 띄워 두고 마우스로 클릭하는 것도, 편하긴 했지만 결국은 수작업이었습니다.

미러링은 '보는' 용도, adb는 '조작하는' 용도

처음에는 brew install scrcpy로 화면 미러링부터 시작했습니다. USB로 연결한 기기 화면이 맥에 그대로 떠서, 사람이 눈으로 확인하기에는 이만한 게 없습니다. 다만 스크립트로 같은 동작을 반복하려고 하면 미러링은 갑자기 애매해집니다. 미러링 창의 픽셀을 마우스로 누르는 건 자동화가 아니라 그냥 원격 클릭이기 때문입니다.

그래서 역할을 나눴습니다. 미러링은 사람이 지켜보는 용도, adb는 스크립트가 조작하고 검증하는 용도입니다. 반복 검증의 실제 일은 미러링 창이 아니라 adb가 직접 합니다.

brew install scrcpy   # 사람이 눈으로 볼 때만
# 반복 조작·검증은 adb 로

캡처하고, 좌표로 누른다 — 기본 동작

adb로 화면을 조작하는 기본기는 의외로 단출합니다. 화면을 이미지로 뜨고, 좌표를 찍어 누르고, 텍스트를 넣는 것이 거의 전부입니다.

adb exec-out screencap -p > shot.png         # 현재 화면 캡처
adb shell input tap 540 1200                 # (x, y) 좌표 탭
adb shell input swipe 540 1600 540 800 300   # 스와이프 (마지막은 ms)
adb shell input text "hello@example.com"     # 텍스트 입력
adb shell input keyevent 4                   # 뒤로가기(KEYCODE_BACK)

screencap으로 지금 화면을 이미지로 받아 어디를 누를지 좌표를 정하고, input tap으로 그 좌표를 누릅니다. 이 캡처와 탭을 번갈아 돌리면, 사람이 화면을 보고 손가락을 옮기는 과정을 그대로 코드로 옮길 수 있습니다.

가장 먼저 막힌 곳 — 좌표가 어긋난다

그런데 첫 시도에서 input tap이 엉뚱한 곳을 눌렀습니다. 캡처 이미지에서 버튼 중심을 재서 좌표를 넣었는데, 실제로는 그보다 위를 누르고 있었습니다.

원인은 해상도였습니다. 기기의 물리 해상도(예: 1440×2960)와, 개발자 옵션 등으로 걸린 override 해상도(예: 1080×2220)가 다르면 좌표계가 둘이 됩니다. input tap은 현재 override 해상도를 기준으로 좌표를 받는데, 저는 미러링 창에서 축소되어 보이는 픽셀을 재고 있었으니 어긋날 수밖에 없었습니다.

해결은 간단합니다. 좌표는 반드시 adb exec-out screencap이 내놓는 이미지의 픽셀을 기준으로 잡습니다. 그리고 지금 화면이 어느 해상도인지 wm size로 먼저 확인합니다.

adb shell wm size
adb shell pidof com.example.myapp                       # 앱이 살아있는지
adb shell dumpsys activity | grep topResumedActivity    # 지금 포커스가 어디인지
Physical size: 1440x2960
Override size: 1080x2220

Override가 잡혀 있으면 캡처도 그 해상도로 나오고 탭도 그 좌표계로 들어갑니다. 둘의 기준이 같아지는 순간 좌표는 더 이상 어긋나지 않습니다. 화면 전환을 기다릴 때는 pidof로 앱이 떠 있는지, topResumedActivity로 지금 포커스가 어느 화면인지 확인해 두면, 로딩이 끝나기 전에 다음 탭이 나가버리는 실수를 막을 수 있습니다.

진짜 함정 — 넣은 영상이 갤러리에 안 뜬다

여기까지는 예열이었고, 이번 편에서 가장 오래 붙잡은 곳은 따로 있었습니다. 업로드 시나리오를 검증하려면 갤러리 피커에서 테스트 영상을 골라야 하는데, adb push로 분명히 영상을 넣었는데도 피커에 아무것도 뜨지 않았습니다.

파일은 기기 안에 있었습니다. ls로 찍어보면 멀쩡히 존재했습니다. 그런데 갤러리는 그 파일의 존재를 몰랐습니다. 원인은 구형 안드로이드(Android 9)의 미디어 스캐너였습니다. 이 버전의 스캐너는 .MOV 확장자를 잘 색인하지 않았고, 수백 MB에서 1GB에 이르는 초대형 파일도 건너뛰었습니다. 파일을 넣는 것과 미디어 DB에 색인되는 것은 별개의 일이었던 셈입니다.

해결은 두 가지를 함께 했습니다. 확장자를 .mp4로 바꾸고 크기를 적당히 줄인 뒤, 스캔을 직접 강제했습니다.

adb push test.mp4 /sdcard/DCIM/Camera/test.mp4
adb shell am broadcast -a android.intent.action.MEDIA_SCANNER_SCAN_FILE \
  -d file:///sdcard/DCIM/Camera/test.mp4

# 미디어 DB에 색인됐는지 확인
adb shell content query --uri content://media/external/video/media \
  --projection _display_name --where "_display_name='test.mp4'"

브로드캐스트로 스캐너를 깨우고 나면 피커에 영상이 나타납니다. content query로 미디어 DB를 직접 들여다보면 파일이 색인됐는지를 갤러리를 열지 않고도 확인할 수 있어서, 자동화 루프 안에 넣기에 좋았습니다.

자동화가 넘지 않아야 할 선 — 잠금은 사람이 푼다

한 가지는 처음부터 자동화 대상에서 뺐습니다. 화면 잠금(PIN·지문)입니다. adb로 못 푸는 것은 아니지만, 자격증명을 코드로 흘려 넣는 순간 그 스크립트는 다루기 위험한 물건이 됩니다. 그래서 잠금 해제와 민감한 재인증 팝업은 사람이 처리하도록 경계를 그었습니다.

돌이켜 보면 이 경계를 명확히 둔 게 오히려 마음이 편했습니다. 자동화가 어디까지 하고 어디서부터 사람에게 넘기는지를 분명히 해 두면, 스크립트가 조용히 위험한 곳까지 넘어가는 일을 걱정하지 않아도 됩니다.

캡처 → 판정 → 입력, 그 반복

결국 하고 싶었던 것은 하나의 루프였습니다. 화면을 캡처하고, 지금 어느 화면인지 판정하고, 다음 좌표를 누르는 것. 이 세 가지를 이어 붙이면 로그인부터 영상 업로드, 결과 확인까지 실기기 시나리오를 사람 손 없이 반복 재현할 수 있습니다. 무언가를 고치고 나서 회귀 검증이 필요할 때마다, 같은 루프를 다시 돌리면 됩니다.

3부작을 마치며

세 편을 짧게 회수하면 이렇습니다. 1부에서 Homebrew만으로 Xcode 없이 안드로이드 개발환경을 세팅했고, 2부에서 Expo dev-client로 실기기에 앱을 올려 Metro를 붙였으며, 이 3부에서 adb로 그 실기기를 원격 조작하며 QA했습니다. 맥 한 대와 안드로이드 기기 한 대, 그리고 커맨드라인 몇 줄이면 Xcode 없이도 실기기 검증의 처음부터 끝까지가 이어진다는 것을, 이번에 손으로 확인해 본 셈입니다.

「맥에서 Xcode 없이 안드로이드 앱 실기기 테스트하기」 3부작(완결). 앞 편: 「Expo dev-client로 안드로이드 실기기에 앱 올리고 Metro 붙이기」.

AndroidadbQA자동화scrcpy실기기테스트

관련 글

Expo dev-client로 안드로이드 실기기에 앱 올리고 Metro 붙이기

1부에서 만든 개발환경 위에서 Expo dev-client를 안드로이드 실기기에 올리고 Metro를 붙였습니다. CNG 원리, pnpm 모노레포의 Unable to resolve module, LAN IP 접속, adb 딥링크와 콜드 스타트까지 막혔던 지점을 순서대로 적었습니다.

관련도 96%

맥에서 Xcode 없이 안드로이드 개발환경 세팅하기 (Homebrew만으로)

iOS는 Xcode가 필수지만 안드로이드는 다릅니다. Android Studio 없이 Homebrew와 command-line tools만으로 React Native/Expo 개발환경을 세팅한 기록입니다. JDK 17 keg-only 함정부터 SDK 패키지, 에뮬레이터까지 막힌 순서 그대로 정리했습니다.

관련도 95%

Xcode 설치부터 아이폰 실기기 설치까지, 무료 계정으로 뚫은 관문 여섯 개

Xcode를 설치했는데도 아이폰에 앱이 올라가지 않았습니다. 커맨드라인 도구와 Xcode의 차이부터 무료 개발자 계정의 제약, 개발자 모드가 켜지지 않는 이유까지, 실제로 막혔던 여섯 지점과 원문 에러를 정리했습니다.

관련도 91%