Cordova에서 Android/iOS 분기를 넣다 보면, iOS는 잘 되는데 Android에서만 Gradle 빌드가 터지거나(혹은 반대), 특정 환경(Release만, 특정 ABI만)에서만 실패하는 경우가 종종 생깁니다. 대개는 “분기 처리”를 위해 추가한 설정이 build.gradle에 누적되면서 충돌하는 패턴이에요.

플랫폼 분기와 빌드 설정 충돌을 상징하는 일러스트

아래는 빌드 로그 → 흔한 원인 → 해결 단계 순서로, Product Flavor/변수/플러그인 hook 때문에 꼬이는 상황을 빠르게 정리하는 가이드입니다.

1) 빌드 로그에서 ‘분기 관련’ 신호 먼저 찾기

먼저 실패 지점을 “플러그인 설치/적용 단계”인지, “Gradle 설정 파싱 단계”인지, “컴파일/패키징 단계”인지 나눠보면 원인 범위가 확 줄어듭니다.

  • Gradle 파싱/설정 단계: “Could not find method …”, “A problem occurred evaluating project …”, “Duplicate method …”
  • 의존성 해결 단계: “Could not resolve …”, “All com.android.support libraries must use the exact same version”, “Duplicate class …”
  • 빌드 변형(variant/flavor) 단계: “Task … not found”, “Variant … was not found”, “Cannot choose between the following variants …”

특히 분기(예: dev/prod, free/paid, China/Global)를 넣은 프로젝트는 로그에 flavor, variant, applicationIdSuffix, manifestPlaceholders, productFlavors 같은 단어가 자주 등장합니다. 이 키워드가 보이면 “설정 충돌” 가능성이 큽니다.

2) 흔한 원인 A: Product Flavor를 Cordova가 모르는 방식으로 추가함

Cordova-Android는 내부적으로 기본 빌드 태스크/variant 구성을 전제로 동작합니다. 여기에 productFlavors를 무리하게 넣으면, Cordova가 호출하는 태스크 이름과 실제 생성된 태스크가 어긋나서 실패하기도 합니다.

자주 보이는 로그 예

  • “Task 'assembleDebug' not found in project ':app'”
  • “Variant 'debug' was not found. Please specify a variant name.”

해결 단계

  • 우선 Android Studio/Gradle 기준으로 실제 생성되는 variant를 확인합니다. (예: devDebug, prodRelease)
  • Cordova CLI로 빌드할 때는, 가능하면 Cordova-Android가 지원하는 방식(빌드 타입/환경변수/gradleArg)으로 우회합니다.
  • 정말 flavor가 필요하다면, “Cordova가 호출하는 태스크”와 “생성되는 태스크”가 일치하도록 빌드 호출을 flavor에 맞춰 조정합니다. (프로젝트별로 다르니, 먼저 variant 목록을 확정하는 게 핵심입니다.)

포인트는 “flavor를 추가하는 것” 자체보다, Cordova 빌드 파이프라인이 어떤 variant를 기대하는지를 먼저 맞추는 겁니다.

3) 흔한 원인 B: build.gradle 변경이 누적(중복 삽입)되어 충돌

Cordova 플러그인과 hook은 build.gradle에 내용을 “추가 삽입”하는 방식이 많습니다. 분기 로직을 넣으려고 직접 편집까지 섞이면, 어느 순간 아래처럼 중복이 생깁니다.

중복된 Gradle 설정이 충돌하는 상황을 그린 그림

자주 보이는 로그 예

  • “Could not find method implementation() for arguments …” (gradle plugin 버전/DSL 불일치 포함)
  • “Cannot add task 'xxx' as a task with that name already exists.”
  • “Duplicate class … found in modules …” (의존성 중복으로 이어짐)

해결 단계(안전한 정리 순서)

  • platforms/android는 “생성물”로 보고, 우선 백업 후 재생성 가능한 상태인지 확인합니다.
  • 직접 수정한 build.gradle이 있다면, “왜 필요한지”를 메모로 남기고(또는 별도 패치 파일로 관리) 재현 가능한 형태로 옮깁니다.
  • 플러그인/Hook이 넣는 gradle 설정은 중복 삽입이 쉬우니, 동일 블록(productFlavors, repositories, dependencies, packagingOptions 등)이 두 번 들어가지 않는지 확인합니다.

