Gradle dla Androida, AAR i uzależnienia warunkowe
Skrócona forma: Jakie są sposoby porządkowania kodu / POM dla AAR, tak że aplikacje używające tego AAR mają tylko zależności, których faktycznie potrzebują?
Długa forma:
Załóżmy, że mamy aplikację, która zależy od projektu biblioteki Android spakowanego jako AAR (L).
L zawiera mieszankę klas, a każda aplikacja (np. A) użyje tylko podzbioru tych klas. Na przykład:
L może zawieraćFragment
implementacje natywnych fragmentów interfejsu API poziomu 11, fragmentów przeniesionych z powrotem i fragmentów o smaku ActionBarSherlock
L może zawieraćActivity
wdrożenia do regularnych działań,FragmentActivity
, ActionBarActivity
oraz działania o smaku ActionBarSherlock
L może podnosić wydarzenia przezLocalBroadcastManager
, Square's Otto i EventBus Greenrobota
I tak dalej
Te przypadki mają dwie główne cechy wspólne, jak to widzę:
Aplikacje zazwyczaj dotyczą tylko niektórych klas. Na przykład aplikacja korzystająca z Otto nie dba o kod, który odwołuje się do EventBus Greenrobota, lub o aplikacji, która z niego korzystaActionBarActivity
nie przejmuje się ActionBarSherlock.
Jeśli AAR jest artefaktem w repozytorium, aplikacje nie będą się przejmować wszystkimi możliwymi zależnościami potrzebnymi do zbudowania AAR. Na przykład aplikacja korzystająca z natywnych fragmentów interfejsu API poziomu 11 nie będzie potrzebowaćsupport-v4
lubactionbarsherlock
, chociaż sam AAR potrzebuje ich do zbudowania rocznego sprawozdania z działalności
Jeśli mielibyśmy korzystać z JAR zamiast AAR i zarządzania zrzucaniem zależności, jest to dość proste. Budowanie JAR miałoby zależności czasu kompilacji (np.support-v4
). Jednak aplikacje korzystające z tego JAR mogą pominąć te zależności i dopóki aplikacje te nie używają klas, które naprawdę potrzebują tych zależności, życie jest dobre.
Mam jednak trudności z zobaczeniem, jak osiągnąć to samo z artefaktami AAR i Maven określonymi w abuild.gradle
plik. Jeśli L madependencies
blok odwołując się do zależności w górę, aplikacje z kolei pobierają te zależności w sposób przejściowy, gdy aplikacje zależą od L.
Jedynym rozwiązaniem, które jestem całkiem pewne, będzie podział L na kilka bibliotek. Na przykład, używając scenariusza fragmentu, możemy mieć:
L1, który zawiera implementację natywnej wersji fragmentów interfejsu API poziomu 11 oraz dowolny wspólny kod potrzebny do innych scenariuszy. Ta biblioteka nie miałaby żadnych zależności.
L2, który zawiera implementację, która korzysta z backportu fragmentów pakietu wsparcia Android. L2 miałby zależności na L1 i nasupport-v4
.
L3, który zawiera implementację wykorzystującą fragmenty o smaku Sherlocka. L3 miałby zależności od L1 iactionbarsherlock
.
Następnie aplikacja zdecyduje, czy zależeć będzie od L1, L2, czy L3, a zatem otrzyma tylko niezbędne zależności w górę (jeśli istnieją).
Moje pytanie brzmi: czy to najlepsze rozwiązanie? Czy jest jeszcze coś w świecie Gradle dla Androida, AAR i artefaktów w stylu Maven, które pozwalają aplikacjom polegać na pojedynczym L? Jestem zaniepokojony możliwymi kombinatorycznymi eksplozjami bibliotek, aby poradzić sobie ze zróżnicowaną mieszanką zależności zależnych. Martwię się również o dziwne aplikacjerobić potrzebują wielu wdrożeń i niezależnie od tego, czy potrafimy niezawodnie określić zależności dla tych aplikacji (np. aplikacja zależna zarówno od L1, jak i L2, ponieważ to, co autor tej aplikacji uważa za potrzebne aplikacji).
Wiem, że istnieją sposoby na aplikacjęblok wykluczać zależności (patrz odpowiedź Josepha Earla na składnię), więc aplikacja może zależeć od L, a następnie zablokowaćactionbarsherlock
zależność upstream, jeśli nie jest potrzebna. Chociaż mogłoby to zadziałać, w przypadkach, w których jestem autorem L, wolałbym zastosować podejście L1 / L2 / L3, ponieważ wydaje się to czystsze.
Jakieś inne sugestie?