Cheondi
개발 · Unity

Android AAR 빌드 의존성

Android SDK의 AAR 의존성 충돌을 빌드 단계와 클래스 경로로 좁혀 해결한 기록입니다.

  • #android
  • #aar
  • #gradle

외부 기능을 위해 AAR 파일 하나를 추가한 뒤 Android 빌드가 실패했다. Unity 콘솔의 마지막 줄에는 Gradle 작업 실패만 보여 처음에는 SDK 버전을 무작정 바꿔 봤다. 상세 로그를 올려 보니 같은 클래스가 두 라이브러리에 들어 있다는 메시지가 앞쪽에 있었다.

AAR은 파일 하나처럼 보이지만 내부 클래스와 리소스, 다른 라이브러리 의존성을 함께 가져올 수 있었다.

빌드 실패 단계의 구분

C# 컴파일, Android 프로젝트 생성, Gradle 의존성 해석, dex 병합 중 어디에서 실패했는지를 확인했다.

Duplicate class ... found in modules sdk-core-A and sdk-core-B

이 메시지는 코드 문법보다 의존성 그래프 문제라는 단서였다. 두 AAR의 포함 내용과 Gradle dependency 결과를 비교했다.

직접 의존성과 전이 의존성의 중복

Unity 플러그인 폴더에 넣은 공통 라이브러리를 새 SDK도 내부 의존성으로 가져오고 있었다. 어느 쪽 버전을 기준으로 할지 정하고 중복 파일을 제거하거나 Gradle exclude 규칙을 적용했다.

implementation('com.example:sample-sdk:1.2.3') {
    exclude group: 'com.example', module: 'shared-core'
}

실제 group과 module은 공급 SDK의 문서와 생성된 의존성 그래프로 확인해야 했다.

빌드 이후 런타임 검증

중복을 없앴다고 필요한 클래스까지 빠지면 앱 시작 후 ClassNotFound가 날 수 있었다. SDK 초기화, 대상 기능 호출, 앱 재실행을 실제 기기에서 확인했다. ProGuard나 코드 축소가 적용되는 빌드도 따로 봤다.

라이선스와 배포 범위 때문에 AAR 원본을 저장소에 넣어도 되는지도 확인했다. 바이너리를 직접 관리할지 패키지 저장소 버전을 고정할지 팀 규칙이 필요했다.

빌드 설정을 고친 뒤에는 깨끗한 환경에서도 같은 의존성을 받을 수 있는지 확인했다. 내 PC의 Gradle 캐시에만 남은 파일 덕분에 우연히 성공하면 다른 개발자나 배포 서버에서 다시 실패할 수 있었다.

코드 의존성으로서의 바이너리

처음에는 AAR을 플러그인 폴더에 넣으면 끝나는 자산처럼 생각했다. 실제로는 버전, 전이 의존성, 빌드 설정, 런타임 초기화까지 영향을 주는 코드였다.

이후 네이티브 SDK를 추가할 때는 파일 복사보다 의존성 그래프와 지원 버전을 먼저 본다. 빌드의 마지막 오류보다 처음 깨진 단계와 구체적인 클래스 충돌을 찾는 습관도 이때 생겼다.

기술 문서 기반의 책임 경계

이 문제를 고친 뒤 관련 공식 자료를 찾아 읽으면서, 당시 코드에서 우연히 맞았던 부분과 규칙으로 남겨야 할 부분을 나눠 봤다.

Android 문서에서 AAR은 class만 든 파일이 아니라 manifest, resource, consumer rules, native library까지 포함할 수 있는 라이브러리 묶음이다. 따라서 중복 class 오류를 한 파일의 문제로만 보면 전이 의존성과 resource merge 충돌을 놓치기 쉽다.

빌드 산출물의 출처를 확인하라는 SLSA 관점까지 더하면, 어떤 저장소와 버전에서 받은 AAR인지와 digest를 남겨야 다른 환경에서도 같은 문제를 재현할 수 있다.

다음에 Android AAR 빌드 의존성 같은 문제를 보면 아래 순서부터 확인하려고 한다.

  • 직접·전이 의존성 전체 그래프
  • 소스 커밋과 산출물 digest
  • 깨끗한 환경의 재현 빌드
  • release 축소·서명 설정 검증

중복 모듈을 제외한 뒤에는 빌드 성공뿐 아니라 초기화·기능 호출·축소 빌드까지 실제 기기에서 확인해야 한다.

공식 참고 자료