Uso di Build Flavors: strutturare correttamente le cartelle di origine e build.gradle


166

Nota: risposta modificata dopo la risposta di Xavier

Sto cercando di utilizzare diversi Build Flavours per uno stesso progetto applicativo in Android Studio. Tuttavia, mi sembra che abbia avuto un momento terribile configurandolo per funzionare in modo appropriato.

passi:

  1. Crea un nuovo progetto Android Studio, chiamato "Test".
  2. Apri build.gradle * e ha aggiunto le seguenti righe:

    productFlavors {
    flavor1 {
        packageName 'com.android.studio.test.flavor1'
        }
    flavor2 {
        packageName 'com.android.studio.test.flavor2'
        }
    }
  3. Dopo aver riavviato Android Studio, ora vedo 4 varianti di build nella sezione Build Variants. Ciò significa che finora siamo riusciti a creare i sapori del prodotto. **
  4. Creata una nuova cartella di origine per flavour1 ; tuttavia, non sono sicuro di farlo nel modo giusto. Ecco come l'ho fatto:

    • Tieni presente che il nome del mio pacchetto per questo progetto è: com.foo.test
    • Fare clic con il tasto destro sulla srccartella, per flavour1, ho effettivamente creato le singole cartelle in Explorer, in un modo che sia la struttura src/flavor1/java/com/foo/test/MainActivity.java.
    • Quanto sopra ha funzionato bene, poiché la cartella 'java' è in blu , il che significa che l'IDE sa che è una directory di origine attiva. Inoltre, il pacchetto è stato creato automaticamente. Nonostante ciò, ricevo un avviso per la presenza di una classe duplicata.Vedi screenshot qui.
    • Per flavour2, ho provato a creare il pacchetto manualmente, ma la cartella "src" per flavour2 non sembra essere in blu, e quindi le opzioni sono diverse quando si fa clic con il tasto destro del mouse e "Nuovo pacchetto" non è disponibile per me. Vedi l'immagine qui.
    • Nota che per flavour1 ho anche creato una directory 'res', che diventa blu, ma nonostante ciò, non offre la possibilità di creare un file di risorse Android o una directory di risorse Andorid, nel caso volessi usare diversi Risoruce per sapori diversi.

Sto facendo qualcosa di sbagliato? Oppure mi sfugge qualcosa? Fammi sapere se hai bisogno di maggiori informazioni.

* Il mio progetto sembra avere due file build.gradle. Uno situato nella radice della cartella del progetto (\ GradleTest), questo è vuoto. Il secondo si trova sulla radice di una sottocartella di \ GradleTest, anche etichettata 'GradleTest' (GradleTest-GradleTest), questa è quella che aveva già il codice all'apertura; quindi, quello è quello che ho modificato.

** Ho controllato le impostazioni dei gradi e apparentemente Usa l'importazione automatica era già abilitato. Nonostante ciò, apportare modifiche al file build.gradle non aggiorna automaticamente le varianti di build. Nota: ho anche provato a utilizzare Build - Rebuild Project e / o Build - Make Project, no-go. Devo ancora chiudere il progetto e riaprire per rendere effettive le modifiche.


Nota che applicationIdora è supportato anziché packageName.
Hamzeh Soboh

Risposte:


220

Se hai ottenuto le preferenze di Studio, nella sezione Gradle, puoi abilitare l'importazione automatica per il tuo progetto (lo abiliteremo di default in seguito). Ciò consentirà a Studio di reimportare build.gradle ogni volta che lo modifichi.

La creazione di sapori non significa che utilizzerai un codice personalizzato per loro, quindi non creiamo le cartelle. Devi crearli tu stesso.

Se guardi il mio discorso IO vedrai come mescoliamo insieme i valori degli aromi e costruiamo il tipo per creare la variante.

Per l'origine Java:

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

sono tutti e 3 utilizzati per creare un singolo output. Ciò significa che non possono definire la stessa classe.

Se vuoi avere una versione diversa della stessa classe nei due gusti dovrai crearla in entrambi i gusti.

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

E poi il tuo codice in src / main / java può fare

import com.foo.A

a seconda del sapore selezionato, viene utilizzata la versione corretta di com.foo.A.

