애플리케이션 프로젝트 C에서 사내 배포 aar 프로젝트 A를 사용하는데, 이 녀석은 다시 다른 사내 배포 aar 프로젝트 B 를 사용하는 중이다. 또한 C는 B를 직접 참고하고 있기도 하다.
C -> A(by aar) -> B(by aar)
-> B(by aar)
사내 배포 aar 을 쓰면 local aar 캐시 때문에 aar이 새로 배포될 때 마다 굉장히 짜증이 난다. 더군다나 두개의 aar이 맞물렸을 경우에 문제가 발생하면, 이게 A 의 캐시 때문인지, B의 캐시 때문인지 문제 파악 자체도 어렵기 때문에 짜증이 제곱이 된다.
문제 발견하기
적어도 문제를 빠르게 파악하기 위해 현재까지 최선의 방법이라고 생각하는 건 다음과 같다.
- 각 aar 의 BuildConfig 클래스 등에 반드시 build time 이나 build git hash 등을 남기다.
- 뭔가 꼬이는 상황이 발생하면, 로컬 gradle cache를 뒤져 해당 aar 혹은 jar 파일을 찾아낸다. 그 다음 java decompile 도구를 이용해 BuildConfig 클래스의 내용을 열어서 build time 혹은 git hash를 확인해서 언제 릴리즈된 빌드인지 확인한다.
이렇게하면 적어도 로컬 aar이 언제적 빌드인지 정확히 파악할 수 있다. 둘 중 한놈이라도 최신이 아니라면 그 녀석을 최신으로 내려받기 위한 조치를 취해서 최신 aar를 갖춘 후 문제를 해결해나가면 된다.
로컬 aar 캐시를 갱신하기
로컬 aar을 날리고 새로 받기 위해 할 수 있는 대응은 다음과 같다.
gradlew 커맨드 라인 대응
- gradlew 명령에 --refresh-dependencies 옵션을 붙인다. ex)
gradlew clean --refresh-dependencies
- build.gradle 에 아래 명령을 추가한 후 다시 빌드 : 보통 땐 주석처리할 것.
//aar 등 의존 라이브러리 갱신이 필요할 때에만 살짝 주석을 풀자 //configurations.all { // // Check for updates every build // resolutionStrategy.cacheChangingModulesFor 0, 'seconds' //}
- 그래도 안되면 ~/.gradle 쪽의 cache 디렉터리 몽땅 삭제
안드로이드 스튜디오 대응
- 로컬 캐시 aar 에 포함된 클래스 아무거나 찾아들어간다.
- 안드로이드 스튜디오의 project 윈도우를 보면 그 aar 의 local cache jar 파일이 보인다. jar 파일에 우클릭하고
Reveal in Finder
를 선택해 로컬 캐시 파일을 찾아낸 후 삭제한다. - 프로젝트의 .idea 폴더 밑의 libraries 디렉터리를 모두 삭제한다. 왠지 cache 디렉터리도 함께 삭제하니 더 잘 되는 것 같은 느낌적인 필링이 든다.
- gradle sync 를 한다.
aar 의존관계를 모듈 의존관계로 변경
두 aar 프로젝트를 직접 빌드할 수 있는 행복한 상황이라면, 프로젝트 C를 임시로 수정해서 골치아픈 캐시가 끼어드는 aar 의존관계를 모듈 의존관계로 고친 후 빌드를 하면 된다. settings.gradle을 수정하면 의존 모듈을 추가할 수 있다. 이 때 임시로 추가한 모듈의 프로젝트는 아마도 프로젝트 외부에 위치할 것이기 때문에 projectDir을 명시해야 한다.
애플리케이션 프로젝트 C의 settings.gradle
include ':기존_의존_모듈', ':임시_모듈_a' , ':임시_모듈_b'
project(':임시_모듈_a').projectDir = new File('모듈_a_프로젝트의_로컬_경로')
project(':임시_모듈_b').projectDir = new File('모듈_b_프로젝트의_로컬_경로')
애플리케이션 프로젝트 C의 build.gradle
// 기존 aar 의존 관계를 임시로 주석처리
// implementation("com.mycompany:lib_a:1.0.0-SNAPSHOT")
// 대신 모듈 의존 관계를 임시로 추가
implementation project(':임시_모듈_a')
// 모듈 b도 동일
// implementation("com.mycompany:lib_b:1.0.0-SNAPSHOT")
implementation project(':임시_모듈_b')
이렇게 하면 a, b를 모두 로컬 경로로 참조할 수 있다. 더 완벽하게 하려면 모듈 a에서도 모듈 b를 aar이 아닌 로컬 모듈로 참고하도록 모듈 a 의 settings.gradle와 build.gradle을 수정하면 된다. 하지만 굳이 그럴 필요까지 없는 경우, 즉 A->B 관계는 문제가 없고 C->B 관계만 문제가 발생한 경우엔, C->A->B 로 연결되는 의존관계만 임시로 끊어두면 굳이 모듈 A의 프로젝트를 건드리지 않아도 된다. 수정하기 귀찮으니깐. 이 경우의 문법이 좀 직관적이지 않은데, 다음 링크에서 힌트를 찾았다. 다음과 같이 하면 된다.
애플리케이션 프로젝트 C의 build.gradle
// 기존 aar 의존 관계를 임시로 주석처리 , A->B 의존 관계는 exclude
// implementation("com.mycompany:lib_a:1.0.0-SNAPSHOT") {
// exclude group: 'com.mycompany', module: 'lib_b'
//}
implementation(project(':임시_모듈_a')) {
exclude group: 'com.mycompany', module: 'lib_b'
}
이렇게 하면 모듈 A를 수정하지 않아도 A->(B aar) 의존관계가 끼어들어 빌드 상황이 꼬이는 문제를 막을 수 있다. 핵심은 project 의존관계에서 exclude를 하려면 project를 한번 더 괄호로 감싸줘야 한다는 것!