Utilisation de Build Flavors - Structurer correctement les dossiers source et build.gradle

166

Remarque: réponse modifiée après la réponse de Xavier

J'essaie d'utiliser différentes saveurs de construction pour un même projet d'application dans Android Studio. Cependant, il semble que je passe un temps terrible à le configurer pour qu'il fonctionne correctement.

Pas:

  1. Créez un nouveau projet Android Studio, nommé «Test».
  2. Ouvrez build.gradle * et ajoutez les lignes suivantes:

    productFlavors {
    flavor1 {
        packageName 'com.android.studio.test.flavor1'
        }
    flavor2 {
        packageName 'com.android.studio.test.flavor2'
        }
    }
  3. Après avoir redémarré Android Studio, je vois maintenant 4 variantes de construction dans la section Variantes de construction. Cela signifie que nous avons réussi jusqu'à présent à configurer les saveurs des produits. **
  4. Création d'un nouveau dossier source pour flavour1 ; cependant, je ne sais pas si je le fais de la bonne manière. Voici comment je l'ai fait:

    • Gardez à l'esprit que le nom de mon package pour ce projet est: com.foo.test
    • Faites un clic droit sur le srcdossier, pour flavour1, j'ai en fait créé les dossiers individuels dans l'explorateur, de la même manière que la structure src/flavor1/java/com/foo/test/MainActivity.java.
    • Ce qui précède a bien fonctionné, puisque le dossier «java» est en bleu , ce qui signifie que l'EDI connaît son répertoire source actif. En outre, le package a été créé automatiquement. Malgré cela, je reçois un avertissement pour une classe en double trouvée. Voir la capture d'écran ici.
    • Pour flavour2, j'ai essayé de créer le package manuellement, mais le dossier 'src' pour flavour2 ne semble pas être en bleu, et donc les options sont différentes lorsque je clique avec le bouton droit, et 'New Package' n'est pas disponible pour moi. Voir l'image ici.
    • Notez que pour flavour1, j'ai également créé un répertoire `` res '', qui devient bleu, mais malgré cela, n'offre pas la possibilité de créer un fichier de ressources Android ou un répertoire de ressources Andorid, au cas où je voudrais utiliser différents se résorbe pour différentes saveurs.

Est-ce que je fais quelque chose de mal? Ou est-ce que je manque quelque chose? Tenez-moi au courant si vous avez besoin de plus d'informations.

* Mon projet semble avoir deux fichiers build.gradle. Celui situé à la racine du dossier du projet (\ GradleTest), celui-ci est vide. Le second situé à la racine d'un sous-dossier de \ GradleTest, également appelé 'GradleTest' (GradleTest-GradleTest), c'est celui qui avait déjà du code à l'ouverture; c'est donc celui que j'ai édité.

** J'ai vérifié les paramètres de gradle et, apparemment, l'option Utiliser l'importation automatique était déjà activée. Malgré cela, apporter des modifications au fichier build.gradle ne met pas automatiquement à jour les variantes de build. Remarque: j'ai également essayé d'utiliser Build - Rebuild Project et / ou Build - Make Project, no-go. Je dois encore fermer le projet et le rouvrir pour que les modifications prennent effet.

daniel_c05
la source
Notez que applicationIdc'est désormais le support pris en charge au lieu de packageName.
Hamzeh Soboh

Réponses:

220

Si vous êtes arrivé dans les préférences de Studio, dans la section Gradle, vous pouvez activer l'importation automatique pour votre projet (nous l'activerons par défaut plus tard). Cela permettra à Studio de réimporter votre build.gradle chaque fois que vous le modifiez.

Créer des saveurs ne signifie pas que vous allez utiliser un code personnalisé pour eux, donc nous ne créons pas les dossiers. Vous devez les créer vous-même.

Si vous regardez mon exposé IO, vous verrez comment nous mélangeons les valeurs des saveurs et le type de construction pour créer la variante.

Pour la source Java:

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

sont tous les 3 utilisés pour créer une seule sortie. Cela signifie qu'ils ne peuvent pas définir la même classe.

Si vous voulez avoir une version différente de la même classe dans les deux saveurs, vous devrez la créer dans les deux saveurs.

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

Et puis votre code dans src / main / java peut faire

import com.foo.A

selon la saveur choisie, la bonne version de com.foo.A est utilisée.