특히 팀에서 “cordova platform rm/add android”를 자주 하는 프로젝트라면, 수동 편집은 결국 사라지기 쉬워서 더 위험합니다. 가능하면 config.xml/플러그인 변수/Hook 중 한 가지로만 관리 포인트를 정하는 편이 안정적이에요.

4) 흔한 원인 C: Android 전용 gradle 설정을 iOS에도 적용하려고 한 흔적

각 플랫폼 분기 안내를 하다 보면, “공통 스크립트에서 Android/iOS를 한 번에 처리”하려고 하다가 문제가 생깁니다. 예를 들어 Hook이 iOS 빌드에도 실행되는데 Android 전용 파일을 건드리거나, 반대로 Android 빌드에서 iOS 파일을 찾다가 실패하는 식이죠.

자주 보이는 로그 예

  • “File not found: platforms/android/app/build.gradle” (플랫폼 추가 전/경로 변경 시)
  • “Cannot read property … of undefined” (Hook에서 platform 분기 누락)

해결 단계

  • Hook 스크립트에서 platform === 'android' / platform === 'ios' 분기를 먼저 강제합니다.
  • 플랫폼 폴더 존재 여부를 체크하고, 없으면 조용히 종료(또는 명확한 메시지로 실패)하도록 합니다.
  • Android 전용 변경(build.gradle, AndroidManifest.xml, res/xml 등)과 iOS 전용 변경(Info.plist, entitlements 등)을 한 파일에서 섞지 말고, 최소한 함수/모듈로 분리해둡니다.

분기 자체는 간단하지만, “플랫폼 추가/삭제/재생성” 같은 Cordova의 워크플로우를 고려하지 않으면 로그가 애매해지고 재현이 어려워집니다.

5) 흔한 원인 D: manifestPlaceholders/applicationIdSuffix로 런타임 값이 꼬임

Android/iOS 분기 안내를 하다 보면, Android 쪽에서만 도메인/스킴/키 값을 바꾸기 위해 manifestPlaceholdersapplicationIdSuffix를 쓰는 경우가 있습니다. 이때 플러그인이 참조하는 값이 variant별로 달라져서 빌드/패키징 단계에서 실패할 수 있어요.

자주 보이는 로그 예

  • “Manifest merger failed …”
  • “Attribute … is also present …” (variant별 manifest가 충돌)
  • “INSTALL_FAILED_CONFLICTING_PROVIDER” (빌드는 되는데 설치 단계에서 충돌)

해결 단계

  • Manifest merge 로그를 끝까지 보고, 어떤 manifest(플러그인/메인/variant)가 충돌하는지 먼저 확정합니다.
  • provider/authority 같은 값은 applicationId에 의존하는 경우가 많아, suffix 적용 시 함께 바뀌도록 규칙을 통일합니다.
  • 플러그인 문서에 “manifestPlaceholders를 사용하라”는 가이드가 있다면, 그 키 이름을 variant마다 다르게 만들지 말고 한 키로 유지하는 편이 안전합니다.

6) 빠른 점검 체크리스트(로그 기반)

빌드 로그 기반 점검 체크리스트를 상징하는 일러스트

  • 로그에 variant/flavor가 보이면: 생성된 variant 이름과 Cordova가 호출하는 태스크가 맞는지 확인
  • “evaluating project”, “could not find method”면: build.gradle 파싱 단계 충돌(중복/버전/DSL)부터 의심
  • “duplicate class”면: dependency 중복(플러그인 간 동일 라이브러리) 가능성 → 의존성 정리/버전 통일
  • Hook 사용 시: platform 분기파일 존재 여부 체크가 있는지 확인
  • platforms/android 직접 수정했으면: 재생성 시 사라질 수 있는 변경인지, 재현 가능한 관리 방식인지 점검

마무리

Cordova에서 Android/iOS 분기 처리를 하다가 생기는 Gradle 문제는, 대부분 “설정이 늘어나는 과정에서 중복/불일치가 생긴 것”으로 귀결됩니다. 빌드 로그를 단계별로 나눠 보고(파싱/의존성/variant), flavor·hook·manifestPlaceholders처럼 분기와 맞닿은 지점부터 정리하면 빨리 안정화됩니다.

가능하면 변경 지점을 한 곳(config.xml 또는 플러그인 변수 또는 hook)으로 줄이고, platforms 폴더를 재생성해도 동일하게 재현되는 형태로 관리해두면 이후 유지보수가 훨씬 편해져요.