App multi-gusto basata sulla libreria multi-sapore in Android Gradle


102

La mia app ha diversi gusti per diversi mercati di sistemi di fatturazione in-app.

Ho un'unica libreria che condivide il codice di base per tutti i miei progetti. Quindi ho deciso di aggiungere quei sistemi di pagamento a questa libreria come gusti di prodotto.

La domanda è: la libreria Android può avere gusti di prodotto?

In tal caso, come posso includere gusti diversi nel rispettivo sapore dell'app?

Ho cercato molto e non sono riuscito a trovare nulla su questo scenario. L'unica cosa vicina che ho trovato è stata questa 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')
}

Ho cambiato la configurazione in cose diverse ma non ha funzionato!

Sto usando Android Studio 0.8.2.


dopo molte ricerche, non ho trovato il modo per raggiungere questo obiettivo, anche se aggiorno il plugin Android 3.4.2all'ultima versione e passo all'ultima 5.5.1, ha ancora fallito con il tempo di compilazione, o il collegamento delle risorse non è riuscito in aapt, o non riesco a trovare il simbolo all'interno della libreria module
VinceStyling

Risposte:


141

Finalmente ho scoperto come farlo, lo spiegherò qui per altri che affrontano lo stesso problema:

La parte fondamentale è impostare publishNonDefault su true nella libreria build.gradle, quindi è necessario definire le dipendenze come suggerito dalla guida utente.

L'intero progetto sarebbe così:

Libreria build.gradle:

apply plugin: 'com.android.library'

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

progetto build.gradle:

apply plugin: 'com.android.application'

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

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

Ora puoi selezionare la versione dell'app e il pannello Build Variants e la libreria verrà selezionata di conseguenza e tutte le build e l'esecuzione verranno eseguite in base alla versione selezionata.

Se hai più moduli di app basati sulla libreria Android Studio si lamenterà del conflitto di selezione delle varianti, va bene, ignoralo.

inserisci qui la descrizione dell'immagine


Grazie per la condivisione, ora posso sbarazzarmi della mia soluzione alternativa defaultPublishConfig.
Delblanco

2
Eseguendo AS 1.1.0, la soluzione di cui sopra sembra funzionare ancora, tuttavia 1) la scelta delle build di debug / rilascio è persa e mi sembra di continuare ad avere problemi con AIDL trovato nella libreria che non riesce a produrre il codice appropriato molto spesso. Qualche idea su questo?
3c71

1
@IgorGanapolsky buildTypes non ha nulla a che fare con questo. Ogni gusto ha tutti i tipi di build (di solito debug e release) e tutti funzionano con questo approccio.
Ali

1
@ An-droid definisce la libreria da utilizzare per il gusto market1!
Ali

1
Perché è impostato sul tipo di build "release"? Il tipo di build "release" viene scelto durante le build di debug?
WindRider

35

C'è un problema con la risposta di Ali . Stiamo perdendo una dimensione molto importante nelle nostre varianti di build. Se vogliamo avere tutte le opzioni (nel mio esempio sotto 4 (2 x 2)) dobbiamo solo aggiungere configurazioni personalizzate nel file build.gradle del modulo principale per poter utilizzare tutti i multi-buildType multi-gusto in Build Variants. Dobbiamo anche impostare publishNonDefault true nel file build.gradle del modulo della libreria .

Soluzione di esempio:

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

}

Dopo aver fatto stesse cose nella mia richiesta, Error:java.lang.RuntimeException: Error: more than one library with package name, Avvenuto
Chetan Joshi

21

Aggiornamento per Android Plugin 3.0.0 e versioni successive

Secondo la documentazione ufficiale di Android - Migrazione delle configurazioni delle dipendenze per i moduli locali ,

Con la risoluzione delle dipendenze in base alle varianti, non è più necessario utilizzare configurazioni specifiche della variante, come freeDebugImplementation, per le dipendenze dei moduli locali: il plugin si occupa di questo per te

Dovresti invece configurare le tue dipendenze come segue:

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

Quindi, nella risposta di Ali, cambia

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

per

implementation project(':lib')

E il plugin si occuperà automaticamente delle configurazioni specifiche delle varianti. Spero che aiuti gli altri ad aggiornare il plug-in Android Studio a 3.0.0 e versioni successive.


7

Il mio plugin per Android è 3.4.0 e trovo che non abbia bisogno di configurazioni adesso. Tutto ciò di cui hai bisogno è assicurarti che flavourDimensions e productFlavors nell'applicazione contenga un productFlavor dello stesso flavourDimensions e productFlavors nelle librerie.Per esempio:

Nella build.gradle di mylibrary

apply plugin: 'com.android.library'

android {        
    ....
    flavorDimensions "mylibFlavor"

    productFlavors {
        market1
        market2
    }
}

build.gradle dell'applicazione:

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

