Multi-Flavour-App basierend auf Multi-Flavour-Bibliothek in Android Gradle

102

Meine App bietet verschiedene Varianten für In-App-Abrechnungssysteme für verschiedene Märkte.

Ich habe eine einzige Bibliothek, die den Basiscode für alle meine Projekte gemeinsam nutzt. Deshalb habe ich beschlossen, diese Zahlungssysteme als Produktaromen in diese Bibliothek aufzunehmen.

Die Frage ist, kann Android-Bibliothek Produktaromen haben?

Wenn ja, wie kann ich verschiedene Geschmacksrichtungen in die jeweilige Geschmacksrichtung der App aufnehmen?

Ich habe viel gesucht und konnte nichts über dieses Szenario finden. Das einzige, was ich in der Nähe fand, war das in http://tools.android.com/tech-docs/new-build-system/user-guide :

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

Ich habe die Konfiguration auf verschiedene Dinge geändert, aber es hat nicht funktioniert!

Ich benutze Android Studio 0.8.2.

Ali
quelle
Nach vielen Suchanfragen habe ich keine Möglichkeit gefunden, dies zu erreichen. Selbst wenn ich das Android-Plugin auf die neueste 3.4.2Version aktualisiere und auf die neueste Version heruntergefahren habe, ist die Kompilierungszeit 5.5.1immer noch fehlgeschlagen, oder die Ressourcenverknüpfung ist in aapt fehlgeschlagen oder ich kann das Symbol in der Bibliothek nicht finden Modul
VinceStyling

Antworten:

141

Schließlich habe ich herausgefunden, wie das geht. Ich werde es hier anderen erklären, die vor dem gleichen Problem stehen:

Der Schlüssel besteht darin, PublishNonDefault in der Bibliothek build.gradle auf true zu setzen. Anschließend müssen Sie Abhängigkeiten definieren, wie im Benutzerhandbuch vorgeschlagen.

Das ganze Projekt würde so aussehen:

Bibliothek 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')
}

Jetzt können Sie die App-Variante und das Bedienfeld „Varianten erstellen“ auswählen. Die Bibliothek wird entsprechend ausgewählt, und alle Builds und Ausführungen werden basierend auf der ausgewählten Variante durchgeführt.

Wenn Sie mehrere App-Module haben, die auf der Bibliothek basieren, wird sich Android Studio über einen Konflikt bei der Variantenauswahl beschweren. Es ist in Ordnung, ignorieren Sie ihn einfach.

Geben Sie hier die Bildbeschreibung ein

Ali
quelle
Vielen Dank für die Freigabe. Jetzt kann ich meine defaultPublishConfig-Problemumgehung entfernen.
Delblanco
2
Unter AS 1.1.0 scheint die oben genannte Lösung immer noch zu funktionieren. 1) Die Auswahl an Debug- / Release-Builds geht jedoch verloren, und ich habe anscheinend weiterhin Probleme mit AIDL in der Bibliothek, die nicht sehr oft den entsprechenden Code erzeugen. Irgendwelche Gedanken dazu?
3c71
1
@IgorGanapolsky buildTypes hat damit nichts zu tun. Jede Variante hat alle Build-Typen (normalerweise Debugging und Release) und alle funktionieren mit diesem Ansatz.
Ali
1
@ An-Droide definiert die Bibliothek, die für den Geschmack von market1 verwendet werden soll!
Ali
1
Warum ist der Build-Typ "Release" eingestellt? Wird der Build-Typ "Release" während der Debug-Builds ausgewählt?
WindRider
35

Es gibt ein Problem mit Ali Antwort. Wir verlieren eine sehr wichtige Dimension in unseren Build-Varianten. Wenn wir alle Optionen haben möchten (in meinem Beispiel unter 4 (2 x 2)), müssen wir nur benutzerdefinierte Konfigurationen in der Datei build.gradle des Hauptmoduls hinzufügen , um alle Multi-Flavour-Multi-Build-Typen in verwenden zu können Build Variants. Wir müssen auch PublishNonDefault in der Datei build.gradle des Bibliotheksmoduls auf true setzen .

