Verwenden von Build Flavours - Strukturieren von Quellordnern und build.gradle korrekt


166

Bitte beachten Sie: Antwort nach Xaviers Antwort bearbeitet

Ich versuche, verschiedene Build Flavours für ein und dasselbe Anwendungsprojekt in Android Studio zu verwenden. Es scheint mir jedoch eine schreckliche Zeit zu sein, es so zu konfigurieren, dass es richtig funktioniert.

Schritte:

  1. Erstellen Sie ein neues Android Studio-Projekt mit dem Namen "Test".
  2. Öffnen Sie build.gradle * und fügen Sie die folgenden Zeilen hinzu:

    productFlavors {
    flavor1 {
        packageName 'com.android.studio.test.flavor1'
        }
    flavor2 {
        packageName 'com.android.studio.test.flavor2'
        }
    }
  3. Nach dem Neustart von Android Studio werden jetzt 4 Build-Varianten im Abschnitt Build-Varianten angezeigt. Das heißt, wir waren bisher erfolgreich bei der Einrichtung der Produktaromen. ** **.
  4. Erstellt einen neuen Quellordner für flavour1 ; Ich bin mir jedoch nicht sicher, ob ich es richtig mache. So habe ich es gemacht:

    • Beachten Sie, dass mein Paketname für dieses Projekt lautet: com.foo.test
    • Klicken Sie mit der rechten srcMaustaste auf den Ordner. Für Flavour1 habe ich die einzelnen Ordner im Explorer so erstellt, wie es die Struktur ist src/flavor1/java/com/foo/test/MainActivity.java.
    • Das Obige hat gut funktioniert, da der 'Java'-Ordner blau ist , was bedeutet, dass die IDE weiß, dass es sich um ein aktives Quellverzeichnis handelt. Außerdem wurde das Paket automatisch erstellt. Trotzdem wird eine Warnung für doppelte Klasse gefunden. Siehe Screenshot hier.
    • Für Flavour2 habe ich versucht, das Paket manuell zu erstellen, aber der Ordner 'src' für Flavour2 scheint nicht blau zu sein. Daher sind die Optionen beim Klicken mit der rechten Maustaste unterschiedlich, und 'Neues Paket' steht mir nicht zur Verfügung. Siehe Bild hier.
    • Beachten Sie, dass ich für flavour1 auch ein 'res'-Verzeichnis erstellt habe, das zwar blau wird, aber trotzdem nicht die Möglichkeit bietet, entweder eine Android-Ressourcendatei oder ein Andorid-Ressourcenverzeichnis zu erstellen, falls ich ein anderes verwenden möchte Resoruzen für verschiedene Geschmacksrichtungen.

Mache ich etwas falsch? Oder fehlt mir etwas? Lassen Sie mich wissen, wenn Sie weitere Informationen benötigen.

* Mein Projekt scheint zwei build.gradle-Dateien zu haben . Eine befindet sich im Stammverzeichnis des Projektordners (\ GradleTest) und ist leer. Der zweite befindet sich im Stammverzeichnis eines Unterordners von \ GradleTest, der auch als "GradleTest" (GradleTest-GradleTest) bezeichnet wird. Dieser Ordner hatte bereits Code beim Öffnen. Daher ist dies derjenige, den ich bearbeitet habe.

** Ich habe gradle Einstellungen und scheinbar Verwendung Auto-Import wurde bereits aktiviert. Trotzdem werden die Build-Varianten nicht automatisch aktualisiert , wenn Änderungen an der Datei build.gradle vorgenommen werden . Hinweis: Ich habe auch versucht, Build - Rebuild Project und / oder Build - Make Project ohne Verwendung zu verwenden. Ich muss das Projekt noch schließen und erneut öffnen, damit die Änderungen wirksam werden.


Beachten Sie, dass applicationIdjetzt die statt unterstützt wird packageName.
Hamzeh Soboh

Antworten:


220

Wenn Sie in den Studio-Einstellungen im Abschnitt Gradle angekommen sind, können Sie den automatischen Import für Ihr Projekt aktivieren (dies wird später standardmäßig aktiviert). Auf diese Weise kann Studio Ihr build.gradle bei jeder Bearbeitung erneut importieren.

Das Erstellen von Aromen bedeutet nicht, dass Sie benutzerdefinierten Code für sie verwenden, sodass wir keine Ordner erstellen. Sie müssen sie selbst erstellen.

Wenn Sie sich meinen IO-Vortrag ansehen , werden Sie sehen, wie wir Werte aus den Geschmacksrichtungen und dem Build-Typ zusammenmischen, um die Variante zu erstellen.