Questo significa anche che entrambe le versioni di A devono avere la stessa API (almeno quando si tratta dell'API utilizzata dalle classi in src / main / java / ...

Modifica per abbinare la domanda rivista

Inoltre, è importante inserire la stessa classe A solo nelle cartelle di origine che si escludono a vicenda. In questo caso src / flavour1 / java e src / flavour2 / java non vengono mai selezionati insieme, ma lo sono main e flavour1.

Se si desidera fornire una versione diversa di un'attività con un sapore diverso, non inserirla in src / main / java.

Nota che se avevi 3 sapori e ne volevi uno personalizzato per flavour1, mentre flavour2 e flavour3 condividevano la stessa attività, potresti creare una cartella di origine comune per quelle altre due attività. Hai totale flessibilità nella creazione di nuove cartelle di origine e nella configurazione del set di fonti per usarle.

Su altri tuoi punti:

È normale che la cartella della sorgente del secondo sapore non sia blu. È necessario passare al 2 ° sapore per abilitarlo, quindi sarà possibile creare pacchetti e classi all'interno. Fino ad allora, Studio non lo considera una cartella di origine. Speriamo di migliorare questo in futuro per rendere l'IDE consapevole di quelle cartelle di origine non attive .

Penso che sia anche normale che non sia possibile creare file di risorse nella cartella res. Il sistema di menu non è stato aggiornato per gestire tutte queste cartelle di risorse extra. Questo verrà dopo.


1
Ho aggiunto alcuni nuovi elementi alla fine della mia risposta, ma il duplicato ha un senso. Non puoi avere la stessa classe sia in src / main / java che in src / flavour1 / java di entrambi sono usati quando selezioni flavour1. Nella mia risposta, nota come ho inserito la stessa classe solo in flavour1 / java e flavour2 / java in quanto questi sono esclusivi e mai abilitati insieme.
Xavier Ducrohet,

Ehi Xavier, puoi darmi una descrizione più dettagliata di come posso usare una versione diversa di un'attività nei miei gusti? Ho un progetto di test in cui desidero utilizzare diverse versioni di MainActivity, ma in entrambi gli apk (flavour1 e flavour2) esiste solo la versione di main / java. Quando non inserisco MainActivity in main / java, l'app si blocca all'avvio.
JensJensen,

@XavierDucrohet che ne dici di avere risorse diverse e codici diversi basati su sapori, ma li hai in moduli diversi in modo da poter includere un modulo o l'altro in base al sapore, senza dover mescolare codice e risorse nello stesso progetto radice? È supportato?
Valerio Santinelli,

3
@ValerioSantinelli Puoi fare dipendenze per sapore. UsaflavorCompile ...
Xavier Ducrohet il

@XavierDucrohet Ho provato quello che mi hai suggerito ma non funziona come mi aspettavo. Puoi vedere come è strutturato il mio progetto lì: stackoverflow.com/q/24410995/443136
Valerio Santinelli,

19

"Sapori del prodotto" su Android

A volte mi è stato chiesto come lavorare con host, icone o persino nomi di pacchetti diversi, a seconda delle diverse versioni della stessa app.

Ci sono molte ragioni per farlo e un modo semplice per andare: Sapori di prodotto.

Puoi definire sul tuo script build.gradle questo tipo di cose che ho descritto prima.

Aromi di prodotto Parte di questo articolo è scritta pensando agli aromi di prodotto, quindi quali sono? Per quanto riguarda la documentazione Android:

Un sapore del prodotto definisce una versione personalizzata dell'applicazione creata dal progetto. Un singolo progetto può avere diversi gusti che cambiano l'applicazione generata.

Come puoi definirli? Devi scrivere sul tuo build.gradle quali sapori vuoi definire:

productFlavors {  
        ...
        devel {
            ...
        }

        prod {
            ...
        }
    }

Ora avremo due diversi gusti della nostra app. Puoi controllarlo anche su Android Studio nella scheda Crea varianti

Crea varianti

Nomi di pacchetti multipli

Cosa succede se si desidera aver installato sul telefono un'app con stato di sviluppo e una per stato di produzione. Come forse saprai, puoi installare solo un'app con lo stesso nome di pacchetto (se provi a installare un nuovo APK con lo stesso di quello installato sul tuo telefono, proverà ad aggiornarlo).

L'unica cosa che devi fare è definirla su ciascuno dei tuoi gusti di prodotto:

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

Invia richieste a più host in base all'aroma Come prima, è necessario includere alcuni parametri nel campo di configurazione dell'aroma del prodotto.

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

        }
    }
}

