Cordova 프로젝트에서 Android(Gradle) 빌드가 실패하면, 플러그인 하나가 원인인 경우가 꽤 많습니다. 문제는 에러가 길고(특히 CI 로그), 플러그인/의존성/권한 중 어디부터 봐야 할지 막막하다는 점이죠. 이 글은 “빌드 실패 로그부터 원인 좁히기” 관점으로, 로그에서 단서를 뽑고 plugin.xml과 Gradle dependency, 권한 설정까지 체크리스트로 정리해 빠르게 수습하는 흐름을 담았습니다.

Magnifying glass untangling a knot symbolizing log debugging

먼저 “딱 한 줄”의 핵심 에러를 찾고, 그 줄이 가리키는 파일/플러그인으로 되돌아가는 방식으로 접근해보세요.

1) 로그에서 ‘진짜 에러 한 줄’ 뽑는 법(원인 좁히기 시작점)

Gradle 로그는 경고가 많아서, 마지막 줄만 보고 해결하려 하면 오히려 빙빙 돌기 쉽습니다. 아래 패턴을 기준으로 “원인 후보”를 추립니다.

  • Could not resolve / Could not find: 의존성(라이브러리) 버전/저장소 문제 가능성이 큼
  • Duplicate class: 같은 라이브러리가 다른 버전으로 2번 들어옴(플러그인 충돌 빈번)
  • Manifest merger failed: AndroidManifest.xml 충돌(권한/퍼미션/uses-sdk/Provider 등)
  • AAPT / resource / Android resource linking failed: res 충돌, minSdk/targetSdk 불일치, 라이브러리 리소스 충돌
  • Execution failed for task :app:compile...: 바로 위에 있는 “Caused by” 라인부터 읽는 게 핵심

팁은 간단합니다. 에러 메시지에서 문제가 난 모듈 이름(예: com.google.android.gms:play-services-xxx)이나 중복된 클래스 패키지, 또는 충돌 난 manifest 항목을 찾아 메모해두세요. 이 메모가 곧 “어떤 플러그인에서 이걸 가져왔는가”로 이어집니다.

2) 플러그인 목록·버전 고정부터 확인(재현 가능한 상태 만들기)

원인 좁히기 전에, 현재 설치된 플러그인과 버전을 고정(또는 최소한 기록)해두면 같은 삽질을 줄일 수 있습니다.

  • 플러그인 목록 확인: cordova plugin list
  • 플랫폼 버전 확인: cordova platform list
  • package.json에 cordova.plugins, dependencies에 버전이 명시되어 있는지 확인

여기서 중요한 포인트는 “플러그인 버전이 떠다니는 상태”를 피하는 겁니다. 어떤 플러그인은 의존성 업데이트에 민감해서, 어제 되던 빌드가 오늘 갑자기 깨지는 패턴이 나옵니다(특히 Google 계열 라이브러리).

Interlocking puzzle pieces showing a mismatched plugin dependency

3) plugin.xml에서 dependency/Gradle 변수 찾기(충돌 지점이 자주 숨어있음)

로그에서 “Could not resolve”나 “Duplicate class”가 보이면, 대부분은 특정 플러그인이 어떤 Android dependency를 끌고 왔는지가 관건입니다. 이때 플러그인의 plugin.xml을 열어 아래 항목을 확인합니다.

  • <framework src="..." / <framework custom="true" type="gradleReference">: Gradle에 추가되는 라이브러리/참조
  • google play services / firebase 계열 버전 지정 유무
  • cordova-android 버전에 따라 작동 방식이 바뀌는 설정(예: AndroidX 전환 관련)
  • 변수(예: PLAY_SERVICES_VERSION 등)로 버전을 주입하는 플러그인인지

여기서의 실전 요령은 “중복 클래스”가 찍힌 패키지를 보고, 그 패키지가 포함될 만한 라이브러리를 떠올린 뒤 해당 플러그인의 plugin.xml에서 framework 선언을 찾는 겁니다. 플러그인 두 개가 같은 계열 라이브러리를 서로 다른 버전으로 끌고 오면, 거의 항상 Duplicate class로 터집니다.

4) 권한/Manifest 충돌은 ‘Manifest merger failed’ 기준으로 역추적