Für die Java-Quelle:

src/main/java
src/flavor1/java
src/debug/java

werden alle 3 verwendet, um eine einzelne Ausgabe zu erstellen. Dies bedeutet, dass sie nicht dieselbe Klasse definieren können.

Wenn Sie eine andere Version derselben Klasse in den beiden Geschmacksrichtungen haben möchten, müssen Sie sie in beiden Geschmacksrichtungen erstellen.

src/flavor1/java/com/foo/A.java
src/flavor2/java/com/foo/A.java

Und dann kann Ihr Code in src / main / java

import com.foo.A

Je nach ausgewähltem Geschmack wird die richtige Version von com.foo.A verwendet.

Dies bedeutet auch, dass beide Versionen von A dieselbe API haben müssen (zumindest wenn es um die API geht, die von Klassen in src / main / java / ... verwendet wird.

Bearbeiten, um der überarbeiteten Frage zu entsprechen

Darüber hinaus ist es wichtig, dieselbe A-Klasse nur in Quellordnern abzulegen, die sich gegenseitig ausschließen. In diesem Fall werden src / Flavor1 / Java und Src / Flavour2 / Java niemals zusammen ausgewählt, sondern Main und Flavour1.

Wenn Sie eine andere Version einer Aktivität in einer anderen Variante bereitstellen möchten, fügen Sie sie nicht in src / main / java ein.

Beachten Sie, dass Sie, wenn Sie 3 Geschmacksrichtungen hatten und nur eine benutzerdefinierte für Flavour1 wollten, während Flavour2 und Flavour3 dieselbe Aktivität gemeinsam hatten, gemeinsame Quellordner für diese beiden anderen Aktivitäten erstellen könnten. Sie haben die volle Flexibilität, neue Quellordner zu erstellen und den Quellensatz für deren Verwendung zu konfigurieren.

Weiter zu Ihren anderen Punkten:

Es ist normal, dass der 2. Flavour-Quellordner nicht blau ist. Sie müssen zur zweiten Variante wechseln, um sie zu aktivieren, und dann können Sie darin Pakete und Klassen erstellen. Bis dahin betrachtet Studio es nicht als Quellordner. Wir werden dies hoffentlich in Zukunft verbessern, um die IDE auf diese nicht aktiven Quellordner aufmerksam zu machen .

Ich denke, es ist auch normal, dass Sie keine Ressourcendateien im Ordner res erstellen können. Das Menüsystem wurde nicht aktualisiert, um mit all diesen zusätzlichen Ressourcenordnern fertig zu werden. Dies wird später kommen.


1
Ich habe am Ende meiner Antwort einige neue Elemente hinzugefügt, aber das Duplikat ist sinnvoll. Sie können nicht dieselbe Klasse in src / main / java und src / flavour1 / java haben, da beide bei der Auswahl von flavour1 verwendet werden. Beachten Sie in meiner Antwort, dass ich dieselbe Klasse nur in Flavour1 / Java und Flavour2 / Java eingefügt habe, da diese exklusiv sind und niemals zusammen aktiviert werden.
Xavier Ducrohet

Hey Xavier, kannst du mir eine detailliertere Beschreibung geben, wie ich eine andere Version einer Aktivität in meinen Geschmacksrichtungen verwenden kann? Ich habe ein Testprojekt, in dem ich verschiedene Versionen meiner MainActivity verwenden möchte, aber in beiden Apks (Flavour1 und Flavour2) gibt es nur die Version von Main / Java. Wenn ich MainActivity nicht in main / java einbinde, stürzt die App ab, wenn ich sie starte.
JensJensen

@XavierDucrohet Wie wäre es mit unterschiedlichen Ressourcen sowie unterschiedlichem Code basierend auf Geschmacksrichtungen, aber mit unterschiedlichen Modulen, sodass wir das eine oder andere Modul basierend auf der Geschmacksrichtung einschließen können, ohne Code und Ressourcen im selben Stammprojekt mischen zu müssen? Wird das unterstützt?
Valerio Santinelli

3
@ValerioSantinelli Sie können Abhängigkeiten pro Geschmack erstellen. Verwenden SieflavorCompile ...
Xavier Ducrohet

@XavierDucrohet Ich habe versucht, was Sie vorgeschlagen haben, aber es funktioniert nicht wie erwartet. Sie können sehen, wie mein Projekt dort strukturiert ist: stackoverflow.com/q/24410995/443136
Valerio Santinelli

19

"Product Flavours" auf Android

Ich wurde manchmal gefragt, wie man mit verschiedenen Hosts, Symbolen oder sogar Paketnamen arbeitet, abhängig von verschiedenen Versionen derselben App.

Es gibt viele Gründe dafür und einen einfachen Weg: Produktaromen.

Sie können in Ihrem build.gradle-Skript solche Dinge definieren, die ich zuvor beschrieben habe.

Produktaromen Ein Teil dieses Artikels befasst sich mit Produktaromen. Was sind sie also? In Bezug auf die Android-Dokumentation:

Eine Produktvariante definiert eine angepasste Version der vom Projekt erstellten Anwendung. Ein einzelnes Projekt kann verschiedene Varianten haben, die die generierte Anwendung ändern.

Wie können Sie sie definieren? Sie müssen auf Ihrem build.gradle schreiben, welche Geschmacksrichtungen Sie definieren möchten:

productFlavors {  
        ...
        devel {
            ...
        }

        prod {
            ...
        }
    }

Jetzt haben wir zwei verschiedene Varianten unserer App. Sie können dies auch in Android Studio auf der Registerkarte Build Variants überprüfen

Varianten erstellen

Mehrere Paketnamen

Was ist, wenn Sie eine App mit Entwicklungsstatus und eine App mit Produktionsstatus auf Ihrem Telefon installiert haben möchten? Wie Sie vielleicht wissen, können Sie nur eine App mit demselben Paketnamen installieren (wenn Sie versuchen, eine neue APK mit derselben zu installieren, die auf Ihrem Telefon installiert ist, wird versucht, sie zu aktualisieren).

Das einzige, was Sie tun müssen, ist, es für jede Ihrer Produktaromen zu definieren:

android {  
    productFlavors {
        devel {
            applicationId "zuul.com.android.devel"
        }
        prod {
            applicationId "zuul.com.android"
        }
    }
}

Senden von Anforderungen an mehrere Hosts je nach Version Wie zuvor müssen Sie einige Parameter in Ihr Konfigurationsfeld für die Produktvariante aufnehmen.

android {  
    productFlavors {
        devel {
            applicationId "zuul.com.android.devel"
            buildConfigField 'String', 'HOST', '"http://192.168.1.34:3000"'

        }

        prod {
            applicationId "zuul.com.android"
               buildConfigField 'String', 'HOST', '"http://api.zuul.com"'

        }
    }
}

Als Beispiel werden wir versuchen, Ihnen zu zeigen, wie Sie dies in Retrofit integrieren können, um eine Anfrage an den entsprechenden Server zu senden, ohne zu behandeln, auf welchen Server Sie zeigen, und basierend auf der Variante. In diesem Fall ist dies ein Auszug aus der Zuul Android App:

public class RetrofitModule {

    public ZuulService getRestAdapter() {
        RestAdapter restAdapter = new RestAdapter.Builder()
                .setEndpoint(BuildConfig.HOST)
                .setLogLevel(RestAdapter.LogLevel.FULL)
                .build();
        return restAdapter.create(ZuulService.class);
    }

}

Wie Sie sehen, müssen Sie nur die BuildConfig-Klasse verwenden, um auf die soeben definierte Variable zuzugreifen.

Jede Variable, die über Ihren Code verfügbar ist Die HOST-Variable ist nicht die einzige, die Sie in Ihrem Code verfügbar machen können. Sie können es mit allem machen, was Sie wollen:

prod {  
    applicationId "zuul.com.android"
    buildConfigField 'String', 'HOST', '"http://api.zuul.com"'
    buildConfigField 'String', 'FLAVOR', '"prod"'
    buildConfigField "boolean", "REPORT_CRASHES", "true"
}

Sie können wie folgt darauf zugreifen:

BuildConfig.HOST  
BuildConfig.FLAVOR  
BuildConfig.REPORT_CRASHES  

Unterschiedliche Symbole pro Geschmacksrichtung Wenn Sie unterschiedliche Symbole pro Geschmacksrichtung haben möchten, damit Sie visuell erkennen können, welche Sie öffnen (Sie können dies auch unter dem Namen tun ... Aber es passt nicht in den Raum!), Haben Sie nur neue Verzeichnisstrukturen für jede der Varianten zu definieren.

In dem Beispiel, das ich gerade verwendet habe, gibt es zwei Geschmacksrichtungen: Entwickeln und Stoßen. Dann könnten wir zwei neue Verzeichnisstrukturen definieren, um die gewünschten Ressourcen zu definieren:

Struktur

Dies funktioniert mit anderen Arten von Ressourcen wie strings.xml, integers.xml, arrays.xmlusw.

Konfigurieren Sie die Signatureinstellungen

So konfigurieren Sie die Signaturkonfigurationen für Ihren Release-Build-Typ mithilfe von Gradle-Build-Konfigurationen manuell:

1.Erstellen Sie einen Keystore. Ein Schlüsselspeicher ist eine Binärdatei, die einen Satz privater Schlüssel enthält. Sie müssen Ihren Schlüsselspeicher an einem sicheren Ort aufbewahren. 2.Erstellen Sie einen privaten Schlüssel. Ein privater Schlüssel repräsentiert die Entität, die mit der App identifiziert werden soll, z. B. eine Person oder ein Unternehmen. 3. Fügen Sie die Signaturkonfiguration der Datei build.gradle auf Modulebene hinzu:

android {
...
defaultConfig {...}
signingConfigs {
    release {
        storeFile file("myreleasekey.keystore")
        storePassword "password"
        keyAlias "MyReleaseKey"
        keyPassword "password"
    }
}
buildTypes {
    release {
        ...
        signingConfig signingConfigs.release
    }
}

}}

