Application multi-saveurs basée sur une bibliothèque multi-saveurs dans Android Gradle

102

Mon application a plusieurs versions pour plusieurs marchés de systèmes de facturation intégrée.

J'ai une seule bibliothèque qui partage le code de base pour tous mes projets. J'ai donc décidé d'ajouter ces systèmes de paiement à cette bibliothèque en tant que saveurs de produits.

La question est la suivante: la bibliothèque Android peut-elle avoir des saveurs de produits?

Si tel est le cas, comment puis-je inclure différentes saveurs dans la saveur respective de l'application?

J'ai beaucoup cherché et je n'ai rien trouvé sur ce scénario. La seule chose proche que j'ai trouvée était celle-ci dans http://tools.android.com/tech-docs/new-build-system/user-guide :

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

J'ai changé de configuration pour différentes choses mais cela n'a pas fonctionné!

J'utilise Android Studio 0.8.2.

Ali
la source
après de nombreuses recherches, je n'ai trouvé aucun moyen d'y parvenir, même si j'ai mis à niveau le plugin Android vers la dernière 3.4.2version et gradué vers la dernière 5.5.1, cela a toujours échoué avec le temps de compilation, ou la liaison des ressources a échoué dans aapt, ou je ne trouve pas le symbole qui se trouve dans la bibliothèque module
VinceStyling

Réponses:

141

Enfin j'ai découvert comment faire cela, je vais l'expliquer ici pour les autres confrontés au même problème:

L'élément clé est de définir publishNonDefault sur true dans la bibliothèque build.gradle, puis vous devez définir les dépendances comme suggéré par le guide de l'utilisateur.

L'ensemble du projet serait comme ceci:

Bibliothèque build.gradle:

apply plugin: 'com.android.library'

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

projet build.gradle:

apply plugin: 'com.android.application'

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

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

Vous pouvez maintenant sélectionner la saveur de l'application et le panneau Variantes de construction et la bibliothèque sera sélectionnée en conséquence et toute la construction et l'exécution seront effectuées en fonction de la saveur sélectionnée.

Si vous avez plusieurs modules d'application basés sur la bibliothèque, Android Studio se plaindra du conflit de sélection de variantes, c'est ok, ignorez-le.

entrez la description de l'image ici

Ali
la source
Merci pour le partage, je peux maintenant me débarrasser de ma solution de contournement defaultPublishConfig.
Delblanco
2
En exécutant AS 1.1.0, la solution ci-dessus semble toujours fonctionner, cependant 1) le choix des versions de débogage / publication est perdu et je semble continuer à avoir des problèmes avec AIDL trouvé dans la bibliothèque qui ne parvient pas à produire le code approprié très souvent. Des pensées à ce sujet?
3c71
1
@IgorGanapolsky buildTypes n'a rien à voir avec cela. Chaque saveur a tous les types de construction (généralement le débogage et la publication) et tous fonctionnent avec cette approche.
Ali le
1
@ An-droid définit la bibliothèque à utiliser pour la saveur market1!
Ali le
1
Pourquoi est-il défini sur le type de construction "release"? Le type de build "release" est-il choisi lors des builds de débogage?
WindRider
35

Il y a un problème avec la réponse d' Ali . Nous perdons une dimension très importante dans nos variantes de construction. Si nous voulons avoir toutes les options (dans mon exemple ci-dessous 4 (2 x 2)), nous devons simplement ajouter des configurations personnalisées dans le fichier build.gradle du module principal pour pouvoir utiliser tous les multi-buildType multi-saveur dans Build Variants. Nous devons également définir publishNonDefault sur true dans le fichier build.gradle du module de bibliothèque .

Exemple de solution:

Lib build.gradle