Cela signifie également que les deux versions de A doivent avoir la même API (du moins en ce qui concerne l'API utilisée par les classes dans src / main / java / ...

Modifier pour correspondre à la question révisée

De plus, il est important de placer la même classe A uniquement dans des dossiers source qui s'excluent mutuellement. Dans ce cas, src / flavour1 / java et src / flavour2 / java ne sont jamais sélectionnés ensemble, mais main et flavour1 le sont.

Si vous souhaitez fournir une version différente d'une activité dans une saveur différente, ne la placez pas dans src / main / java.

Notez que si vous aviez 3 saveurs et que vous en vouliez seulement une personnalisée pour la saveur1, alors que la saveur2 et la saveur3 partageaient la même activité, vous pourriez créer un dossier source commun pour ces deux autres activités. Vous disposez d'une flexibilité totale pour créer de nouveaux dossiers sources et configurer l'ensemble de sources pour les utiliser.

Passons à vos autres points:

Il est normal que le deuxième dossier source de saveur ne soit pas bleu. Vous devez passer à la 2ème version pour l'activer, puis vous pourrez créer des packages et des classes à l'intérieur. Jusque-là, Studio ne le considère pas comme un dossier source. Nous espérons améliorer à l'avenir faire l'IDE au courant de ces contrôle inactifs dossiers source.

Je pense qu'il est également normal que vous ne puissiez pas créer de fichiers de ressources dans le dossier res. Le système de menus n'a pas été mis à jour pour gérer tous ces dossiers de ressources supplémentaires. Cela viendra plus tard.

Xavier Ducrohet
la source
1
J'ai ajouté de nouveaux éléments à la fin de ma réponse, mais le double a du sens. Vous ne pouvez pas avoir la même classe à la fois dans src / main / java et src / flavour1 / java car les deux sont utilisés lors de la sélection de flavour1. Dans ma réponse, remarquez comment je mets la même classe uniquement dans flavour1 / java et flavour2 / java car ils sont exclusifs et jamais activés ensemble.
Xavier Ducrohet
Hey Xavier, pouvez-vous me donner une description plus détaillée de la façon dont je peux utiliser une version différente d'une activité dans mes saveurs? J'ai un projet de test dans lequel je souhaite utiliser différentes versions de ma MainActivity, mais dans les deux apks (flavour1 et flavour2), il n'y a que la version de main / java. Lorsque je ne mets pas MainActivity dans main / java, l'application se bloque lorsque je la démarre.
JensJensen
@XavierDucrohet que diriez-vous d'avoir différentes ressources ainsi que différents codes basés sur des saveurs, mais les avoir dans différents modules afin que nous puissions inclure un module ou l'autre en fonction de la saveur, sans avoir à mélanger le code et les ressources dans le même projet racine? Cela est-il pris en charge?
Valerio Santinelli le
3
@ValerioSantinelli Vous pouvez faire des dépendances par saveur. UtilisationflavorCompile ...
Xavier Ducrohet
@XavierDucrohet J'ai essayé ce que vous avez suggéré mais cela ne fonctionne pas comme prévu. Vous pouvez voir comment mon projet est structuré ici: stackoverflow.com/q/24410995/443136
Valerio Santinelli
19

"Saveurs de produits" sur Android

On m'a parfois demandé comment travailler avec différents hôtes, icônes ou même noms de packages, en fonction de différentes versions de la même application.

Il y a de nombreuses raisons de faire cela et une solution simple: les saveurs des produits.

Vous pouvez définir sur votre script build.gradle ce genre de choses que j'ai décrites précédemment.

Saveurs des produits Une partie de cet article est consacrée à la réflexion sur les saveurs des produits, alors que sont-elles? Concernant la documentation Android:

Une saveur de produit définit une version personnalisée de l'application créée par le projet. Un même projet peut avoir différentes saveurs qui changent l'application générée.

Comment pouvez-vous les définir? Vous devez écrire sur votre build.gradle les saveurs que vous souhaitez définir:

productFlavors {  
        ...
        devel {
            ...
        }

        prod {
            ...
        }
    }

Maintenant, nous aurons deux saveurs différentes de notre application. Vous pouvez également le vérifier sur Android Studio dans l'onglet Variantes de construction

Construire des variantes

Nom de package multiple

Que faire si vous souhaitez avoir installé sur votre téléphone une application avec l'état de développement et une pour l'état de production. Comme vous le savez peut-être, vous ne pouvez installer qu'une seule application avec le même nom de package (si vous essayez d'installer un nouvel APK avec le même que celui installé sur votre téléphone, il essaiera de le mettre à jour).

Il ne vous reste plus qu'à le définir sur chacune de vos saveurs de produits:

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

Envoyer des demandes à plusieurs hôtes en fonction de la saveur Comme auparavant, vous devez inclure certains paramètres dans le champ de configuration de la saveur de votre produit.

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

        }
    }
}

