Loading the catalog…
Loading the catalog…
개요 폰을 케이블로 데스크탑에 꽂아두고 Claude Code 에게 "앱이 왜 죽는지 봐줘" 라고 하면, 알아서 기기 모델과 OS 버전을 확인하고 로그를 뒤져서 크래시 원인을 찾아온다. 처음 보면 Claude Code 가 폰과 직접 통신하는 특별한 기능이 있는 것처럼 느껴진다. 실제로는 그런 기능이 없다. Claude Code 가 하는 일은 터미널에서 adb 나 xcrun devicectl 같은 명령을 실행하고 그 출력을 읽는 것뿐이다. 폰과 통신하는 일은 원래 있던 개발 도구들이 하고, Claude Code 는 그 도구를 사람 대신 두드린다. 이 글은 케이블을 꽂는 순간부터 Claude Code 가 폰의 값을 읽어내기까지 어떤 층이 쌓여 있는지를 아래에서부터 정리한다. Android 를 중심으로 보고, iOS 는 차이점만 짚는다. 전체 구조 먼저 그림 한 장으로 층을 나눠두면 이후 내용이 편하다. ┌──────────────────────────────────────────────┐ │ Claude Code (에이전트 루프) │ 어떤 명령을 칠지 판단 │ └─ Bash 도구 │ 명령 실행 → stdout 읽기 ├──────────────────────────────────────────────┤ │ adb client ──▶ adb server (localhost:5037) │ 데스크탑의 프로세스 ├──────────────────────────────────────────────┤ │ USB 프로토콜 (ADB 인터페이스) │ 케이블 ├──────────────────────────────────────────────┤ │ adbd (폰의 데몬) ──▶ shell, getprop, logcat │ 폰 안에서 실제 실행 └──────────────────────────────────────────────┘ 위 두 층과 아래 세 층은 완전히 독립적이다. Claude Code 가 없어도 아래 세 층은 그대로 동작하고, 개발자가 터미널에 adb logcat 을 치는 것과 Claude Code 가 치는 것은 폰 입장에서 구분되지 않는다. 케이블과 USB 인터페이스 데이터 선이 있는 케이블 USB-C 케이블이라고 다 같은 게 아니다. 충전 전용 케이블은 전원 선만 있고 데이터를 주고받는 D+/D− 선이 빠져 있다. 이런 케이블을 꽂으면 폰은 충전만 되고, 데스크탑의 USB 장치 목록에 아예 나타나지 않는다. adb devices 가 빈 목록을 돌려줄 때 설정보다 케이블을 먼저 의심해야 하는 이유가 이것이다. 폰에 딸려온 케이블이나 데이터 전송이 명시된 케이블을 쓰는 게 가장 빠른 해결책이다. 폰이 자신을 소개하는 과정 데이터 선이 연결되면 데스크탑의 USB 호스트가 폰에게 "너는 어떤 장치냐" 를 묻는다. 폰은 자신이 제공하는 인터페이스 목록으로 답한다. 파일 전송용 MTP, 사진 전송용 PTP, 그리고 개발자 옵션에서 USB 디버깅을 켜면 ADB 인터페이스 가 이 목록에 추가된다. ADB 인터페이스는 class 0xFF , subclass 0x42 , protocol 0x01 이라는 고유한 조합으로 식별된다. 데스크탑의 adb server 는 이 조합을 가진 USB 인터페이스를 찾아서 폰으로 인식한다. 폰의 USB 모드가 "충전만" 으로 되어 있어도 디버깅이 켜져 있으면 대부분 이 인터페이스는 살아 있다. ADB 의 세 구성 요소 ADB 는 하나의 프로그램이 아니라 세 조각으로 나뉘어 있다. client — 터미널에서 실행하는 adb 명령 그 자체다. 명령을 받아서 server 로 넘기고 결과를 출력한 뒤 종료된다. server — 데스크탑에서 백그라운드로 상주하며 localhost:5037 을 연다. USB 로 연결된 기기를 감시하고, 여러 client 의 요청을 적절한 기기로 보낸다. adbd — 폰 안에서 도는 데몬이다. server 가 보낸 요청을 받아 셸 명령을 실행하고 결과를 돌려준다. 처음 adb devices 를 치면 "daemon not running; starting now at tcp:5037" 이 찍히는 게 server 가 뜨는 순간이다. 그 다음부터는 같은 server 를 재사용한다. 이 구조 덕분에 Android Studio, React Native CLI, 터미널, Claude Code 가 동시에 같은 폰을 붙잡고 있어도 충돌하지 않는다. 전부 같은 server 에 요청하는 client 일 뿐이다. 반대로 Android Studio 가 들고 있는 adb 와 PATH 상의 adb 버전이 다르면 서로 server 를 죽이고 다시 띄우는 일이 반복되는데, 기기가 붙었다 끊겼다 하는 증상의 흔한 원인이다. RSA 키 인증 USB 디버깅은 폰의 셸을 통째로 여는 권한이라 아무 컴퓨터에나 허용되면 안 된다. 그래서 처음 연결할 때 RSA 키로 인증한다. 데스크탑의 adb 는 처음 실행될 때 ~/.android/adbkey 와 adbkey.pub 키 쌍을 만든다 폰에 연결하면 adbd 가 인증을 요구하고, server 는 공개키를 보낸다 폰 화면에 "USB 디버깅을 허용하시겠습니까?" 팝업과 키 지문이 뜬다 허용하면 공개키가 폰의 /data/misc/adb/adb_keys 에 저장된다 허용 전 상태에서 adb devices 를 치면 기기 옆에 unauthorized 가 찍힌다. Claude Code 가 이 출력을 받으면 "폰 화면에서 디버깅 허용을 눌러달라" 고 요청하는데, 이것도 특별한 지능이 아니라 이 상태 문자열의 의미를 알고 있어서다. unauthorized 가 계속 풀리지 않으면 폰의 개발자 옵션에서 "USB 디버깅 권한 승인 취소" 를 누르고 다시 연결하면 대부분 해결된다. Claude Code 가 값을 읽어내는 방식 여기까지가 폰과 데스크탑이 통신할 수 있는 기반이다. Claude Code 는 이 위에서 도구를 사용하는 에이전트로 동작한다. 에이전트 루프와 Bash 도구 Claude Code 의 동작은 단순한 반복이다. 모델이 다음에 할 행동을 고르고, 도구가 그걸 실행하고, 결과를 다시 모델이 읽는다. 폰과 관련된 작업에서 쓰이는 도구는 대부분 Bash 다. "연결된 폰 정보 알려줘" 라는 요청이 들어오면 흐름은 대략 이렇다. $ adb devices List of devices attached R3CT50ABCDE device $ adb shell getprop ro.product.model SM-S928N $ adb shell getprop ro.build.version.sdk 35 $ adb shell wm size Physical size: 1440x3120 모델은 학습 과정에서 adb 의 사용법과 출력 형식을 이미 알고 있다. 그래서 첫 명령의 결과를 보고 기기가 하나 붙어 있다는 걸 확인하고, 이어서 필요한 값을 읽는 명령을 스스로 고른다. 출력이 사람이 읽을 수 있는 텍스트라는 점도 중요하다. 별도의 파서 없이 모델이 그대로 해석할 수 있다. "알아서 파악한다" 는 느낌의 정체가 여기에 있다. 폰이 데이터를 밀어주는 게 아니라, 모델이 상황에 맞는 명령을 연달아 실행하며 끌어오는 것이다. 자주 읽는 값들 실무에서 Claude Code 가 주로 쓰는 명령은 정해져 있다. 목적 명령 기기 모델, OS 버전 adb shell getprop ro.product.model , ro.build.version.release 화면 크기와 밀도 adb shell wm size , adb shell wm density 설치된 앱 버전 adb shell dumpsys package <패키지명> | grep versionName 메모리 사용량 adb shell dumpsys meminfo <패키지명> 로그 adb logcat 스크린샷 adb exec-out screencap -p > screen.png 현재 화면의 뷰 계층 adb shell uiautomator dump 스크린샷은 특히 유용하다. 이미지 파일로 저장한 뒤 Claude Code 가 그 파일을 읽으면 화면을 직접 보고 레이아웃 문제를 판단할 수 있다. 텍스트 명령만으로는 알 수 없는 시각적 상태까지 확인 범위가 넓어진다. React Native 개발에서의 활용 RN CLI 개발자에게는 사실 익숙한 구조다. npx react-native run-android 도 내부적으로 adb 를 호출해서 APK 를 설치하고 앱을 실행한다. Metro 에 연결하는 것도 adb reverse tcp:8081 tcp:8081 로 폰의 8081 포트를 데스크탑으로 돌려두는 방식이다. Claude Code 는 같은 도구를 같은 방식으로 쓴다. 크래시 원인 추적 가장 효과가 큰 건 로그 분석이다. logcat 은 출력량이 많아서 사람이 눈으로 훑기 어려운데, Claude Code 는 필터링과 해석을 한 번에 한다. # RN 관련 로그만 adb logcat ReactNative:V ReactNativeJS:V *:S # 네이티브 크래시 adb logcat -b crash -d New Architecture 환경에서는 TurboModule 이나 Fabric 컴포넌트에서 네이티브 크래시가 나면 JS 쪽 에러 화면 없이 앱이 그냥 꺼지는 경우가 있다. 이때 -b crash 버퍼에 남은 스택 트레이스를 Claude Code 가 읽고, 프로젝트의 네이티브 코드에서 해당 지점을 찾아가는 흐름이 꽤 쓸 만하다. 반복 확인 자동화 화면을 고치고 결과를 확인하는 사이클도 맡길 수 있다. 코드를 수정하고, Fast Refresh 가 반영될 시간을 두고, 스크린샷을 찍어서 의도대로 바뀌었는지 확인하는 과정을 Claude Code 가 혼자 돌린다. 여러 기기를 붙여두면 adb -s <serial> 로 기기별로 같은 확인을 반복해 화면 크기별 차이도 비교할 수 있다. 권한 설정 Claude Code 는 Bash 명령을 실행하기 전에 매번 허락을 구한다. adb 명령을 자주 쓴다면 프로젝트의 .claude/settings.json 에 허용 목록을 넣어두는 편이 편하다. { "permissions": { "allow": [ "Bash(adb devices)", "Bash(adb logcat:*)", "Bash(adb shell getprop:*)", "Bash(adb exec-out screencap:*)" ] } } Bash(adb:*) 처럼 통째로 열어두는 건 권하지 않는다. adb uninstall 이나 adb shell pm clear 처럼 앱 데이터를 날리는 명령도 함께 허용되기 때문이다. 읽기 위주 명령만 열어두고, 상태를 바꾸는 명령은 확인을 거치게 두는 게 안전하다. 프로젝트에서 자주 쓰는 패키지명이나 로그 태그는 CLAUDE.md 에 적어두면 Claude Code 가 매번 추측하지 않고 바로 쓴다. iOS 의 경우 iOS 도 원리는 같다. 다만 층을 구성하는 도구가 다르다. usbmuxd — macOS 에 상주하는 데몬으로, USB 위에 여러 TCP 연결을 다중화한다. adb server 와 비슷한 위치다 페어링 — 폰 화면의 "이 컴퓨터를 신뢰하겠습니까?" 가 RSA 키 인증에 해당한다. 수락하면 페어링 레코드가 맥에 저장된다 명령 도구 — Xcode 15 이후로는 xcrun devicectl 이 기본이다. xcrun devicectl list devices 로 연결된 기기를, xcrun devicectl device info details --device <id> 로 상세 정보를 읽는다 실무에서 체감되는 차이는 로그다. Android 의 logcat 만큼 터미널에서 편하게 스트리밍할 수 있는 공식 도구가 마땅치 않아서, libimobiledevice 의 idevicesyslog 같은 서드파티 도구를 쓰거나 Xcode 콘솔에 의존하게 된다. 그래서 Claude Code 와 실기기를 함께 쓰는 흐름은 아직 Android 쪽이 훨씬 매끄럽다. 시뮬레이터라면 xcrun simctl 로 스크린샷과 로그를 다룰 수 있어서 사정이 낫다. 주의사항 USB 디버깅은 강한 권한이다. adb 로 연결된 상태에서는 앱 설치와 삭제, 앱 데이터 접근, 화면 입력 조작까지 가능하다. 개인 폰을 테스트 기기로 쓴다면 작업이 끝난 뒤 디버깅을 꺼두는 습관이 좋다. 여러 기기가 붙어 있으면 대상을 명시해야 한다. 기기가 둘 이상이면 adb shell 은 "more than one device" 에러를 낸다. Claude Code 는 보통 이 에러를 보고 -s 옵션을 붙여 다시 시도하지만, 어떤 기기를 대상으로 할지는 처음부터 알려주는 편이 낫다. 에뮬레이터가 켜져 있는 걸 잊고 있다가 엉뚱한 기기의 로그를 보는 일이 생각보다 흔하다. 무선 디버깅도 같은 구조다. Android 11 이상은 adb pair 로 Wi-Fi 연결을 맺을 수 있다. 이 경우 USB 층이 TCP 로 바뀔 뿐 adb server 위쪽은 그대로라서 Claude Code 입장에서는 차이가 없다. 정리 케이블을 꽂으면 Claude Code 가 폰을 알아서 파악하는 것처럼 보이지만, 실제로는 여러 층이 각자의 일을 하고 있다. 데이터 선이 있는 케이블이 USB 연결을 만들고, USB 디버깅이 ADB 인터페이스를 열고, RSA 키 인증이 이 컴퓨터를 믿을 수 있는지 확인한다. adb server 가 그 위에서 기기를 관리하고, 폰의 adbd 가 명령을 실제로 실행한다. 여기까지는 Claude Code 와 무관하게 원래 존재하던 구조다. Claude Code 는 그 맨 위에서 터미널을 쓰는 사람의 자리를 대신한다. adb 의 사용법과 출력 형식을 알고 있는 모델이 Bash 도구로 명령을 실행하고, 결과를 읽고, 다음 명령을 고른다. "알아서" 의 정체는 이 판단의 연쇄다. 이렇게 보면 문제가 생겼을 때 어디를 봐야 하는지도 분명해진다. adb devices 가 기기를 못 찾으면 케이블이나 디버깅 설정 문제이고, unauthorized 면 인증 문제이고, adb 는 잘 되는데 Claude Code 가 엉뚱한 일을 하면 그건 대상 기기나 패키지명 같은 맥락을 더 알려줘야 하는 문제다.
What RADAR observed and classified to build this opportunity. It is what the source published, not a verification that the offer is still active.
USB-C 연결과 클로드코드의 디바이스 인식 원리. 개요 폰을 케이블로 데스크탑에 꽂아두고 Claude Code 에게 "앱이 왜 죽는지 봐줘" 라고 하면, 알아서 기기 모델과 OS 버전을 확인하고 로그를 뒤져서 크래시 원인을 찾아온다. 처음 보면 Claude Code 가 폰과 직접 통신하는 특별한 기능이 있는 것처럼 느껴진다. 실제로는 그런 기능이 없다. Claude Code 가 하는 일은 터미널에서 adb 나 xcrun devicectl 같은 명령을 실행하고 그 출력을 읽는 것뿐이다. 폰과 통신하는 일은 원래 있던 개발 도구들이 하고, Claude Code 는 그 도구를 사람 대신 두드린다. 이 글은 케이블을 꽂는 순간부터 Claude Code 가 폰의 값을 읽어내기까지 어떤 층이 쌓여 있는지를…
Open source