홈시리즈멘토링

© 2026 정기창. All rights reserved.

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

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

© 2026 정기창. All rights reserved.

콘텐츠: CC BY-NC-SA 4.0

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

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

정기창·2026년 7월 26일

이 글은 3부작 시리즈 "맥에서 Xcode 없이 안드로이드 앱 실기기 테스트하기"의 1부입니다.

  • 1부(이 글): 맥에서 Xcode 없이 안드로이드 개발환경 세팅하기 (Homebrew만으로)
  • 2부: Expo dev-client로 안드로이드 실기기에 앱 올리고 Metro 붙이기
  • 3부: adb로 안드로이드 실기기를 원격 조작하며 QA하기

iOS 앱은 Xcode 없이 빌드할 수 없습니다. 시뮬레이터도 코드 서명도 전부 Xcode 안에 묶여 있으니까요. 그래서 맥에서 모바일 개발환경을 세팅하려다 보면 으레 Xcode부터, 혹은 Android Studio부터 떠올리게 됩니다. 저도 그랬습니다.

그런데 안드로이드는 사정이 달랐습니다. Xcode는 물론이고 Android Studio조차 반드시 필요한 것은 아니었습니다. command-line tools만 있으면 빌드도, 에뮬레이터도, 실기기 배포도 전부 됩니다. 이 글은 그 사실을 확인하고서 React Native/Expo 안드로이드 환경을 Homebrew만으로 세팅한 기록입니다. 순탄하지만은 않았고, 특히 JDK에서 한 번 크게 막혔습니다. 막혔던 순서 그대로 적어 보겠습니다.

첫 번째 벽: JDK 25로는 Gradle이 빌드되지 않습니다

macOS에 Homebrew로 openjdk를 그냥 설치하면 최신 버전, 그러니까 지금은 JDK 25가 들어옵니다. 그런데 Gradle 8.14와 Android Gradle Plugin이 요구하는 것은 JDK 17입니다. 버전이 높다고 되는 게 아니라 정확히 17이어야 합니다. JDK 25로 빌드를 돌리면 Gradle이 그대로 실패합니다.

그래서 brew install openjdk@17로 17을 따로 설치했습니다. 여기서 두 번째 함정이 나옵니다. 이 formula는 keg-only입니다. keg-only란 Homebrew가 설치는 하되 시스템 경로에 자동으로 symlink를 걸지 않는 상태를 말합니다. 시스템 기본 JDK와 충돌할 수 있어 일부러 격리해 두는 것입니다. 그래서 설치만 하고 끝내면 java -version은 여전히 25를 가리킵니다.

해결은 JAVA_HOME을 명시적으로 지정하는 것입니다.

export JAVA_HOME="/opt/homebrew/opt/openjdk@17/libexec/openjdk.jdk/Contents/Home"

돌이켜 보면 이 한 줄을 찾는 데 가장 오래 걸렸습니다. "17을 깔았는데 왜 25로 빌드되지?"라는 질문의 답이 keg-only라는 Homebrew의 개념 안에 숨어 있었기 때문입니다. 이름을 알고 나면 당연한데, 모르면 한참을 헤매는 종류의 함정이라는 생각이 들었습니다.

Android command-line tools 설치

JDK가 자리를 잡으면 그다음은 안드로이드 SDK입니다. Android Studio 없이 cask로 설치할 수 있습니다.

brew install --cask android-commandlinetools

설치 경로는 /opt/homebrew/share/android-commandlinetools입니다. 이 경로를 ANDROID_HOME으로 잡고, 하위 도구들과 앞서 지정한 JDK를 PATH에 추가합니다. 아래 묶음을 ~/.zshrc에 넣어 두면 새 셸을 열 때마다 자동으로 적용됩니다.

export ANDROID_HOME="/opt/homebrew/share/android-commandlinetools"
export PATH="$ANDROID_HOME/cmdline-tools/latest/bin:$ANDROID_HOME/platform-tools:$ANDROID_HOME/emulator:$JAVA_HOME/bin:$PATH"