Beispiellösung:

Lib build.gradle

android {

    publishNonDefault true

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

App 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
quelle
Gleiche Material in Meine Anwendung Nach tun, Error:java.lang.RuntimeException: Error: more than one library with package name, occoured
Chetan Joshi
21

Update für Android Plugin 3.0.0 und höher

Laut der offiziellen Android-Dokumentation - Abhängigkeitskonfigurationen für lokale Module migrieren ,

Mit der variantenabhängigen Abhängigkeitsauflösung müssen Sie für lokale Modulabhängigkeiten keine variantenspezifischen Konfigurationen wie freeDebugImplementation mehr verwenden - das Plugin erledigt dies für Sie

Sie sollten Ihre Abhängigkeiten stattdessen wie folgt konfigurieren:

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'
}

Also in Alis Antwort ändern

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

zu

implementation project(':lib')

Und das Plugin kümmert sich automatisch um variantenspezifische Konfigurationen. Hoffe, es hilft anderen, Android Studio Plugin auf 3.0.0 und höher zu aktualisieren.

Harsh4789
quelle
7

Mein Android-Plugin ist 3.4.0, und ich finde, dass es jetzt keine Konfigurationen benötigt. Sie müssen lediglich sicherstellen, dass die FlavourDimensions und ProductFlavors in der Anwendung einen ProductFlavor mit denselben FlavourDimensions und ProductFlavors in Bibliotheken enthalten. Beispiel:

In mylibrary's build.gradle

apply plugin: 'com.android.library'

android {        
    ....
    flavorDimensions "mylibFlavor"

    productFlavors {
        market1
        market2
    }
}

build.gradle der Anwendung:

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')
}

Nach der Synchronisierung können Sie alle Optionen im Fenster "Varianten erstellen" wechseln: Geben Sie hier die Bildbeschreibung ein

JiajiaGu
quelle
Aber was ist, wenn ich nicht die gleichen Geschmacksrichtungen in meinem Haupt-App-Modul haben möchte? Angenommen, ich habe mehrere App-Module mit eigenen Geschmacksrichtungen und ein gemeinsames Modul mit eigenen Geschmacksrichtungen, und ich möchte meine Bibliothek mit bestimmten Geschmacksrichtungen in meiner App verwenden. Wie würdest du das machen? Es ist nicht sinnvoll, meine lib-Aromen in alle Apps zu kopieren.
Billda
@Billda Sie müssen nicht alle kopieren, sondern nur ein Produkt in der App behalten. Für mein Beispiel kann ich market1 oder market2 im build.gradle der Anwendung behalten.
JiajiaGu
2

Damit die Varianten in einer AAR-Bibliothek funktionieren, müssen Sie defaultPublishConfig in der Datei build.gradle Ihres Android Library-Moduls definieren.

Weitere Informationen finden Sie unter: Bibliothekspublikation .

Bibliothekspublikation

Standardmäßig veröffentlicht eine Bibliothek nur ihre Release-Variante. Diese Variante wird von allen Projekten verwendet, die auf die Bibliothek verweisen, unabhängig davon, welche Variante sie selbst erstellen. Dies ist eine vorübergehende Einschränkung aufgrund von Gradle-Einschränkungen, auf deren Beseitigung wir hinarbeiten. Sie können steuern, welche Variante veröffentlicht wird:

android {defaultPublishConfig "debug"}

Beachten Sie, dass dieser Veröffentlichungskonfigurationsname auf den vollständigen Variantennamen verweist. Release und Debug sind nur anwendbar, wenn keine Geschmacksrichtungen vorhanden sind. Wenn Sie die standardmäßig veröffentlichte Variante ändern möchten, während Sie Flavours verwenden, schreiben Sie:

android {defaultPublishConfig "flavour1Debug"}

