에뮬레이터 자동화 스크립트 대수술
목차
저녁 6시부터 자정까지, 이 시간대의 핵심은 단 하나였다. 여러 Android 앱을 에뮬레이터에서 자동 설치/재설치하는 스크립트들이 제각각 흩어져 있던 걸 하나씩 정리하고, 거기서 터진 버그들을 잡는 것. 릴리즈 날짜가 당겨지는 상황에서 수동으로 에뮬 띄우고, 앱 설치하고, 다시 세팅하는 반복 작업이 너무 많았다. 이걸 스크립트화해두지 않으면 다음 사람(미래의 나 포함)이 똑같은 삽질을 반복한다. 그래서 이날 저녁은 통째로 "자동화 빚 갚기"에 썼다.
adb unauthorized 문제와 콜드부팅 복구
가장 시간을 많이 잡아먹은 건 intonaire_reinstall.sh였다. 처음 스크립트를 짤 때는 adb 연결이 항상 깔끔하게 붙는다고 가정했는데, 실제로 돌려보면 에뮬레이터가 unauthorized 상태로 뜨는 경우가 있었다. 특히 에뮬을 껐다 켰거나 호스트 측 adb 데몬이 죽었다 살아났을 때 이게 자주 터졌다.
unauthorized 상태에서 adb shell 때리면 그냥 permission denied로 떨어지고, 스크립트 전체가 조용히 실패한다. 에러 메시지도 딱히 안 나오니까 처음엔 왜 설치가 안 되는지 한참 헤맸다. 결국 흐름을 이렇게 바꿨다:
# adb 상태 체크 후 unauthorized면 콜드부팅으로 복구
STATUS=$(adb -s "$SERIAL" get-state 2>&1)
AUTH=$(adb -s "$SERIAL" shell echo ok 2>&1)
if [[ "$AUTH" != "ok" ]]; then
echo "[!] adb unauthorized 감지 — 콜드부팅 시도"
adb -s "$SERIAL" emu kill
sleep 5
# 에뮬 재기동 로직
...
fi
콜드부팅 후 adb 데몬 재시작하면 보통 authorized로 복구된다. 이 로직을 넣고 나서야 스크립트가 중간에 말없이 죽는 일이 없어졌다. 사실 이 부분은 "에뮬레이터 자동화 스크립트라면 기본 중에 기본"인데, 처음엔 귀찮아서 대충 넘겼다가 결국 더 많은 시간을 날렸다. 반면교사.
좌표 실측은 또 별개의 작업이었다. intonaire_reinstall.sh에서 설치 버튼을 adb tap으로 누르는 부분이 있는데, 에뮬 해상도나 밀도 설정이 바뀌면 좌표가 틀어진다. 이번에 에뮬 신버전으로 올리면서 설치 버튼 Y 좌표가 기존에 하드코딩해둔 값이랑 달라졌다. 실제로 에뮬 띄우고 adb shell input tap 날려서 확인한 결과 Install 버튼 기준 Y=1458, 특정 다이얼로그 기준 Y=752로 바뀐 걸 확인하고 반영했다. 좌표 기반 자동화의 고질적인 문제다. 에뮬 버전 올릴 때마다 이 작업을 수동으로 해야 한다는 게 불편하긴 한데, 지금 단계에선 layout inspector로 뽑아서 박는 게 현실적으로 빠르다.
love, jlpt, intonaire - 앱마다 다른 설치 패턴
이날 다룬 앱이 세 개였는데, 설치 흐름이 각각 달라서 스크립트도 따로 관리하고 있다.
love_setup_and_run.sh는 옵트인 단계가 있다. 앱을 그냥 설치하는 게 아니라, 특정 플래그를 켜서 설치해야 하는 옵트인 플로우가 있고, 그 다음에 실행까지 한 번에 이어져야 한다. 기존엔 옵트인 스텝이랑 설치 스텝이 별개 스크립트로 나뉘어 있어서 순서를 헷갈리거나 중간 스텝 빠뜨리는 일이 있었다. 이걸 love_setup_and_run.sh 하나로 통합해서, 실행 하나로 옵트인 - 설치 - 실행까지 이어지도록 정리했다.
open_jlpt_batch.sh는 좀 다른 케이스다. JLPT 관련 앱은 자동 설치가 아직 완성이 안 된 상태라서, 배치 파일로 수동 설치 흐름을 안내하는 용도로 만들었다. 완전 자동화가 아닌 반자동이지만, 그래도 "이 순서대로 하세요" 가이드를 스크립트로 묶어두면 실수가 줄어든다. 임시방편이긴 해도 실용적인 선택이었다.
| 앱 | 설치 방식 | 자동화 수준 | 비고 |
|---|---|---|---|
| love | 옵트인 + adb install + 실행 | 완전 자동 | 신규 통합 |
| jlpt | 배치 오프너 (수동 유도) | 반자동 | 추후 자동화 예정 |
| intonaire | adb install + 좌표 tap | 완전 자동 | 콜드부팅 복구 추가 |
크래시픽스 진행상태 추적과 에뮬 신버전 대응
update_pass.sh와 CLAUDE.md 업데이트는 큰 작업은 아니었지만 맥락상 중요했다. 에뮬레이터 신버전이 들어오면서 기존 update_pass.sh가 맞지 않는 부분이 생겼고, 신버전 동작 방식에 맞춰 수정했다. 이 타이밍에 크래시픽스 진행상태도 함께 기록해뒀다.
lumen과 gwang은 둘 다 13/13 완료 상태를 찍었다. 원래 크래시 재현 케이스를 하나씩 잡아가는 방식이었는데, 이날 시점에서 두 앱 모두 전체 케이스를 처리한 것. gwang은 재설치 스크립트(gwang_reinstall.sh)도 이번에 같이 손봤다. intonaire는 전송 재시도 상태로, 아직 진행 중인 케이스가 남아 있다. 이 상황을 CLAUDE.md에 기록해두는 이유는, 팀 내에서 "지금 어디까지 됐어?" 물어볼 때마다 구두로 설명하는 게 번거롭기 때문이다. 진행 상태는 코드 옆에 붙여두는 게 제일 확실하다.
# 크래시픽스 현황 (2026-07-03 기준)
# lumen : 13/13 완료
# gwang : 13/13 완료
# intonaire : 전송 재시도 중
간단한 주석 몇 줄이지만, 다음 번에 이 파일 열었을 때 컨텍스트 복원 시간이 확 줄어든다.
문서 작업 - Play 프로덕션 액세스 신청
PLAY-PRODUCTION-APPLICATION.md는 이날 저녁 작업 중 유일하게 "코드 아닌" 작업이었다. Play 스토어 프로덕션 액세스 신청을 하면 구글 측에서 검토 질문이 오는데, 그 답변을 어떻게 작성할 것인지 지침 문서를 정리한 것. 앱마다 심사 통과 기준이 조금씩 달라서, "이 앱은 이런 포인트를 강조해서 답변해라"는 식의 가이드가 있으면 다음 신청 때 처음부터 고민을 반복하지 않아도 된다.
스크립트 작업과는 결이 다르지만, 결국 같은 목표다. 반복 작업을 줄이고, 다음 번 실행 비용을 낮추는 것. 코드든 문서든 한 번 정리해두면 이자처럼 돌아온다.
이날 작업을 돌아보면, 아이러니하게도 "자동화를 위한 자동화"가 얼마나 손이 많이 가는 일인지를 다시 실감했다. adb 좌표 실측하고, unauthorized 케이스 디버깅하고, 앱마다 다른 설치 패턴 정리하고. 완성된 스크립트 하나가 돌아가는 걸 보면 5분짜리처럼 보이지만, 그 뒤에 에뮬 수십 번 재부팅과 좌표 하나 맞추려는 tap 테스트들이 쌓여 있다. 그래도 한 번 잘 만들어두면 이후론 진짜 5분이 된다. 그 빚을 이날 저녁에 많이 갚았다.
🛒 이 글과 어울리는 추천 상품
*위 링크는 쿠팡파트너스 활동의 일환이며, 일정액의 수수료를 제공받을 수 있습니다.
댓글 0
첫 댓글 달아줘.