# Android 공기계 로컬 USB 테스트 전환 검토

작성일: 2026-07-08
상태: 검토 완료

## 1. 목적

기존 Windows Android Studio emulator + WSL/Docker Flutter 기반 테스트는 유지하되, 앞으로의 기본 수동/통합 테스트 경로를 "집에서 가져온 Android 공기계 + 로컬 PC USB 연결" 방식으로 전환할 수 있는지 검토한다.

이번 검토의 범위는 아래와 같다.

- 현재 저장소에서 emulator 전용 가정이 어디에 있는지 확인
- 공기계 연결 방식으로 바꿀 때 유지 가능한 코드와 추가 필요한 보강점을 구분
- 실제 전환 시 가장 작은 변경 경로를 제안

## 2. 결론 요약

- 앱 코드 자체는 공기계 테스트로 전환 가능한 구조다. 실행 시점에 `TDC114_API_BASE`를 `--dart-define`으로 주입하는 방식이라 target만 안정적으로 잡히면 emulator와 device를 공용으로 사용할 수 있다.
- 현재 가장 강하게 emulator에 묶여 있는 부분은 앱 로직이 아니라 운영 스크립트와 문서다.
- 공기계 전환의 핵심 이점은 Windows emulator portproxy, Docker local ADB, remote ADB server, VM service dynamic port 문제를 대부분 피할 수 있다는 점이다.
- 다만 실기기에서는 emulator 전용 주소 `10.0.2.2`를 쓸 수 없고, 로컬 HTTP 접근은 Android cleartext 정책에 막힐 가능성이 높다.
- 따라서 "기존 emulator 코드는 유지"하면서도, 앞으로는 실기기용 env/체크 스크립트/실행 절차를 별도로 추가하는 방식이 가장 안전하다.

## 3. 현재 코드/스크립트 구조에서 확인한 사항

### 3.1 target 선택 자체는 이미 공용화되어 있음

- `scripts/integration_tests.sh`
  - `TDC114_FLUTTER_DEVICE_ID` 또는 `TDC114_ADB_CONNECT_ADDRESS`가 있으면 해당 target으로 실행한다.
  - 즉, Flutter가 실기기를 인식하기만 하면 integration test 명령 자체는 재사용 가능하다.
- `scripts/manual-postlogin-run.sh`
  - `TDC114_FLUTTER_DEVICE_ID` 또는 `TDC114_ADB_CONNECT_ADDRESS` 기반으로 `flutter run -d <device>`를 실행한다.
  - 수동 점검 경로도 공기계 전환에 재사용 가능하다.
- `scripts/flutter-docker.sh`
  - `ADB_SERVER_SOCKET`, `TDC114_ADB_CONNECT_ADDRESS`를 Docker에 전달한다.
  - 구조상 device 연결 경로도 수용할 수 있다.

### 3.2 실제로는 preflight와 운영 정책이 emulator 기준임

- `scripts/check-android-emulator-env.sh`
  - 이름부터 emulator 전용이다.
  - Windows Android Studio, Device Manager, portproxy, emulator GUI 복구 절차를 전제로 한다.
- `scripts/startup.sh`
  - 기본 Android precheck 스크립트가 `check-android-emulator-env.sh`로 고정돼 있다.
- 문서 다수
  - `docs/checklist_morning_startup_runtime_2026-07-03.md`
  - `docs/policy_android_studio_wsl_adb_2026-07-03.md`
  - `docs/scenario_android_emulator_device_integration_test_2026-07-03.md`
  - 위 문서들은 현재 운영 중심축이 emulator임을 보여준다.

### 3.3 emulator 전용 API 주소 가정이 남아 있음

- `scripts/integration_tests.sh`
  - bootstrap용 base URL에서 `10.0.2.2 -> 127.0.0.1` 치환을 수행한다.
- `scripts/manual-postlogin-run.sh`
  - 동일하게 `10.0.2.2 -> 127.0.0.1` 치환을 수행한다.
- 문서 전반
  - emulator env는 `TDC114_API_BASE=http://10.0.2.2:5000`을 표준으로 본다.

이 부분은 "실기기에서 무엇을 쓸지"만 정하면 큰 문제는 아니다. 실기기는 아래 둘 중 하나면 된다.

- `adb reverse tcp:5000 tcp:5000` 후 `http://127.0.0.1:5000`
- 같은 LAN에서 `http://<PC_LAN_IP>:5000`

## 4. 공기계 전환 시 기대 효과

### 4.1 사라지거나 크게 줄어드는 문제

- Windows emulator GUI 상태 의존
- `5037` ADB server 공유 문제
- `5555`/`5557`/`5559` 같은 emulator adbd portproxy 관리
- Docker 내부 local ADB key와 Windows ADB key 불일치
- remote Windows ADB server가 만든 VM service dynamic port가 Docker localhost와 어긋나는 문제

즉, 지금까지 반복된 문제의 상당수는 "앱" 문제가 아니라 "Windows emulator를 WSL/Docker Flutter에서 원격으로 다루는 구조"에서 생겼다. USB 실기기는 이 복잡도를 상당히 낮춘다.

### 4.2 새로 관리해야 하는 문제

- 공기계의 USB 디버깅/RSA 승인 상태
- `adb reverse` 재설정 필요 여부
- 단말과 PC가 같은 네트워크인지 여부(LAN IP 방식일 때)
- Android의 cleartext HTTP 허용 여부

## 5. 가장 중요한 기술 리스크

### 5.1 Android cleartext HTTP 차단 가능성

현재 `app/android/app/src/main/AndroidManifest.xml`에는 아래가 없다.

- `android:usesCleartextTraffic="true"`
- debug용 `network_security_config`

