Aplikacja o wielu smakach oparta na bibliotece wielu smaków w Android Gradle

102

Moja aplikacja ma kilka wersji dla kilku rynków z systemami rozliczeń w aplikacji.

Mam jedną bibliotekę, która udostępnia kod podstawowy dla wszystkich moich projektów. Postanowiłem więc dodać te systemy płatności do tej biblioteki jako smaki produktów.

Pytanie brzmi, czy biblioteka Androida może mieć smaki produktów?

Jeśli tak, w jaki sposób mogę uwzględnić różne smaki w poszczególnych smakach aplikacji?

Szukałem dużo i nie mogłem znaleźć nic na temat tego scenariusza. Jedyną bliską rzeczą, jaką znalazłem, było to w http://tools.android.com/tech-docs/new-build-system/user-guide :

dependencies {
    flavor1Compile project(path: ':lib1', configuration: 'flavor1Release')
    flavor2Compile project(path: ':lib1', configuration: 'flavor2Release')
}

Zmieniłem konfigurację na inne rzeczy, ale to nie zadziałało!

Używam Android Studio 0.8.2.

Ali
źródło
po wielu poszukiwaniach nie znalazłem sposobu na osiągnięcie tego, nawet zaktualizowałem wtyczkę Androida do najnowszej 3.4.2wersji i gradle do najnowszej 5.5.1, nadal nie udało się z czasem kompilacji, lub połączenie zasobów nie powiodło się w aapt, lub nie mogę znaleźć symbolu, który wewnątrz biblioteki moduł
VinceStyling

Odpowiedzi:

141

W końcu dowiedziałem się, jak to zrobić, wyjaśnię to tutaj innym, którzy mają ten sam problem:

Kluczową częścią jest ustawienie parametru PublishingNonDefault na wartość true w bibliotece build.gradle. Następnie należy zdefiniować zależności zgodnie z zaleceniami podręcznika użytkownika.

Cały projekt wyglądałby tak:

Biblioteka build.gradle:

apply plugin: 'com.android.library'

android {        
    ....
    publishNonDefault true
    productFlavors {
        market1 {}
        market2 {}
    }
}

projekt build.gradle:

apply plugin: 'com.android.application'

android {
    ....
    productFlavors {
        market1 {}
        market2 {}
    }
}

dependencies {
    ....
    market1Compile project(path: ':lib', configuration: 'market1Release')
    market2Compile project(path: ':lib', configuration: 'market2Release')
}

Teraz możesz wybrać smak aplikacji i panel Warianty kompilacji, a biblioteka zostanie odpowiednio wybrana, a cała kompilacja i uruchomienie zostaną wykonane w oparciu o wybrany smak.

Jeśli masz wiele modułów aplikacji opartych na bibliotece, Android Studio będzie narzekać na konflikt wyboru wariantu, jest ok, po prostu zignoruj.

wprowadź opis obrazu tutaj

Ali
źródło
Dziękuję za udostępnienie. Teraz mogę pozbyć się obejścia mojego defaultPublishConfig.
Delblanco
2
W systemie AS 1.1.0 powyższe rozwiązanie wydaje się nadal działać, jednak 1) wybór kompilacji do debugowania / wydania jest utracony i wydaje mi się, że nadal mam problemy z AIDL znalezionym w bibliotece, który bardzo często nie tworzy odpowiedniego kodu. Jakieś przemyślenia na ten temat?
3c71
1
@IgorGanapolsky buildTypes nie ma z tym nic wspólnego. Każdy smak ma wszystkie typy kompilacji (zwykle debugowania i wydania) i wszystkie działają z tym podejściem.
Ali
1
@ An-droid określa bibliotekę, która ma być używana dla smaku market1!
Ali
1
Dlaczego jest ustawiony na typ kompilacji „wydanie”? Czy podczas kompilacji z debugowaniem wybrano typ kompilacji „wydanie”?
WindRider
35

Jest jeden problem z odpowiedzią Ali . W naszych wariantach budowy tracimy jeden bardzo ważny wymiar. Jeśli chcemy mieć wszystkie opcje (w moim przykładzie poniżej 4 (2 x 2)), musimy po prostu dodać niestandardowe konfiguracje w głównym pliku build.gradle modułu , aby móc używać wszystkich typów multi-smaków multi-buildType w Build Variants. Musimy również ustawić parametr PublishingNonDefault na true w pliku build.gradle modułu biblioteki .

Przykładowe rozwiązanie:

Lib build.gradle

android {

    publishNonDefault true

    buildTypes {
        release {
        }
        debug {
        }
    }
    productFlavors {
        free {
        }
        paid {
        }
    }
}

Aplikacja build.gradle

android {

    buildTypes {
        debug {
        }
        release {
        }
    }
    productFlavors {
        free {
        }
        paid {
        }
    }
}