Dopo la sincronizzazione, puoi cambiare tutte le opzioni nella finestra Build Variants: inserisci qui la descrizione dell'immagine


Ma cosa succede se non voglio avere gli stessi gusti nel modulo dell'app principale? Supponiamo che io abbia più moduli di app che hanno i suoi gusti specifici e un modulo comune che ha i suoi gusti e voglio usare nella mia app la mia libreria con un gusto specifico. Come lo faresti? Non ha senso copiare i miei gusti lib su tutte le app.
Billda

@Billda Non è necessario copiare tutto, basta mantenere lo stesso productFlavor nell'app, per il mio esempio, posso mantenere market1 o market2 nel build.gradle dell'applicazione.
JiajiaGu

2

Per far funzionare le versioni su una libreria AAR, devi definire defaultPublishConfig nel file build.gradle del tuo modulo Libreria Android.

Per ulteriori informazioni, vedere: Library Publication .

Pubblicazione in biblioteca

Per impostazione predefinita, una libreria pubblica solo la sua variante di rilascio. Questa variante verrà utilizzata da tutti i progetti che fanno riferimento alla libreria, indipendentemente dalla variante che costruiscono da soli. Si tratta di una limitazione temporanea dovuta alle limitazioni di Gradle che stiamo cercando di rimuovere. Puoi controllare quale variante viene pubblicata:

android {defaultPublishConfig "debug"}

Notare che questo nome di configurazione di pubblicazione fa riferimento al nome completo della variante. Il rilascio e il debug sono applicabili solo quando non ci sono gusti. Se desideri modificare la variante pubblicata predefinita durante l'utilizzo dei gusti, dovresti scrivere:

android {defaultPublishConfig "flavour1Debug"}


1

Al momento non è possibile, anche se se ricordo bene è una caratteristica che vogliono aggiungere. (Modifica 2: link , link2 )

Modifica: per il momento sto utilizzando l' defaultPublishConfigopzione per dichiarare quale variante della libreria viene pubblicata:

android {
    defaultPublishConfig fullRelease
    defaultPublishConfig demoRelease 
}

1
Quindi, ogni volta che compilerò l'app, devo cambiarlo in build.gradle della libreria?
Ali

Bene, sì ... ogni volta che vuoi compilare l'app con un sapore diverso.
Delblanco

In realtà, quando definisco i gusti per il modulo libreria, il pacchetto R ereditato non trova il modulo dell'app.
Ali

Hai sincronizzato i file gradle in AS?
Delblanco

@Delblanco Sembra un lavoro manuale e molto fragile (gli sviluppatori sono pigri e dimenticano di modificare i loro file build.gradle).
IgorGanapolsky

1

So che questo argomento è stato chiuso, ma solo un aggiornamento con gradle 3.0, guarda questo: https://developer.android.com/studio/build/gradle-plugin-3-0-0-migration.html#variant_aware e grep matchingFallbackse missingDimensionStrategy. Ora è molto più semplice dichiarare le dipendenze tra i tipi di modulo.

... e in questo caso preciso con gradle3.0, poiché i sapori condividono lo stesso nome, gradle li mapperà magicamente, non è richiesta alcuna configurazione.


Per me sembra che quel materiale generato dal runtime venga saltato. Ad esempio, la generazione di schemi simonvt-> non funziona più con il nuovo modo per me. : - /
Stefan Sprenger,

1

Ho anche riscontrato un problema durante la compilazione dei moduli per varie opzioni.

Quello che ho trovato:

Sembra che non sia necessario aggiungerlo publishNonDefault trueal build.gradlefile lib , poiché Gradle 3.0.1 .

Dopo aver decompilato una classe, ho BaseExtensiontrovato questo:

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

E invece di:

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

Dovremmo usare:

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

L'unica cosa importante è aggiungere una configurations {...}parte al file build.gradle.

Quindi, la variante finale del build.gradlefile dell'app è:

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

Inoltre, puoi utilizzare le varianti del filtro per limitare le varianti di build.

Ps non dimenticare di includere moduli nel settings.gradlefile, come:

include ':app'
include ':lib'
project(':lib').projectDir = new File('app/libs/lib')

signore, può spiegare come lo script determinerà il tempo per includere la libreria in una determinata configurazione oppure no? Voglio dire, ho un caso in cui ho bisogno di usare un po 'di lib per un certo sapore, ma non ho bisogno di usarlo per l'altro sapore
Jenya Kirmiza

Non sono entrato in una situazione del genere. Ma un tutorial di Google developer.android.com/studio/build/dependencies consiglia di aggiungere un prefisso prima del comando "implementazione" nel blocco "dipendenze {...}". Vale a dire dipendenze {paidImplementation project (': lib')}, o dipendenze {debugImplementation project (': lib')}, o qualsiasi combinazione di più varianti di dipendenze {paidProdDebugImplementation project (': lib')}. Dai un'occhiata e dacci un feedback :)
Sergio
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.