권한 문제는 런타임 크래시로만 나타나는 게 아니라, 빌드 단계에서 Manifest merger failed로 바로 실패하는 경우가 있습니다. 특히 다음 케이스에서 자주 나옵니다.

  • 같은 permission/feature가 서로 다른 조건으로 중복 선언됨
  • provider(authorities) 값 충돌(다른 플러그인이 동일 authority 사용)
  • uses-sdk(minSdk/targetSdk) 충돌

로그에는 보통 “어떤 manifest 줄에서 충돌했는지”, “어느 라이브러리 manifest가 원인인지”가 함께 찍힙니다. 그 라이브러리를 가져온 플러그인을 찾아, config.xml의 설정(preference, edit-config)이나 플러그인 버전을 조정하는 방식으로 해결 방향을 잡습니다.

Shield and layered papers symbolizing manifest permission conflicts

5) 플러그인/권한 체크리스트(빌드 실패 로그 기준)

아래 체크리스트를 위에서 아래로 순서대로 훑으면, “로그 → 원인 플러그인” 연결이 훨씬 빨라집니다.

  • 에러 유형 분류: Could not resolve / Duplicate class / Manifest merger / AAPT 중 무엇인가
  • 핵심 키워드 메모: 라이브러리 좌표(group:name:version), 중복 클래스 패키지, 충돌 난 manifest 항목
  • 플러그인 목록 고정: cordova plugin list 결과를 저장하고, package.json에 버전이 고정돼 있는지 확인
  • plugin.xml 확인: <framework> 선언으로 어떤 dependency를 추가하는지 찾기
  • 버전 충돌 후보 정리: 같은 계열(google/fasterxml/okhttp 등)이 여러 플러그인에서 들어오는지 확인
  • AndroidManifest 충돌 지점 확인: provider/permission/uses-sdk 관련 로그가 가리키는 쪽부터 역추적
  • 최근 변경점부터 되돌리기: 마지막에 추가/업데이트한 플러그인부터 임시 제거 후 빌드로 범위 좁히기

체크리스트를 돌렸는데도 애매하면, “어느 플러그인을 제거하면 빌드가 통과하는가”로 최소 재현을 만든 뒤, 그 플러그인 하나만 놓고 의존성/manifest를 집중 분석하는 편이 빠릅니다.

6) 흔한 원인별 빠른 대응(안전한 범위에서)

여기서는 특정 프로젝트에 종속되지 않는 범위에서, 로그 패턴별로 자주 먹히는 대응만 정리합니다.

  • Could not resolve: 해당 dependency를 끌고 오는 플러그인을 찾고, 플러그인 버전을 올리거나(또는 내리거나) 한쪽으로 통일되도록 조정
  • Duplicate class: 중복되는 라이브러리 계열을 찾고, 같은 버전으로 맞추거나 둘 중 하나 플러그인의 의존성 주입 방식을 변경(가능하면 플러그인 업데이트로 해결)
  • Manifest merger failed: 충돌 항목(provider authorities, permission 등)을 로그로 특정한 뒤, 충돌을 만든 플러그인 설정을 조정하거나 플러그인 조합을 재검토
  • resource linking failed: minSdk/targetSdk/AndroidX 전환 여부 같은 “프로젝트 전역 조건”과 플러그인 요구조건이 맞는지 확인

핵심은 “로그에 찍힌 대상(라이브러리/manifest/클래스)”을 플러그인 단위로 연결하는 것입니다. 플러그인을 감으로 만지기 시작하면, 해결은 됐는데 왜 됐는지 모르는 상태가 남아서 다음 업데이트 때 또 터집니다.

마무리

Gradle 빌드 실패는 대부분 ‘긴 로그’ 때문에 어려워 보이지만, 실제로는 에러 한 줄 → 해당 dependency/manifest → 그걸 넣은 플러그인으로 이어지는 추적 게임에 가깝습니다.

이번 체크리스트 흐름대로 접근해서 원인 플러그인을 좁힌 다음, 버전 통일과 manifest 충돌 제거까지 정리해두면 다음 빌드 실패 때도 훨씬 빨리 복구할 수 있습니다.