configurations {
    freeDebugCompile
    paidDebugCompile
    freeReleaseCompile
    paidReleaseCompile
}

dependencies {

    freeDebugCompile project(path: ':lib', configuration: 'freeDebug')
    paidDebugCompile project(path: ':lib', configuration: 'paidDebug')
    freeReleaseCompile project(path: ':lib', configuration: 'freeRelease')
    paidReleaseCompile project(path: ':lib', configuration: 'paidRelease')

}
AppiDevo
źródło
Po wykonaniu tych samych czynności w mojej aplikacji Error:java.lang.RuntimeException: Error: more than one library with package name, wystąpiło
Chetan Joshi
21

Aktualizacja dla wtyczki Android 3.0.0 i nowszych

Zgodnie z oficjalną dokumentacją systemu Android - Migracja konfiguracji zależności dla modułów lokalnych ,

Dzięki rozwiązywaniu zależności z uwzględnieniem wariantów nie musisz już używać konfiguracji specyficznych dla wariantów, takich jak freeDebugImplementation, dla lokalnych zależności modułów - wtyczka zajmie się tym za Ciebie

Zamiast tego powinieneś skonfigurować swoje zależności w następujący sposób:

dependencies {
    // This is the old method and no longer works for local
    // library modules:
    // debugImplementation project(path: ':library', configuration: 'debug')
    // releaseImplementation project(path: ':library', configuration: 'release')

    // Instead, simply use the following to take advantage of
    // variant-aware dependency resolution. You can learn more about
    // the 'implementation' configuration in the section about
    // new dependency configurations.
    implementation project(':library')

    // You can, however, keep using variant-specific configurations when
    // targeting external dependencies. The following line adds 'app-magic'
    // as a dependency to only the "debug" version of your module.

    debugImplementation 'com.example.android:app-magic:12.3'
}

Więc w odpowiedzi Ali, zmień się

dependencies {
    ....
    market1Compile project(path: ':lib', configuration: 'market1Release')
    market2Compile project(path: ':lib', configuration: 'market2Release')
}

do

implementation project(':lib')

Wtyczka automatycznie zajmie się konfiguracjami specyficznymi dla wariantu. Mam nadzieję, że pomoże to innym w uaktualnieniu wtyczki Android Studio do wersji 3.0.0 i nowszej.

Ostry4789
źródło
7

Moja wtyczka do Androida to 3.4.0 i uważam, że nie wymaga teraz konfiguracji.Wystarczy upewnić się, że plik flavourDimensions i productFlavors w aplikacji zawiera jeden produktFlavor o tym samym smakuDimensions and productFlavors w bibliotekach. Przykład:

W kompilacji mylibrary

apply plugin: 'com.android.library'

android {        
    ....
    flavorDimensions "mylibFlavor"

    productFlavors {
        market1
        market2
    }
}

build.gradle aplikacji:

apply plugin: 'com.android.application'

android {
    ....
    flavorDimensions "mylibFlavor", "appFlavor"
    productFlavors {
        market1 {
            dimension "mylibFlavor"
        }
        market2 {
            dimension "mylibFlavor"
        }
        common1 {
            dimension "appFlavor"
        }
        common2 {
            dimension "appFlavor"
        }
    }
}

dependencies {
    ....
    implementation project(path: ':mylibrary')
}

Po synchronizacji możesz przełączyć wszystkie opcje w oknie wariantów budowania: wprowadź opis obrazu tutaj

JiajiaGu
źródło
Ale co, jeśli nie chcę mieć tych samych smaków w moim głównym module aplikacji? Załóżmy, że mam wiele modułów aplikacji, które mają własne specyficzne smaki i jeden wspólny moduł, który ma własne smaki i chcę użyć w mojej aplikacji mojej biblioteki o określonym smaku. Jak byś to zrobił? Kopiowanie moich smaków lib do wszystkich aplikacji nie ma sensu.
Billda
@Billda Nie musisz kopiować wszystkiego, po prostu zachowaj ten sam productFlavor w aplikacji, dla mojej próbki mogę zachować market1 lub market2 w aplikacji build.gradle.
JiajiaGu
2

Aby uzyskać smaki działające w bibliotece AAR, musisz zdefiniować defaultPublishConfig w pliku build.gradle modułu Android Library.

Aby uzyskać więcej informacji, zobacz: Publikacja biblioteczna .

Publikacja biblioteczna

Domyślnie biblioteka publikuje tylko swój wariant wydania. Ten wariant będzie używany we wszystkich projektach odwołujących się do biblioteki, bez względu na to, który wariant samodzielnie utworzą. Jest to tymczasowe ograniczenie ze względu na ograniczenia Gradle, nad których usunięciem pracujemy. Możesz kontrolować, który wariant ma być publikowany:

android {defaultPublishConfig "debug"}

