macOS에서 APK를 빌드하고 설치하기 — 서명·ADB·실기기 검증

정기창·

APK를 만드는 일은 빌드 버튼을 누르는 것으로 끝나지 않았습니다. 서명한 파일을 만들고, 기기에 설치하고, 실제 화면이 그려졌는지 확인하는 단계가 각각 필요했습니다.

관리자 WebView 앱 연재의 마지막 편입니다. 앞에서 정한 구조와 보안 설정을 macOS에서 빌드하고 검증한 과정을 정리합니다. 명령 예시는 프로젝트에 적용한 도구 구성을 기준으로 하며, 최신 버전의 조합을 추천하는 목록은 아닙니다.

빌드 도구의 역할부터 나눴습니다

도구·설정이번 구성역할
JDK17Java 컴파일·Gradle 실행
Gradle Wrapper8.14.3프로젝트 빌드 버전 고정
Android Gradle Plugin8.11.0Android 빌드 작업 제공
compileSdk·targetSdk36컴파일 API·대상 동작 기준
minSdk26Android 8.0 이상 설치
Build Tools36.0.0패키징·서명 검증 도구

SDK 36으로 빌드한다고 Android 16 기기에서만 실행되는 것은 아닙니다. 설치 가능한 최소 버전은 minSdk로 따로 정했습니다. 실제 설치 확인은 Android 9 기기에서 했고, 자동 계측 테스트는 API 36 에뮬레이터에서 실행했습니다. 두 환경에서 확인한 내용도 뒤에서 구분합니다.

Gradle은 저장소에 포함한 Wrapper로 실행합니다. 개발자마다 설치한 전역 Gradle 버전을 사용하는 대신, 프로젝트가 정한 버전을 내려받는 방식입니다. 배포 ZIP의 SHA-256도 Wrapper 설정에 넣어 확인하도록 했습니다.

debug와 release를 분리했습니다

debug 빌드는 패키지 이름에 .debug를 붙이고 로컬 관리자 주소를 사용합니다. release는 운영 HTTPS 주소를 사용합니다. 테스트 앱과 운영 앱을 기기에 함께 설치할 수 있으며, 로컬 테스트가 운영 관리자에서 데이터를 수정하는 실수도 줄일 수 있습니다.

debug APK
 ├─ 별도 applicationId suffix: .debug
 ├─ localhost 관리자 화면
 └─ localhost HTTP만 예외 허용

release APK
 ├─ 운영 applicationId
 ├─ 고정된 운영 HTTPS 주소
 ├─ release 서명
 └─ WebView 디버깅 비활성화

자동 테스트는 로컬 서버와 테스트용 데이터로 실행합니다. 운영 앱을 기기에 설치해 첫 화면을 확인하는 일과, 운영 데이터에 생성·수정 요청을 반복하는 테스트는 구분했습니다.

서명 키는 APK와 별도로 관리했습니다

APK 서명은 이 설치 파일을 어떤 키로 만들었는지 확인하는 장치입니다. 업데이트를 배포할 때도 앱 식별자와 서명 관계를 유지해야 합니다. 이번 직접 배포 방식에서는 같은 applicationId와 서명 키를 사용하고 versionCode를 올리는 절차를 정했습니다. 관련 원리는 Android 앱 서명 문서에서 확인할 수 있습니다.

서명 저장소와 비밀번호는 저장소에 넣지 않았습니다. 빌드 스크립트가 환경변수로 전달받도록 했고, 필요한 값이 없으면 즉시 중단합니다. 설치 파일만 다른 운영자에게 전달하며 서명 키를 함께 보내지 않습니다. 키를 잃어버리면 다음 버전을 같은 앱의 업데이트로 전달하는 일이 어려워지므로 별도 백업도 필요합니다.

스크립트는 도구 경로를 가리키는 JAVA_HOME·ANDROID_HOME과, 서명 저장소의 경로·저장소 비밀번호·키 비밀번호를 담은 환경변수를 요구합니다. 서명 관련 변수의 이름은 프로젝트마다 정하면 됩니다.

프로젝트의 빌드 스크립트는 단위 테스트, release lint, release 조립을 실행한 다음 apksigner로 결과를 검증합니다. 아래 명령의 경로와 환경변수는 각자의 환경에서 준비해야 합니다. 비밀번호를 코드 블록이나 셸 히스토리에 직접 적지 않는 편이 좋습니다.

cd admin-android

# JAVA_HOME, ANDROID_HOME과 서명 관련 환경변수를
# 안전한 로컬 설정에서 준비한 뒤 실행합니다.
./build-apk.sh

# 결과
ls app/build/outputs/apk/release/app-release.apk

서명 검증 성공은 파일 서명을 확인했다는 뜻입니다. 앱의 보안, 업무 기능, 공개 스토어 심사를 모두 통과했다는 뜻으로 넓혀 해석하지는 않았습니다.

충전되는 것과 ADB에 연결되는 것은 달랐습니다