SDK 패키지와 라이선스 수락

sdkmanager로 필요한 패키지를 내려받습니다. React Native 0.81.5 기준으로 실제 설치한 조합은 다음과 같습니다.

sdkmanager "platform-tools" "emulator" \
  "platforms;android-36" "build-tools;36.0.0" \
  "ndk;27.1.12297006" "system-images;android-36;google_apis;arm64-v8a"

sdkmanager --licenses

마지막 --licenses를 빠뜨리면 빌드 도중 SDK 자동 다운로드가 라이선스 미동의로 막힙니다. 부끄럽지만 저는 처음에 이걸 건너뛰고 한 번 더 막혔습니다. 버전은 감으로 고른 것이 아니라 React Native 0.81.5가 요구하는 값을 그대로 따른 것입니다.

항목값
compileSdk / targetSdk36
buildTools36.0.0
minSdk24
NDK27.1.12297006
Gradle8.14.3

여기서 눈에 띄는 것이 NDK입니다. 순수 JS/TS 앱이라면 네이티브 컴파일러인 NDK가 필요 없을 것 같은데도 목록에 들어 있습니다. 이유는 Reanimated 4와 worklets가 CMake로 네이티브 코드를 컴파일하기 때문입니다. 이 의존성이 있는 이상 NDK 없이는 빌드가 성립하지 않습니다.

에뮬레이터는 실기기가 없을 때의 폴백

실기기로 테스트할 계획이라면 에뮬레이터는 건너뛰어도 됩니다. 다만 기기가 없을 때를 대비해 AVD도 하나 만들어 두었습니다.

avdmanager create avd -n myapp_api36 \
  -k "system-images;android-36;google_apis;arm64-v8a" -d pixel_7

창을 띄우지 않고 헤드리스로 부팅한 뒤, 부팅이 끝났는지 확인하는 방법은 이렇습니다.

emulator -avd myapp_api36 -no-window -no-audio -no-boot-anim -no-snapshot -gpu swiftshader_indirect &
adb wait-for-device && adb shell getprop sys.boot_completed

마지막 명령이 1을 돌려주면 부팅이 끝난 것입니다.

정리하며

여기까지 하면 Xcode도 Android Studio도 없이, Homebrew와 command-line tools만으로 안드로이드 앱을 빌드할 수 있는 환경이 갖춰집니다. 돌아보면 대부분의 시간은 새로운 것을 배우는 데가 아니라, JDK 버전과 keg-only처럼 이미 정해져 있는 제약을 확인하는 데 들어갔습니다. 그런 함정은 한 번 겪고 나면 다시는 걸리지 않으니, 이 글이 같은 자리에서 멈춘 분께 그 시간을 조금이나마 줄여 주면 좋겠습니다.

다음 2부에서는 이렇게 만든 환경 위에 Expo dev-client를 실기기에 올리고 Metro를 붙이는 과정을 다루겠습니다.

AndroidmacOSHomebrewReact NativeExpo개발환경JDK

관련 글

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

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

관련도 93%

PWA로 admin 페이지에 모바일 푸시 알림 붙이기

알림 하나 받자고 네이티브 앱을 만드는 건 오버킬이었습니다. 그래서 이미 쓰던 admin 웹앱에 PWA를 최소한으로 얹어 모바일 푸시 알림만 받기로 했습니다. iOS 설치형 제약과 푸시 전용 service worker, Slack fan-out까지 직접 부딪쳐 얻은 교훈을 담았습니다.

관련도 90%

Prettier + husky + lint-staged로 팀 코드 스타일 자동화하기

코드 스타일 논쟁을 없애고 git commit 시 자동으로 포매팅되는 환경을 구축한 경험. Prettier 설정부터 husky + lint-staged 연동, git-blame-ignore-revs까지 실제 적용 과정을 정리했습니다.

관련도 90%