Generieren Sie eine signierte APK:

Um eine signierte APK zu generieren, wählen Sie im Hauptmenü Erstellen> Signierte APK generieren. Das Paket in app / build / apk / app-release.apk ist jetzt mit Ihrem Release-Schlüssel signiert.

Ref: https://developer.android.com/studio/build/build-variants.html#signing,http://blog.brainattica.com/how-to-work-with-flavours-on-android/



7

Es scheint, dass Sie Ihr Projekt neu laden müssen, nachdem Sie neue Geschmacksrichtungen hinzugefügt haben build.gradle. Danach sehen Sie 4 Build-Varianten in der Ansicht Build-Varianten (Sie greifen vom linken Rand des Fensters darauf zu).

In Bezug auf die zusätzlichen Quellverzeichnisse müssen Sie diese anscheinend von Hand erstellen: src/flavor1/javaund src/flavor2/java. Sie werden sehen, dass durch Ändern der Version in der Ansicht "Build Variants" die derzeit aktiven Quellverzeichnisse geändert werden (das Verzeichnis ist blau, wenn es sich um ein aktives Quellverzeichnis handelt ).

Schließlich „wird gradle neue sourceSets schaffen für die neue Aromen“ bedeutet , dass gradle die Objekte schaffen android.sourceSets.flavor1und android.sourceSets.flavor2und Sie können sie in Ihrem build.gradle Skript verwenden. Aber diese Objekte werden dynamisch erstellt, deshalb sehen Sie sie nicht in der build.gradle(ich schlage vor, Sie lesen dies: http://www.gradle.org/docs/current/userguide/tutorial_using_tasks.html Besonders die 6.6: es erklärt die Erstellung einer dynamischen Aufgabe. Ein Gradle-Skript ist ein grooviges Skript. Ich empfehle Ihnen daher, sich auch mit groovig vertraut zu machen.


2
Ich denke, die Importnotiz ist die Build VariantsAnsicht, das habe ich nicht bemerkt.
Chris.Jenkins

2

Ich hatte das gleiche Problem, als ich mein Projekt nach Gradle migrierte. Das Problem war, dass der Build nicht den richtigen Ressourcenordner gefunden hat. Ich habe es behoben, indem ich dies unter dem Android-Element in build.gradle hinzugefügt habe:

sourceSets {
        main {
            res.srcDirs = ['myProject/res']
        }
    }

0

Etwas, das wichtig ist und mich für eine Weile blockiert hat, ist, dass der Geschmacksname, der mit der Packung übereinstimmen muss, im Gegensatz zu der Packung, die in der Geschmacksdefinition in Gradle definiert ist. Beispielsweise:

src/flavor1/java/com/foo/A.java

wird passen

productFlavors {
  flavor1 {
    packageName 'com.android.studio.test.foobar'
  }
}

aber

src/foobar/java/com/foo/A.java wird nicht für den Flavour1-Build verwendet.


0

In gradle:

Für Build-Typen benötigen Sie nur:

buildTypes {
   release{
    //proguard, signing etc.
   }
   debug {
    //development
   }
  }
}

Und dann fügen Sie für Aromen die hinzu, die Sie benötigen

productFlavors {
    pro {
        applicationIdSuffix '.paid'
        buildConfigField 'boolean', 'PRO', 'true'
    }
    free {
        applicationIdSuffix '.free'
        buildConfigField 'boolean', 'PRO', 'false'
    }
}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.