Należy zauważyć, że ta nazwa konfiguracji publikowania odwołuje się do pełnej nazwy wariantu. Wydanie i debugowanie mają zastosowanie tylko wtedy, gdy nie ma żadnych smaków. Gdybyś chciał zmienić domyślny opublikowany wariant podczas używania smaków, napisałbyś:

android {defaultPublishConfig "flavour1Debug"}

David Lev
źródło
1

W tej chwili nie jest to możliwe, chociaż jeśli dobrze pamiętam, to jest funkcja, którą chcą dodać. (Edycja 2: link , link2 )

Edycja: Na razie używam defaultPublishConfigopcji, aby zadeklarować, który wariant biblioteki zostanie opublikowany:

android {
    defaultPublishConfig fullRelease
    defaultPublishConfig demoRelease 
}
Delblanco
źródło
1
Tak więc za każdym razem, gdy mam zamiar kompilować aplikację, muszę to zmienić w pliku build.gradle biblioteki?
Ali
Cóż, tak ... za każdym razem, gdy chcesz skompilować aplikację z innym smakiem.
Delblanco,
Właściwie, kiedy definiuję smaki dla modułu biblioteki, odziedziczony pakiet R nie znajduje modułu aplikacji.
Ali
Czy zsynchronizowałeś pliki Gradle w AS?
Delblanco
@Delblanco Wydaje się, że jest to praca ręczna i bardzo krucha (programiści są leniwi i zapominają o zmodyfikowaniu plików build.gradle).
IgorGanapolsky
1

Wiem, że ten temat został zamknięty, ale tylko aktualizacja z gradle 3.0, zobacz to: https://developer.android.com/studio/build/gradle-plugin-3-0-0-migration.html#variant_aware i grep matchingFallbacksi missingDimensionStrategy. Teraz o wiele łatwiej jest zadeklarować zależności między różnymi rodzajami modułów.

... iw tym konkretnym przypadku z gradle3.0, ponieważ smaki mają tę samą nazwę, gradle mapowałoby je magicznie, nie jest wymagana żadna konfiguracja.

AlexG
źródło
Wydaje mi się, że te elementy generowane przez środowisko wykonawcze są pomijane. Jako przykład simonvt-> generowanie schematów nie działa już z nowym sposobem dla mnie. : - /
Stefan Sprenger
1

Napotkałem również problem z kompilacją modułów dla różnych opcji.

Co znalazłem:

Wygląda na to, że nie musimy dodawać publishNonDefault truedo build.gradlepliku lib , ponieważ Gradle 3.0.1 .

Po dekompilacji klasy BaseExtensionznalazłem to:

public void setPublishNonDefault(boolean publishNonDefault) {
   this.logger.warn("publishNonDefault is deprecated and has no effect anymore. All variants are now published.");
}

I zamiast:

dependencies {
...
   Compile project(path: ':lib', configuration: 'config1Debug')
}

Powinniśmy użyć:

dependencies {
...
   implementation project(':lib')
}

Jedyną ważną rzeczą jest dodanie configurations {...}części do pliku build.gradle.

Tak więc ostateczny wariant build.gradlepliku aplikacji to:

buildTypes {
   debug {
      ...
   }

   release {
      ...
   }
}

flavorDimensions "productType", "serverType"
productFlavors {
   Free {
      dimension "productType"
      ...
   }
   Paid {
      dimension "productType"
      ...
   }
   Test {
      dimension "serverType"
      ...
   }
   Prod {
      dimension "serverType"
      ...
   }
}

configurations {
   FreeTestDebug
   FreeTestRelease
   FreeProdDebug
   FreeProdRelease
   PaidTestDebug
   PaidTestRelease
   PaidProdDebug
   PaidProdRelease
}

dependencies {
   implementation fileTree(dir: 'libs', include: ['*.jar'])
   implementation project(':lib')
   ...
}

Możesz także użyć wariantów filtru, aby ograniczyć warianty kompilacji.

Ps nie zapomnij dołączyć modułów do settings.gradlepliku, takich jak:

include ':app'
include ':lib'
project(':lib').projectDir = new File('app/libs/lib')
Sergio
źródło
proszę pana, czy może pan wyjaśnić, w jaki sposób skrypt określi pogodę, aby włączyć bibliotekę do określonej konfiguracji, czy nie? mam na myśli przypadek, w którym potrzebuję trochę lib dla określonego smaku, ale nie muszę go używać do innego smaku
Jenya Kirmiza
Nie wpadłem w taką sytuację. Jednak samouczek Google developer.android.com/studio/build/dependencies zaleca dodanie przedrostka przed poleceniem „implementacja” w bloku „zależności {...}”. Tj. Zależności {paidImplementation project (': lib')}, lub dependencies {debugImplementation project (': lib')}, lub dowolne zależności kombinacji wielu wariantów {paidProdDebugImplementation project (': lib')}. Sprawdź to i prześlij nam swoją opinię :)
Sergio