로컬 Baron API는 현재 문서와 스크립트 기준으로 주로 `http://127.0.0.1:5000`, `http://10.0.2.2:5000`, `http://<PC_LAN_IP>:5000`를 사용한다. 실기기에서 debug APK를 띄웠을 때 Android 버전에 따라 cleartext가 차단될 수 있다.

따라서 공기계 전환 전에 가장 먼저 확인할 항목은 이것이다.

1. 공기계에서 `flutter run --dart-define=TDC114_API_BASE=http://127.0.0.1:5000` 또는 LAN IP로 실행
2. 로그인/디렉토리 API 호출이 실제로 되는지 확인
3. 차단되면 debug 전용 cleartext 허용 설정 추가

### 5.2 `adb reverse`와 Docker 컨테이너 내부 ADB의 관계

실기기에서 가장 단순한 API 접근 방식은 `adb reverse tcp:5000 tcp:5000`이다. 다만 현재 테스트 명령은 `scripts/flutter-docker.sh`를 통해 Docker 컨테이너 안에서 실행되는 경우가 많다.

검토 시점 기준으로 확인된 점:

- `flutter drive`/`flutter run`은 Docker 내부에서 수행된다.
- `adb reverse`를 누가 실행하느냐에 따라 적용 대상이 달라질 수 있다.

따라서 실무상 가장 안전한 기준은 아래 순서다.

1. 먼저 Windows 또는 WSL host에서 `adb devices`로 공기계가 `device` 상태인지 확인
2. 같은 ADB 경로에서 `adb reverse tcp:5000 tcp:5000` 실행
3. 이후 Docker Flutter가 동일 device를 보는지 확인

만약 Docker 내부 ADB와 host ADB가 서로 다른 서버/세션을 쓰면 `adb reverse`가 예상대로 먹지 않을 수 있다. 그 경우에는 LAN IP 방식을 백업 경로로 잡는 것이 안전하다.

## 6. 변경 영향 검토

### 6.1 그대로 재사용 가능한 것

- `app/` 내부 Dart 앱 코드 대부분
- `app/integration_test/app_smoke_test.dart`
- `app/test_driver/integration_driver.dart`
- `scripts/api-smoke.sh`
- `scripts/check-baron-api-env.sh`
- `scripts/integration_tests.sh`의 기본 실행 구조
- `scripts/manual-postlogin-run.sh`의 post-login seed 구조

### 6.2 공기계 기준으로 별도 추가하는 편이 좋은 것

- 실기기 전용 env 예시
  - `scripts/.env.android-device.local`는 이미 문서상 가정만 있고 tracked example은 부족하다.
- 실기기 preflight 스크립트
  - 예: `scripts/check-android-device-env.sh`
- 실기기 실행 가이드 문서
  - USB 디버깅, RSA 승인, `adb reverse`, LAN IP fallback 포함

### 6.3 나중에 일반화하면 좋은 것

- `check-android-emulator-env.sh`를 유지한 채, 상위 래퍼 `check-android-target-env.sh`를 만들어
  - `TDC114_ANDROID_TARGET_KIND=emulator|device`
  - 또는 env 유무 기준으로 분기
- `startup.sh`에서 precheck script를 교체 가능하게 유지하되, 기본 정책 문구를 "Android target" 기준으로 일반화

## 7. 권장 전환 방식

기존 emulator 코드는 그대로 두고 아래 순서로 가는 것을 권장한다.

1. 이번 테스트까지만 기존 emulator 경로 사용
2. 그 다음부터는 공기계를 기본 target으로 사용
3. 초기에는 `manual-postlogin-run.sh` 중심으로 수동 기능점검부터 안정화
4. 그 다음 `integration_tests.sh`를 공기계 target으로 재사용
5. 충분히 안정화된 뒤에만 `startup.sh` 기본 Android precheck를 실기기 기준으로 확장

## 8. 최소 실행 초안

### 8.1 공기계 수동 점검

```bash
# 1) 공기계 USB 연결 후 host에서 device 확인
adb devices

# 2) reverse 방식 선택 시
adb reverse tcp:5000 tcp:5000

# 3) 실기기용 env 준비
# scripts/.env.android-device.local
TDC114_API_BASE=http://127.0.0.1:5000
TDC114_SMOKE_PHONE=010xxxxxxxx

# 4) 앱 실행
TDC114_SMOKE_ENV_FILE=scripts/.env.android-device.local \
TDC114_FLUTTER_DEVICE_ID=<physical_device_id> \
./scripts/manual-postlogin-run.sh
```

### 8.2 공기계 integration test

```bash
TDC114_SMOKE_ENV_FILE=scripts/.env.android-device.local \
TDC114_FLUTTER_DEVICE_ID=<physical_device_id> \
./scripts/integration_tests.sh
```

LAN IP 방식을 쓰는 경우 env의 `TDC114_API_BASE`만 `http://<PC_LAN_IP>:5000`로 바꾼다.

## 9. 최종 판단

공기계 전환은 타당하다. 현재 막힌 문제의 대부분은 emulator 자체보다도 "Windows emulator + WSL/Docker Flutter + 원격 ADB/portproxy" 조합에서 발생했다.

따라서 다음 기본 방침은 합리적이다.

- emulator 경로는 보존
- 앞으로의 기본 테스트는 공기계 USB 연결 방식으로 전환
- 초기 목표는 "수동 post-login 점검 안정화"
- 그 다음 "integration_tests.sh 공기계 재사용"

단, 실전 전환 전에 반드시 먼저 확인할 항목은 아래 2개다.

1. 공기계에서 local HTTP API가 cleartext 차단 없이 실제 호출되는가
2. `adb reverse`가 Docker Flutter 실행 경로에서도 안정적으로 유지되는가

이 2개가 통과하면 emulator 대비 운영 복잡도는 확실히 낮아질 가능성이 높다.