USB를 꽂았을 때 충전 표시는 나왔지만, 처음에는 개발 도구에서 기기를 확인할 수 없었습니다. 전원 공급과 데이터 통신은 별개의 조건입니다. 데이터 통신을 지원하는 케이블·포트인지 확인하고, 개발자 옵션의 USB 디버깅과 휴대폰의 컴퓨터 인증 화면도 확인해야 합니다.

ADB는 개발 컴퓨터와 Android 기기를 연결하는 도구입니다. ADB 공식 문서를 기준으로 기기 목록과 연결 상태를 확인했습니다. unauthorized라면 휴대폰에서 컴퓨터의 디버깅 권한을 승인하는 절차가 남아 있고, device로 표시되어야 정상적인 개발 명령을 이어갈 수 있습니다.

adb devices -l
adb install -r app/build/outputs/apk/release/app-release.apk

기기가 여러 대라면 adb -s로 대상을 명시합니다. 휴대폰에 설치나 보안 확인 창이 뜨면 사용자가 내용을 보고 처리해야 합니다. 이번에도 설치 확인 화면을 거친 뒤 앱을 실행했습니다.

휴대폰의 localhost는 개발 컴퓨터가 아닙니다

로컬 관리자가 Mac의 127.0.0.1:5173에서 실행 중이어도, 휴대폰에서 같은 주소를 열면 휴대폰 자신을 찾습니다. 이 차이를 해결하기 위해 debug 앱을 검증할 때 adb reverse를 사용했습니다. 기기 쪽 포트로 들어오는 연결을 개발 컴퓨터의 포트로 전달하는 방식입니다.

# 로컬 관리자 서버를 먼저 실행합니다.
adb reverse tcp:5173 tcp:5173

cd admin-android
./gradlew testDebugUnitTest lintDebug assembleDebug assembleDebugAndroidTest
./gradlew connectedDebugAndroidTest

이 경로는 debug 앱의 로컬 검증에만 사용합니다. 운영 APK는 고정된 HTTPS 주소를 사용하므로 adb reverse가 필요하지 않습니다. USB 없이 사용하는 운영 앱과 개발용 터널을 혼동하지 않도록 했습니다.

페이지 로딩 완료와 화면 그리기 완료도 구분했습니다

처음 계측 테스트를 만들 때 단순히 Activity가 켜졌다는 사실만으로는 부족했습니다. React 앱은 문서 로딩이 끝난 뒤에 라우트와 내용을 그릴 수 있습니다. 오류 화면이나 빈 화면이 떠 있어도 앱 프로세스는 정상적으로 실행 중일 수 있습니다.

그래서 테스트에서는 현재 origin이 로컬 주소인지 확인하고, 로그인 화면처럼 실제 관리자 화면에만 있는 문구가 DOM에 나타날 때까지 기다렸습니다. 이후 postVisualStateCallback()으로 그 DOM 상태가 다음 WebView 프레임에 반영될 준비가 되었는지 확인하고 화면을 캡처했습니다. 테스트용 DOM 확인은 release 앱에 범용 네이티브 브리지를 추가하는 것과는 다른 작업입니다.

동시에 파일 접근 차단, 혼합 콘텐츠 차단, Safe Browsing, DOM Storage 같은 WebView 설정도 단언했습니다. 캡처를 열어 실제 화면도 확인했습니다. 성공 여부를 문자열 하나로만 판정하지 않기 위한 보완이었습니다.

확인한 범위와 남은 범위를 따로 적었습니다

검증확인 결과
URL 정책 단위 테스트4건 통과
debug·release lint오류 0, 경고 4
release 빌드·서명 검증통과
API 36 로컬 계측 테스트1건 통과·화면 캡처 확인
Android 9 실기기설치·실행·로그인 화면 확인
실기기 전체 업무 흐름별도 확인 필요

실제 휴대폰에서 로그인 이후 모든 메뉴, 키보드, 뒤로가기, 파일 선택·취소·업로드를 끝까지 검증한 상태는 아닙니다. 특정 구간에서 앱 오류 로그가 없었다는 사실도 전체 기능의 정상 동작을 대신하지 못합니다.

설치 파일은 APK 그대로 전달할 수 있고, 전달 수단에 따라 ZIP에 넣어 전달한 뒤 풀어서 설치할 수도 있습니다. 압축은 전달 형식만 바꾸며 Android의 설치 허용 절차나 서명을 우회하지 않습니다. 소수 운영자에게 전달하는 지금 단계에서는 같은 서명으로 업데이트할 수 있게 관리하는 일이 우선입니다.

이번 작업에서는 “빌드됐다”, “설치됐다”, “화면이 보인다”, “업무가 끝까지 된다”를 서로 다른 완료 조건으로 나누는 것이 도움이 됐습니다. 다음 버전도 이 구분을 유지하면서 실제 사용 중 필요한 기능부터 채워가려 합니다.

AndroidAPKADBmacOS테스트앱 서명