Ad esempio, proveremo a mostrarti come puoi integrarlo con Retrofit per inviare una richiesta al server appropriato senza gestire il server che stai indicando e in base al sapore. In questo caso, questo è un estratto dell'app Android di Zuul:

public class RetrofitModule {

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

}

Come puoi vedere, devi solo usare BuildConfigclass per accedere alla variabile che hai appena definito.

Qualsiasi variabile disponibile tramite il tuo codice La variabile HOST non è l'unica che puoi esporre nel tuo codice. Puoi farlo con quello che vuoi:

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

Puoi accedervi come segue:

BuildConfig.HOST  
BuildConfig.FLAVOR  
BuildConfig.REPORT_CRASHES  

Icone diverse per sapore Se vuoi avere icone diverse per sapore, così puoi rilevare visivamente quale stai aprendo (potresti farlo anche con il nome ... Ma non potrebbe adattarsi allo spazio!), Hai solo per definire nuove strutture di directory per ciascuno dei sapori.

Nell'esempio che ho appena usato ci sono due gusti: devel e prod. Quindi, potremmo definire due nuove strutture di directory in modo da poter definire le risorse che vogliamo:

struttura

Funziona con altri tipi di risorse come strings.xml, integers.xml, arrays.xml, ecc.

Configura le impostazioni di firma

Per configurare manualmente le configurazioni di firma per il tipo di build di rilascio utilizzando le configurazioni di build Gradle:

1.Creare un keystore. Un keystore è un file binario che contiene un set di chiavi private. Devi conservare il tuo archivio chiavi in ​​un luogo sicuro. 2.Creare una chiave privata. Una chiave privata rappresenta l'entità da identificare con l'app, come una persona o un'azienda. 3. Aggiungere la configurazione della firma al file build.gradle a livello di modulo:

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

}

Genera un APK firmato:

Per generare un APK firmato, seleziona Genera> Genera APK firmato dal menu principale. Il pacchetto in app / build / apk / app-release.apk è ora firmato con la chiave di rilascio.

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



7

Sembra che sia necessario ricaricare il progetto dopo aver aggiunto nuovi sapori build.gradle. Successivamente, vedrai 4 Varianti di costruzione nella vista Costruisci varianti (accederai dal bordo sinistro della finestra).

Per quanto riguarda le directory dei sorgenti aggiuntive, sembra che tu debba crearle manualmente: src/flavor1/javae src/flavor2/java. Vedrai che cambiando il sapore nella vista "Crea varianti" cambieranno le directory dei sorgenti attualmente attive (la directory è blu quando è una directory dei sorgenti attiva )

Infine, "Gradle creerà nuovi sourceSets per i vostri nuovi sapori" significa che Gradle creerà gli oggetti android.sourceSets.flavor1e android.sourceSets.flavor2e si possono usare nello script build.gradle. Ma quegli oggetti sono creati dinamicamente, ecco perché non li vedi nel build.gradle(ti consiglio di leggere questo: http://www.gradle.org/docs/current/userguide/tutorial_using_tasks.html Soprattutto il 6.6: spiega il creazione di compiti dinamici. Uno script gradle è uno script groovy, quindi ti consiglio di familiarizzare anche con Groovy)


2
Penso che la nota di importazione sia la Build Variantsvista, non me ne sono accorta.
Chris.Jenkins,

2

Ho avuto lo stesso problema quando ho migrato il mio progetto su Gradle. Il problema era che la build non ha trovato la cartella delle risorse corretta. L'ho corretto aggiungendo questo sotto l'elemento android in build.gradle:

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

0

Qualcosa che è importante e mi ha bloccato per un po 'di tempo è che il nome del sapore che deve abbinare il pacchetto al contrario del pacchetto definito nella definizione del sapore in gradle. Per esempio:

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

corrisponderà

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

ma

src/foobar/java/com/foo/A.java non verrà utilizzato per la build flavour1.


0

In gradle:

Per i tipi di build devi solo:

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

E poi per i sapori aggiungi quelli che ti servono

productFlavors {
    pro {
        applicationIdSuffix '.paid'
        buildConfigField 'boolean', 'PRO', 'true'
    }
    free {
        applicationIdSuffix '.free'
        buildConfigField 'boolean', 'PRO', 'false'
    }
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.