Cordova 프로젝트를 Windows에서 빌드/배포하다 보면, 디버그에서는 잘 되는데 릴리즈 서명 단계에서만 갑자기 막히는 경우가 많습니다. 대부분은 “서명 파일/alias/비밀번호”, “Google 서비스용 SHA-1”, “AndroidManifest/권한”, “플러그인별 설정” 같은 기본 요소들이 어딘가에서 어긋난 경우예요.
아래는 “서명/배포(릴리즈) 실수 방지”를 목표로, 플러그인/권한까지 포함해 출시 직전에 빠르게 훑을 수 있는 체크리스트 형태로 정리했습니다.
1) 릴리즈 서명에서 자주 보는 에러 메시지와 의미
먼저 로그에서 방향을 잡아두면 체크가 빨라집니다. Windows에서 Android 릴리즈 서명 중 흔한 메시지는 다음 패턴으로 나옵니다.
- Keystore was tampered with, or password was incorrect: keystore 비밀번호 또는 key(alias) 비밀번호 불일치
- Alias <...> does not exist: keystore 안에 해당 alias가 없음(오타/다른 파일)
- java.io.FileNotFoundException ... .jks: 경로 오류(상대경로, 공백, OneDrive 동기화 위치 등)
- Failed to read key ...: keystore 포맷/비밀번호/권한 문제(파일 잠김 포함)
- INSTALL_FAILED_UPDATE_INCOMPATIBLE: 기존 설치 앱과 서명이 달라 업데이트 불가(디버그→릴리즈 교체, 또는 다른 keystore)
- Execution failed for task :app:validateSigningRelease: 서명 설정이 누락됐거나 Gradle이 서명 정보를 못 읽는 상황
핵심은 “서명 파일/alias/비밀번호/경로” 4가지가 1세트로 맞아야 한다는 점입니다.
2) keystore 파일/alias/비밀번호: Windows에서 특히 실수하는 지점
Windows에서는 파일 경로와 잠금(동기화/백신) 이슈가 섞여서, 실제 원인과 로그가 다르게 보이기도 합니다. 아래 체크부터 하세요.
- keystore 위치: 프로젝트 폴더 내부(예: keys/)처럼 경로가 안정적인 곳 권장. OneDrive/네트워크 드라이브는 피하기
- 경로 표기: 공백이 있는 경로(예: C:\Users\...\My Keys\)는 설정에서 실수하기 쉬움
- alias 확인: “내가 기억하는 alias”가 아니라, 실제 keystore에 들어있는 alias가 맞는지 확인
- 비밀번호 2종: keystore password와 key password(=alias password)가 다를 수 있음
- 파일 잠김: 빌드 중 백신 검사/동기화가 파일을 잠가 읽기 실패가 나기도 함(특히 첫 빌드)
추가로, 팀 작업이라면 “keystore가 바뀌지 않게 관리”가 가장 중요합니다. 배포용 keystore를 잃어버리거나 바꾸면, 기존 앱 업데이트가 사실상 불가능해집니다.
3) build.json(또는 Gradle signingConfig)에서 흔한 오타/누락 점검
Cordova는 보통 build.json 또는 빌드 커맨드 옵션으로 서명 정보를 연결합니다. 아래 항목이 하나라도 어긋나면 릴리즈에서만 실패합니다.
- keystore: 파일 경로가 맞는지(상대경로면 기준 위치가 어디인지) 확인
- storePassword: keystore 비밀번호
- alias: 실제 alias 이름(대소문자 포함)
- password: 해당 alias(key)의 비밀번호
- keystoreType: JKS/PKCS12를 쓰는 경우 타입 불일치가 없는지 확인(환경에 따라 필요)
실무에서는 “build.json은 맞는데도 실패”하는 경우가 있는데, 이때는 플랫폼/플러그인 변경 후 Gradle 캐시가 꼬였거나, release 변형이 여러 개로 생긴 상태일 수 있습니다. 릴리즈 직전에는 불필요한 변형을 줄이고(빌드 타입/플레이버를 단순하게), 한 번 깨끗한 상태에서 빌드하는 습관이 도움이 됩니다.
4) SHA-1/서명키 불일치로 터지는 배포 후 기능 장애(푸시/로그인)
빌드는 성공했는데 배포 후에만 특정 기능(예: OAuth 로그인, 지도/푸시 등)이 실패하는 케이스가 있습니다. 이건 “앱 기능 자체”가 아니라 서명키(SHA-1/ SHA-256)가 바뀐 릴리즈에서 자주 발생합니다.
- 디버그 SHA-1로 등록해 둔 서비스 설정을 릴리즈 SHA-1로도 추가했는지 확인
- 스토어 배포용이라면 최종 서명 주체가 “내 keystore”인지, “스토어/플랫폼 서명(예: Play App Signing)”인지 구분
- 로그인/푸시가 릴리즈에서만 실패하면, 우선 “서명키 등록” 이슈를 1순위로 의심
즉, “서명 성공 = 기능 정상”이 아닙니다. 배포 전에는 릴리즈 keystore 기준 SHA-1을 사용하는 외부 연동이 있는지 꼭 훑어보세요.
5) 플러그인/권한 체크리스트: 릴리즈 전 최종 점검(형식 그대로 따라 하기)
플러그인이 늘어날수록 AndroidManifest/권한/서비스 선언이 복잡해지고, 릴리즈에서만 검출되는 충돌이 나옵니다. 아래는 “배포 직전”에 빠르게 점검하기 좋은 체크리스트입니다.
- AndroidManifest.xml 변경 주체 확인: config.xml의 preference/edit-config, 플러그인의 plugin.xml 중 어디에서 manifest를 건드리는지 파악
- 권한 과다/중복: 같은 권한이 여러 방식으로 들어가거나, 필요 없는 권한이 남아 있지 않은지 확인
- Android 12+ exported: activity/service/receiver에 exported 요구가 생긴 컴포넌트가 있는지(특히 intent-filter가 있는 경우) 점검
- FileProvider/authority 충돌: 파일 공유/카메라 계열 플러그인에서 authority가 겹치면 설치/실행에서 문제
- 푸시/백그라운드 서비스: 서비스 선언, receiver 선언, permission(예: POST_NOTIFICATIONS) 추가 여부 확인
- 딥링크/스킴: intent-filter가 릴리즈에서도 원하는 형태로 유지되는지(플러그인 설치/제거 후 변형되기 쉬움)
- 네트워크 보안: cleartext 허용 여부(HTTP 접근), networkSecurityConfig 사용 여부(릴리즈에서 차단되어 “접속만 실패”하는 형태가 나옴)
포인트는 “플러그인 하나가 권한을 추가하고, 다른 플러그인이 같은 영역을 덮어쓴다” 같은 충돌을 줄이는 것입니다. 릴리즈 직전에는 플러그인 버전/설정을 동결하고, 필요한 권한만 남기는 쪽이 안전합니다.
6) 배포 전/후 확인 루틴: 설치 실패와 업데이트 불가를 미리 차단
릴리즈 APK/AAB가 만들어졌다고 끝이 아닙니다. 설치/업데이트 단계에서 바로 이슈가 터지기도 합니다.
- 동일 패키지명에서 테스트 단말에 이전 버전이 설치돼 있다면, 서명이 같아야 업데이트 가능
- INSTALL_FAILED_UPDATE_INCOMPATIBLE가 나오면: 기존 앱 삭제 후 설치(테스트용) 또는 keystore를 “원래 배포용”으로 복구
- versionCode 증가: 스토어 업로드는 versionCode가 반드시 증가해야 함(같으면 업로드 거절)
- minSdk/targetSdk 변경: 플러그인 추가로 값이 바뀌면, 구형 단말에서 설치 자체가 안 될 수 있음
- 서명 검증: 최종 산출물이 기대한 서명으로 되어 있는지 확인(팀/CI 환경에서 특히 중요)
특히 Windows에서 로컬 빌드와 CI 빌드가 섞이면 “내 PC에서는 되는데 배포 산출물 서명이 다름” 같은 일이 생길 수 있습니다. 릴리즈 산출물은 항상 동일한 keystore로 서명되는 흐름인지(개인 PC/빌드 서버) 마지막에 한 번 더 확인하세요.
마무리
릴리즈 서명 이슈는 대부분 “한 줄 설정”이나 “한 번 바뀐 keystore” 같은 작은 실수에서 시작합니다. 그래서 배포 직전에는 build.json/keystore 세트와 플러그인 권한(Manifest)만이라도 체크리스트로 고정해두는 게 가장 효과적입니다.
위 항목을 훑고도 계속 실패한다면, 에러 메시지(전체 로그)와 함께 “현재 keystore/alias 사용 방식”을 먼저 정리해두면 원인 좁히기가 훨씬 빨라집니다.