web-dev-qa-db-fra.com

Construire des variantes dans Gradle pour un projet de bibliothèque sous Android

J'essaie de configurer avec Gradle un projet contenant des bibliothèques externes. Avec Gradle, je peux configurer différentes configurations d'environnement (avec une classe dans un fichier de configuration) pour l'application principale à l'aide des variantes de construction afin de pouvoir exécuter du code en fonction de ces variables. 

Le problème est que comment puis-je faire la même chose pour un projet de bibliothèque? J'ai créé cette bibliothèque pour ce projet et j'aimerais configurer différentes variantes de construction pour différents scénarios. 

Par exemple: Dans la bibliothèque, en mode débogage, imprimez tous les journaux afin que je puisse les voir pendant le développement. En mode de lancement ne pas. 

Structure des fichiers:

src ----- > debug -> Java -> config -> PlayerEnvConfig
            main -> com.mypackagename -> etc...
            release -> Java -> config -> PlayerEnvConfig

Code en débogage: Paquet config;

/**
 * Environment configuration for Release
*/
public final class PlayerEnvConfig {
    public static final boolean USE_REPORTING = true;
    public static final boolean USE_ANALYTICS = true;
    public static final boolean USE_LOGGING = false;
    public static final boolean USE_DEBUG_LOGGING = false;
    public static final boolean USE_DEBUGING = false;
}

Code en sortie:

package config;

/**
 * Environment configuration for Release
*/
public final class PlayerEnvConfig {
    public static final boolean USE_REPORTING = true;
    public static final boolean USE_ANALYTICS = true;
    public static final boolean USE_LOGGING = false;
    public static final boolean USE_DEBUG_LOGGING = false;
    public static final boolean USE_DEBUGING = false;
}

Le problème est que pour le projet principal, je peux utiliser ces types de construction pour configurer différemment l'application pour différents scénarios, mais comment puis-je faire de même pour le projet de bibliothèque? 

Car pour le moment, d'après ce que j'ai lu dans http://tools.Android.com/tech-docs/new-build-system/user-guide seule la bibliothèque utilisera le mode débogage lors des tests. 

Des idées? 

Merci!

22
Javier Tarazaga

C'est une réponse @bifmadei de problème de code google et cela m'aide:

Essayez de définir ceci dans le projet de dépendance

Android {
    publishNonDefault true
    ...
}

et cela dans le projet qui l'utilise

dependencies {
    releaseCompile project(path: ':theotherproject', configuration: 'release')
    debugCompile project(path: ':theotherproject', configuration: 'debug')
}

Tiré d'ici: https://code.google.com/p/Android/issues/detail?id=66805

14
Beloo

Je ne sais pas ce qui ne va pas avec votre configuration, mais en ce qui concerne vos besoins, je le ferais différemment.

Dans le fichier de construction de gradle, vous pouvez utiliser le mot clé buildConfig pour ajouter une ligne spécifique à la classe générée BuildConfig.Java.

Vous pouvez donc ajouter quelque chose comme ça dans votre build.gradle:

    release {
        buildConfig "public static final String USE_REPORTING = true;"
    }
    debug {

        buildConfig "public static final String USE_REPORTING = false;"
    }

Et ainsi seulement une PlayerEnvConfig avec

public static final boolean USE_REPORTING = BuildConfig.USE_REPORTING;

Ou même plus PlayerEnvConfig et utilisez directement la classe BuildConfig.


EDIT Depuis une mise à jour, la syntaxe a changé:

buildConfigField "<type>", "<name>", "<value>"
12
tbruyelle

Ceci est documenté dans https://code.google.com/p/Android/issues/detail?id=52962 . Comme vous l'avez découvert, le type de construction n'est pas propagé aux projets de bibliothèque et la solution de contournement n'est pas satisfaisante. Si vous avez le contrôle sur le code du projet de bibliothèque, vous pouvez transformer le statut de débogage en une variable globale modifiable et le définir à partir de votre application principale au démarrage. C'est un peu un bidouillage, et cela a l'inconvénient que le compilateur ne peut pas optimiser les chemins de code inutilisés loin des versions de version, mais à moins que quelque chose d'inhabituel ne se produise, cela devrait fonctionner.

4
Scott Barta

MISE À JOUR - depuis le début de cette publication, le processus de construction de la gradation a beaucoup progressé. Cette réponse risque de ne pas être la meilleure pratique recommandée et de nouvelles modifications pourraient même la freiner. Utilisez votre propre discrétion.

Je pense qu'il y a un peu de confusion sur la structure et la configuration du projet. Disons que vous avez la configuration build.gradle suivante

sourceSets {

    main {
        manifest.srcFile 'src/main/AndroidManifest.xml'
        Java.srcDirs = ['src/main/Java']
        //resources.srcDirs = ['src/main']
        //aidl.srcDirs = ['src/main']
        //renderscript.srcDirs = ['src/main']
        res.srcDirs = ['src/main/res']
        assets.srcDirs = ['src/main/assets']
    }

    debug.setRoot('build-types/debug')
    release.setRoot('build-types/release')
}

Votre structure de dossier de projet devrait être comme suit

project_root
   -src
      -main
         -Java
            -com
               -example
   -build-types
      -debug
         -Java
            -com
               -example
                  -FooBar.Java
      -release
         -Java
            -com
               -example
                  -FooBar.Java

FooBar.Java ne doit pas être dans le prooject_root/src/main/Java/com/example. Il doit se trouver dans les dossiers debug et release qui doivent résider en dehors du dossier src mais à l'intérieur du dossier build-types. C'est configuré par la méthode setRoot('build-types/*****'). Beaucoup de gens sont déroutés de voir 'debug/Java' et 'main/Java', où le dernier est référencé de la manière 'src/main/Java' de la présentation et finit par mettre 'debug/Java' dans src, le mauvais dossier. J'espère que cette aide.

Pour un environnement plus complexe impliquant d’autres bibliothèques, vous pouvez consulter ma réponse ici https://stackoverflow.com/a/19918834/319058

3
Win Myo Htet

Comme le souligne Scott , il s'agit d'une lacune connue de Gradle . Pour résoudre ce problème, vous pouvez utiliser cette méthode, qui utilise la réflexion pour obtenir la valeur de champ de l'application (et non de la bibliothèque):

/**
 * Gets a field from the project's BuildConfig. This is useful when, for example, flavors
 * are used at the project level to set custom fields.
 * @param context       Used to find the correct file
 * @param fieldName     The name of the field-to-access
 * @return              The value of the field, or {@code null} if the field is not found.
 */
public static Object getBuildConfigValue(Context context, String fieldName) {
    try {
        Class<?> clazz = Class.forName(context.getPackageName() + ".BuildConfig");
        Field field = clazz.getField(fieldName);
        return field.get(null);
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    } catch (NoSuchFieldException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    }
    return null;
}

Pour obtenir le champ DEBUG, par exemple, appelez simplement ceci à partir de votre Activity:

boolean debug = (Boolean) getBuildConfigValue(this, "DEBUG");

J'ai également partagé cette solution sur AOSP Issue Tracker .

0
Phil

Ce n'est pas possible avec les projets de bibliothèque comme vous l'avez mentionné vous-même. 

Vous pouvez simplement changer le projet de bibliothèque en projet d'application. Cela semble fonctionner correctement (du moins en théorie, je ne l’ai pas testé moi-même).

L’autre solution consiste à remplacer cette classe dans votre projet d’application. Votre classe de projet d'application sera choisie lors de la fusion et vous aurez ces valeurs disponibles.

0
Saad Farooq