android {

    publishNonDefault true

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

Construction de l'application.

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
la source
Après avoir fait la même chose dans mon application Error:java.lang.RuntimeException: Error: more than one library with package name,, apparu
Chetan Joshi
21

Mise à jour pour Android Plugin 3.0.0 et supérieur

Selon la documentation officielle Android - Migrez les configurations de dépendance pour les modules locaux ,

Avec la résolution des dépendances prenant en charge les variantes, vous n'avez plus besoin d'utiliser des configurations spécifiques aux variantes, telles que freeDebugImplementation, pour les dépendances de modules locaux - le plugin s'en charge pour vous

Vous devez plutôt configurer vos dépendances comme suit:

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

Donc dans la réponse d'Ali, changez

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

à

implementation project(':lib')

Et le plugin s'occupera automatiquement des configurations spécifiques aux variantes. J'espère que cela aidera les autres à mettre à niveau le plugin Android Studio vers la version 3.0.0 et supérieure.

Harsh4789
la source
7

Mon plug-in Android est 3.4.0, et je trouve qu'il n'a pas besoin de configuration maintenant.Tout ce dont vous avez besoin est de vous assurer que les flavours et productFlavors dans l'application contiennent un productFlavor de la même saveurDimensions et productFlavors dans les bibliothèques.

Dans build.gradle de mylibrary

apply plugin: 'com.android.library'

android {        
    ....
    flavorDimensions "mylibFlavor"

    productFlavors {
        market1
        market2
    }
}

build.gradle de l'application:

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

Après la synchronisation, vous pouvez changer toutes les options dans la fenêtre Variantes de construction: entrez la description de l'image ici

JiajiaGu
la source
Mais que faire si je ne veux pas avoir les mêmes saveurs dans mon module d'application principal? Supposons que j'ai plusieurs modules d'application qui ont ses propres saveurs spécifiques et un module commun qui a ses propres saveurs et que je souhaite utiliser dans mon application ma bibliothèque avec une saveur spécifique. Comment feriez-vous cela? Cela n'a pas de sens de copier mes saveurs de lib dans toutes les applications.
Billda
@Billda Vous n'avez pas besoin de tout copier, gardez simplement un même productFlavor dans l'application, pour mon échantillon, je peux garder market1 ou market2 dans build.gradle de l'application.
JiajiaGu
2

Pour que les versions fonctionnent sur une bibliothèque AAR, vous devez définir defaultPublishConfig dans le fichier build.gradle de votre module de bibliothèque Android.

Pour plus d'informations, voir: Publication de la bibliothèque .

Publication de la bibliothèque

Par défaut, une bibliothèque ne publie que sa version de version. Cette variante sera utilisée par tous les projets référençant la bibliothèque, quelle que soit la variante qu'ils construisent eux-mêmes. Il s'agit d'une limitation temporaire en raison des limitations Gradle que nous travaillons à supprimer. Vous pouvez contrôler quelle variante est publiée:

android {defaultPublishConfig "debug"}

Notez que ce nom de configuration de publication fait référence au nom complet de la variante. La version et le débogage ne sont applicables qu'en l'absence de saveurs. Si vous vouliez changer la variante publiée par défaut tout en utilisant des saveurs, vous écririez:

android {defaultPublishConfig "flavour1Debug"}

David Lev
la source
1

Pour le moment, ce n'est pas possible, même si si je me souviens bien, c'est une fonctionnalité qu'ils veulent ajouter. (Édition 2: lien , lien2 )

Edit: Pour le moment, j'utilise l' defaultPublishConfigoption pour déclarer quelle variante de bibliothèque est publiée:

android {
    defaultPublishConfig fullRelease
    defaultPublishConfig demoRelease 
}
Delblanco
la source
1
Donc, chaque fois que je vais compiler l'application, je dois changer cela dans build.gradle de la bibliothèque?
Ali
Eh bien, oui ... chaque fois que vous voulez compiler l'application avec une saveur différente.
Delblanco
En fait, lorsque je définis des saveurs pour le module de bibliothèque, le package R hérité ne trouve pas le module d'application.
Ali
Avez-vous synchronisé les fichiers Gradle dans AS?
Delblanco
@Delblanco Cela semble être un travail manuel et très fragile (les développeurs sont paresseux et oublient de modifier leurs fichiers build.gradle).
IgorGanapolsky
1

Je sais que ce sujet a été fermé, mais juste une mise à jour avec gradle 3.0, voir ceci: https://developer.android.com/studio/build/gradle-plugin-3-0-0-migration.html#variant_aware et grep matchingFallbacksetmissingDimensionStrategy . Il est maintenant beaucoup plus simple de déclarer les dépendances entre les variantes de module.

... et dans ce cas précis avec gradle3.0, comme les saveurs partagent le même nom, gradle les mapperait comme par magie, aucune configuration n'est requise.

AlexG
la source
Pour moi, il semble que les éléments générés par le runtime sont ignorés. Par exemple, la génération de schémas simonvt-> ne fonctionne plus avec la nouvelle méthode pour moi. : - /
Stefan Sprenger
1

J'ai également rencontré un problème lors de la compilation de modules pour diverses options.

Ce que j'ai trouvé:

Il semble que nous n'avons pas besoin d'ajouter publishNonDefault truedans le build.gradlefichier de lib , depuis Gradle 3.0.1 .

Après avoir décompilé une classe a BaseExtensiontrouvé ceci:

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

Et au lieu de:

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

Nous devrions utiliser:

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

La seule chose importante, c'est d'ajouter une configurations {...}partie au fichier build.gradle.

Ainsi, la dernière variante du build.gradlefichier de l'application est:

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

Vous pouvez également utiliser les variantes de filtre pour restreindre les variantes de construction.

N'oubliez pas d'inclure des modules dans le settings.gradlefichier, comme:

include ':app'
include ':lib'
project(':lib').projectDir = new File('app/libs/lib')
Sergio
la source
monsieur, pouvez-vous expliquer comment le script déterminera la météo pour inclure la bibliothèque dans une certaine configuration ou non? Je veux dire, j'ai un cas où j'ai besoin d'utiliser une bibliothèque pour une certaine saveur, mais je n'ai pas besoin de l'utiliser pour l'autre saveur
Jenya Kirmiza
Je ne suis pas entré dans une telle situation. Mais un tutoriel google developer.android.com/studio/build/dependencies recommande d'ajouter un préfixe avant la commande "implementation" dans le bloc "dependencies {...}". C'est-à-dire les dépendances {projet payéImplementation (': lib')}, ou les dépendances {projet debugImplementation (': lib')}, ou toute dépendance à combinaison de variantes multiples {projet payéProdDebugImplementation (': lib')}. Découvrez-le et donnez-nous un commentaire :)
Sergio