안드로이드 라이브러리 프로젝트의 리소스 충돌 해결하기
안드로이드 라이브러리 프로젝트는 리소스를 가질 수 있다. 만약 서로 다른 라이브러리가 동일한 이름의 리소스를 가질 경우, 안드로이드 빌드 도구는 하나의 리소스를 선택해야만 한다. 공식 문서 에선 이 부분을 다음과 같이 설명한다.
여러 AAR 라이브러리 간에 충돌이 발생한 경우 종속성 목록에 맨 처음(dependencies 블록의 윗부분)에 나와 있는 라이브러리의 리소스가 사용됩니다.
즉 A 라이브러리와 B 라이브러리가 모두 ic_user.png
를 가지고 있는데 A를 build.gradle
의존관계에 먼저 선언했다면, A 라이브러리의 ic_user.png
가 앱에 탑재된다. 이 과정에서 의도치 않았던 동작이 일어날 수 있으니 주의해야 한다.
그런데 이 문제가 간단하지 않다. 정말 build.gradle
에 선언된 순서대로 선택될까? 그렇지 않다.
libA 가 libB 에 의존하며 build.gradle을 다음과 같이 작성했다고 생각해보자.
implements libB
implements libA
분명히 B를 먼저 선언했으니 B의 리소스가 먼저 선택될 것 같지만, A의 리소스가 선택된다. 그 이유는 라이브러리의 종속성 순서 때문인 것으로 추정된다. 즉, build.gradle
파일에 명시한 순서가 아닌, 종속성 순서에 따라 결정된다고 추정된다. 명확히 문서에서 확인한 게 아니라 테스트 결과 확인한 것이라 정확한 지는 모르겠다.
종속성 순서 문서에 따르자면, libA 가 libB에 의존하므로 libA 가 더 우선순위가 높다. 즉, libB 의존을 먼저 명시했더라도 libA 의존이 먼저 나온다. 그래서 리소스도 libA 를 먼저 선택하는 것 같다. 확인하고 싶다면 gradlew app:androidDependencies
등의 명령을 수행하면 출력되는 종속성의 내용을 보면 된다.
참고로 앱 빌드 과정에서 생성되는 build/intermediates/blame/debug/single/debug.json
를 보면 각 리소스가 어떤 라이브러리로부터 선택되었는지 확인할 수 있다. 이 내용도 공식 문서에선 찾지 못했고, 테스트를 하던 과정에서 찾아냈다.
자, 그럼 libB
의 리소스를 쓰고싶다면 어떻게 해야 할까? 지금까지 찾아낸 유일한 방법은 다른 라이브러리의 libB에 대한 종속 관계를 제거해서, libB의 종속성 우선순위를 강제로 끌어올리는 방식이다. 즉 build.gradle
을 이렇게 작성하면 된다.
implements libB
implements libA {
exclude libB
}
위 경우는 libA 하나만 libB를 사용하고 있기에 아주 단순한데, 여러개의 라이브러리를 사용하며, 이 중 어느 라이브러리가 libB에 의존하는지도 잘 모르겠다면 어떻게 할까? 다음과 같은 configuration 코드를 작성하면 된다. 단 아래 코드는 너무 무식하니 적절한 필터링이 필요할 듯 하다.
configurations.all.each { config ->
config.allDependencies.all { dep ->
if (dep instanceof ModuleDependency) {
dep.exclude(["group": "라이브러리 그룹", module: "라이브러리 모듈 이름"])
}
}
}
참고로 해결책을 찾던 와중에 라이브러리 리소스 공개 여부를 제어하면 되지 않을까 싶어 찾아봤는데, 리소스 공개 여부는 개발 과정이나 빌드 단계의 검증에만 영향을 미칠 뿐, 리소스 병합엔 영향을 미치지 못하므로 해결책이 되지 못한다.
Congratulations @kingori2! You received a personal award!
You can view your badges on your Steem Board and compare to others on the Steem Ranking
Vote for @Steemitboard as a witness to get one more award and increased upvotes!