À titre d'exemple, nous allons essayer de vous montrer comment vous pouvez intégrer cela avec Retrofit pour envoyer une demande au serveur approprié sans gérer le serveur sur lequel vous pointez et en fonction de la saveur. Dans ce cas, il s'agit d'un extrait de l'application Android 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);
    }

}

Comme vous pouvez le voir, il vous suffit d'utiliser la classe BuildConfig pour accéder à la variable que vous venez de définir.

Toute variable disponible via votre code La variable HOST n'est pas la seule que vous pouvez exposer dans votre code. Vous pouvez le faire avec tout ce que vous voulez:

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

Vous pouvez y accéder comme suit:

BuildConfig.HOST  
BuildConfig.FLAVOR  
BuildConfig.REPORT_CRASHES  

Différentes icônes par saveur Si vous voulez avoir différentes icônes par saveur, afin de pouvoir détecter visuellement celle que vous ouvrez (vous pouvez aussi le faire par son nom ... mais cela ne peut pas s'adapter à l'espace!), Vous avez juste pour définir de nouvelles structures de répertoires pour chacune des saveurs.

Dans l'exemple que je viens d'utiliser, il y a deux saveurs: devel et prod. Ensuite, nous pourrions définir deux nouvelles structures de répertoires afin de pouvoir définir les ressources que nous voulons:

structure

Cela fonctionne avec d'autres types de ressources comme strings.xml, integers.xml, arrays.xml, etc.

Configurer les paramètres de signature

Pour configurer manuellement les configurations de signature pour votre type de build de version à l'aide des configurations de build Gradle:

1.Créez un keystore. Un fichier de clés est un fichier binaire contenant un ensemble de clés privées. Vous devez conserver votre keystore dans un endroit sûr et sécurisé. Créez une clé privée. Une clé privée représente l'entité à identifier avec l'application, telle qu'une personne ou une entreprise. 3.Ajoutez la configuration de signature au fichier build.gradle au niveau du module:

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

}

Générez un APK signé:

Pour générer un APK signé, sélectionnez Créer> Générer un APK signé dans le menu principal. Le package dans app / build / apk / app-release.apk est maintenant signé avec votre clé de version.

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

Technologie A-Droid
la source
7

Il semble que vous deviez recharger votre projet après avoir ajouté de nouvelles saveurs dans build.gradle. Après cela, vous verrez 4 variantes de construction dans la vue Variantes de construction (vous y accédez depuis le bord gauche de la fenêtre).

En ce qui concerne les répertoires sources supplémentaires, il semble que vous deviez les créer à la main: src/flavor1/javaet src/flavor2/java. Vous verrez que changer la saveur dans la vue "Build Variants" changera les répertoires source actuellement actifs (le répertoire est bleu lorsqu'il s'agit d'un répertoire source actif )

Enfin, "gradle créera de nouveaux sourcesSets pour vos nouvelles saveurs" signifie que gradle créera les objets android.sourceSets.flavor1et android.sourceSets.flavor2que vous pourrez les utiliser dans votre script build.gradle. Mais ces objets sont créés dynamiquement, c'est pourquoi vous ne les voyez pas dans le build.gradle(je vous suggère de lire ceci: http://www.gradle.org/docs/current/userguide/tutorial_using_tasks.html Surtout le 6.6: il explique le création d'une tâche dynamique. Un script gradle est un script groovy, je vous suggère donc de vous familiariser avec groovy aussi)

ben75
la source
2
Je pense que la note d'importation est la Build Variantsvue, je ne l'ai pas remarqué.
Chris.Jenkins
2

J'ai eu le même problème lorsque j'ai migré mon projet vers Gradle. Le problème était que la compilation n'avait pas trouvé le dossier de ressources approprié. Je l'ai corrigé en ajoutant ceci sous l'élément android dans build.gradle:

sourceSets {
        main {
            res.srcDirs = ['myProject/res']
        }
    }
Tomer
la source
0

Quelque chose qui est important et m'a bloqué pendant un certain temps est que le nom de la saveur qui doit correspondre au package par opposition au package défini dans la définition de la saveur dans gradle. Par exemple:

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

correspondra

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

mais

src/foobar/java/com/foo/A.java ne sera pas utilisé pour la construction de la saveur1.

bitrock
la source
0

En gradle:

Pour les types de build, vous n'avez besoin que de:

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

Et puis pour les saveurs, vous ajoutez celles dont vous avez besoin

productFlavors {
    pro {
        applicationIdSuffix '.paid'
        buildConfigField 'boolean', 'PRO', 'true'
    }
    free {
        applicationIdSuffix '.free'
        buildConfigField 'boolean', 'PRO', 'false'
    }
}
TouchBoarder
la source