David Lev
quelle
1

Im Moment ist es nicht möglich, obwohl, wenn ich mich richtig erinnere, es eine Funktion ist, die sie hinzufügen möchten. (Bearbeiten 2: Link , Link2 )

Bearbeiten: Im Moment benutze ich die defaultPublishConfigOption, um zu deklarieren, welche Bibliotheksvariante veröffentlicht wird:

android {
    defaultPublishConfig fullRelease
    defaultPublishConfig demoRelease 
}
Delblanco
quelle
1
Also muss ich dies jedes Mal, wenn ich die App kompiliere, in build.gradle der Bibliothek ändern?
Ali
Nun ja ... jedes Mal, wenn Sie die App mit einem anderen Geschmack kompilieren möchten.
Delblanco
Wenn ich Aromen für das Bibliotheksmodul definiere, wird das geerbte R-Paket im App-Modul nicht gefunden.
Ali
Haben Sie die Gradle-Dateien in AS synchronisiert?
Delblanco
@ Delblanco Dies scheint Handarbeit und sehr spröde zu sein (Entwickler sind faul und vergessen, ihre build.gradle-Dateien zu ändern).
IgorGanapolsky
1

Ich weiß, dass dieses Thema geschlossen wurde, aber nur ein Update mit Gradle 3.0, siehe dies: https://developer.android.com/studio/build/gradle-plugin-3-0-0-migration.html#variant_aware und grep matchingFallbacksund missingDimensionStrategy. Jetzt ist es viel einfacher, die Abhängigkeiten zwischen Modulvarianten zu deklarieren.

... und in diesem genauen Fall mit gradle3.0, da Aromen den gleichen Namen haben, würde gradle sie magisch abbilden, es ist keine Konfiguration erforderlich.

AlexG
quelle
Für mich scheint es, dass zur Laufzeit generiertes Material übersprungen wird. Als Beispiel funktioniert die Erzeugung von simonvt-> Schaltplänen für mich nicht mehr mit dem neuen Weg. : - /
Stefan Sprenger
1

Ich hatte auch ein Problem beim Kompilieren von Modulen für verschiedene Optionen.

Was ich gefunden habe:

Es sieht so aus, als müssten wir seit Gradle 3.0.1 nicht publishNonDefault truein die lib- build.gradleDatei einfügen .

Nach dem Dekompilieren fand eine Klasse BaseExtensionFolgendes:

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

Und statt:

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

Wir sollten ... benutzen:

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

Nur das Wichtigste ist, einen configurations {...}Teil zum hinzuzufügen build.gradle.

Die letzte Variante der App- build.gradleDatei lautet also:

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')
   ...
}

Sie können auch Filtervarianten verwenden , um Build-Varianten einzuschränken.

Ps vergessen Sie nicht, Module in die settings.gradleDatei aufzunehmen, wie:

include ':app'
include ':lib'
project(':lib').projectDir = new File('app/libs/lib')
Sergio
quelle
Sir, können Sie erklären, wie der Scrip das Wetter bestimmt, um die Bibliothek in eine bestimmte Konfiguration aufzunehmen, oder nicht? Ich meine, ich habe einen Fall, in dem ich etwas Lib für einen bestimmten Geschmack verwenden muss, aber ich muss es nicht für den anderen Geschmack verwenden
Jenya Kirmiza
Bin nicht in eine solche Situation geraten. In einem Google-Tutorial von developer.android.com/studio/build/dependencies wird jedoch empfohlen, vor dem Befehl "Implementierung" im Block "Abhängigkeiten {...}" ein Präfix hinzuzufügen. Dh Abhängigkeiten {paidImplementation-Projekt (': lib')} oder Abhängigkeiten {debugImplementation-Projekt (': lib')} oder beliebige Kombinationsabhängigkeiten mit mehreren Varianten {paidProdDebugImplementation-Projekt (': lib')}. Probieren Sie es aus und geben Sie uns ein Feedback :)
Sergio