Comment puis-je accéder à une valeur BuildConfig dans mon fichier AndroidManifest.xml?

137

Est-il possible d'accéder à une valeur BuildConfig depuis AndroidManifest.xml?

Dans mon fichier build.gradle, j'ai:

defaultConfig {
    applicationId "com.compagny.product"
    minSdkVersion 16
    targetSdkVersion 21
    versionCode 1
    versionName "1.0"

    // Facebook app id
    buildConfigField "long", "FACEBOOK_APP_ID", FACEBOOK_APP_ID
}

FACEBOOK_APP_ID est défini dans mes fichiers gradle.properties:

# Facebook identifier (app ID)
FACEBOOK_APP_ID=XXXXXXXXXX

Pour utiliser Facebook connect dans mon application, je dois ajouter cette ligne à mon AndroidManifest.xml:

<meta-data android:name="com.facebook.sdk.ApplicationId" android:value="@string/applicationId"/> 

Je veux remplacer @string/applicationIdpar le champ BuildConfig FACEBOOK_APP_IDdéfini dans gradle, comme ceci:

<meta-data android:name="com.facebook.sdk.ApplicationId" android:value="FACEBOOK_APP_ID"/> 

Est-ce possible avec BuildConfig? Sinon, comment puis-je y parvenir?

Anthony
la source

Réponses:

190

Remplacer

buildConfigField "long", "FACEBOOK_APP_ID", FACEBOOK_APP_ID

avec

resValue "string", "FACEBOOK_APP_ID", FACEBOOK_APP_ID

puis reconstruisez votre projet (Android Studio -> Build -> Rebuild Project).

Les deux commandes produisent toutes les deux des valeurs générées - constituées de constantes Java dans le premier cas et de ressources Android dans le second - lors de la génération du projet, mais la seconde méthode génère une stringvaleur de ressource accessible à l'aide de la @string/FACEBOOK_APP_IDsyntaxe. Cela signifie qu'il peut être utilisé dans le manifeste ainsi que dans le code.

stkent
la source
1
C'est le code exact que j'utilise mais je suis confronté à un problème: le SDK Facebook lit la chaîne sous forme d'entier pour une raison quelconque, puis lève une exception ClassCastException car Integer ne peut pas être converti en String. Quelqu'un at-il été confronté à ce problème?
WKS
@WKS Si vous regardez le fichier de ressources généré, le type de ressource correspond-il à ce que vous attendez (chaîne)?
stkent
c'est une chaîne:<item name="facebook_app_id" type="string">15233522...</item>
WKS
13
assurez-vous d'écrire resValue "string" et PAS resValue "String"
keybee
1
Si vous souhaitez utiliser une valeur booléenne, assurez-vous de taper resValue "bool" au lieu de "boolean" -> tanelikorri.com/tutorial/android/set-variables-in-build-gradle
reavcn
85

Un autre moyen d'accéder aux valeurs Gradle Build Config à partir de votre AndroidManifest.xml consiste à utiliser des espaces réservés comme celui-ci:

android {
    defaultConfig {
        manifestPlaceholders = [ facebookAppId:"someId..."]
    }
    productFlavors {
        flavor1 {
        }
        flavor2 {
            manifestPlaceholders = [ facebookAppId:"anotherId..." ]
        }
    }
}

puis dans votre manifeste:

<meta-data android:name="com.facebook.sdk.ApplicationId" android:value="${facebookAppId}"/> 

Voir plus de détails ici: https://developer.android.com/studio/build/manifest-build-variables.html

(Ancien lien juste pour référence: http://tools.android.com/tech-docs/new-build-system/user-guide/manifest-merger )

GregoryK
la source
2
C'est une excellente solution.
BinaryShrub
2
Ouais, c'est une bonne méthode pour l'injection de chaînes de manifestes uniquement!
stkent
2
Comment obtiendriez-vous une valeur de manifestPlaceholders en java? Cela serait utile pour les constantes utilisées à la fois dans le code java et dans le manifeste.
Louis CAD
@LouisCAD Je suppose que vous pouvez essayer de définir une variable dans votre fichier de construction, puis l'utiliser pour définir votre espace réservé et (en plus) le champ BuildConfig, afin que vous puissiez l'utiliser dans votre code.
GregoryK
1
@LouisCAD Je n'ai pas essayé cela, mais vous pouvez essayer ce qui suit: var placeholder = 'your placeholder' (nouvelle ligne) buildConfigField "String", "PLACEHOLDER_NAME", placeholder (nouvelle ligne) manifestPlaceholders = [placeholderName: placholder] (new line) Je serais heureux de savoir si cela fonctionne pour vous
GregoryK
40

Remarque: lorsque vous utilisez resValuela valeur peut être accidentellement écrasée par le fichier de ressources de chaînes (par exemple pour une autre langue)

Pour obtenir une vraie valeur constante que vous pouvez utiliser dans le manifeste et dans le code java, utilisez à la fois manifestPlaceholderset buildConfigField: par exemple

android {
    defaultConfig {
        def addConstant = {constantName, constantValue ->
            manifestPlaceholders += [ (constantName):constantValue]
            buildConfigField "String", "${constantName}", "\"${constantValue}\""
        }

        addConstant("FACEBOOK_APP_ID", "xxxxx")
    }

accès dans le fichier manifeste:

<meta-data android:name="com.facebook.sdk.ApplicationId" android:value="${FACEBOOK_APP_ID}"/>

de java:

BuildConfig.FACEBOOK_APP_ID

Si la valeur de la constante doit être spécifique à buildType, l'assistant addConstantdoit être modifié (pour travailler avec la sémantique de fermeture groovy), par exemple,

buildTypes {
    def addConstantTo = {target, constantName, constantValue ->
        target.manifestPlaceholders += [ (constantName):constantValue]
        target.buildConfigField "String", "${constantName}", "\"${constantValue}\""
    }
    debug {
        addConstantTo(owner,"FACEBOOK_APP_ID", "xxxxx-debug")
    }
    release {
        addConstantTo(owner,"FACEBOOK_APP_ID", "xxxxx-release")
    }
TmTron
la source
1
Ne fonctionne pas, il affiche un identifiant d'application non valide, à partir du manifeste, mais lorsqu'il est défini à partir de java, cela fonctionne
Brajendra Pandey
Je pense que cela ne fonctionnera pas si vous essayez d'ajouter plus d'une constante!
Greg Ennis
1
@GregEnnis Aussi plus de constantes fonctionnent très bien pour moi: par exemple, je viens d'appeler addConstant()deux fois (avec différentes constantNamesbien sûr). Quelle erreur obtenez-vous?
TmTron
1
@TmTron vous n'obtenez pas d'erreur, mais vous réaffectez le tableau entier 'manifestPlaceholders' à chaque fois qu'il est appelé, en ne stockant que la dernière valeur utilisée.
Greg Ennis
@GregEnnis vous avez absolument raison! J'ai eu un code différent dans mon projet de test. J'ai déjà mis à jour ma réponse: il suffit d'utiliser l' +=opérateur comme celui-cimanifestPlaceholders += [...]
TmTron
6

Accédez aux propriétés build.gradle dans votre manifeste comme dans l'exemple suivant:

Par exemple, vous avez une propriété "applicationId" dans votre build.gradle et vous souhaitez y accéder dans votre AndroidManifest:

entrez la description de l'image ici

Accédez à "applicationId" dans AndroidManifest:

<receiver
        android:name="com.google.android.gms.gcm.GcmReceiver"
        android:exported="true"
        android:permission="com.google.android.c2dm.permission.SEND">
        <intent-filter>
            <action android:name="com.google.android.c2dm.intent.RECEIVE" />
            <category android:name="${applicationId}" />
        </intent-filter>
    </receiver>

De même, nous pouvons créer des ressources de chaîne pour d'autres constantes et y accéder dans des fichiers de code aussi simples que:

context.getString(R.string.GCM_SENDER_ID);
Vinay
la source
puis-je définir le facebookAppId: "anotherId ..." dans le fichier .properties où j'enregistrerais le mot de passe de mon magasin et tout. Ensuite, j'accède à ceux dans manifestplaceholders qui seraient indirectement accessibles dans AndroidManifest.xml. Puis-je faire cela?
Aman Verma
3

@stkent c'est bien mais oublie d'ajouter que vous devez reconstruire votre projet par la suite

Remplacer

buildConfigField "long", "FACEBOOK_APP_ID", FACEBOOK_APP_ID

avec

resValue "string", "FACEBOOK_APP_ID", FACEBOOK_APP_ID

puis

Android Studio -> Build -> Rebuild Project

Cela permettra à Android de générer la ressource de chaîne accessible via

R.string.FACEBOOK_APP_ID
FOO
la source
Impossible d'obtenir la propriété inconnue 'FACEBOOK_APP_ID' pour ProductFlavor_ ...
f.trajkovski
2

Une autre option: utilisez un fichier de ressources de chaîne différent pour remplacer toutes les valeurs dépendant de la saveur:

Étape 1: Créez un nouveau dossier dans le dossier "src" avec le nom de votre saveur, dans mon cas "stage"

Étape 2: Créez des fichiers de ressources pour tous les fichiers qui dépendent de la saveur, par exemple:

entrez la description de l'image ici

Étape 3: J'utilise également différentes icônes, donc vous voyez également les dossiers mipmap. Pour cette question, seul le "strings.xml" est important. Vous pouvez maintenant écraser toutes les ressources de chaîne importantes. Il vous suffit d'inclure ceux que vous souhaitez remplacer, tous les autres seront utilisés à partir du "strings.xml" principal, ils s'afficheront dans Android Studio comme ceci:

entrez la description de l'image ici

Étape 4: Utilisez les ressources de chaîne dans votre projet et détendez-vous:

entrez la description de l'image ici

Björn Kechel
la source
Une bonne alternative, surtout si vous avez beaucoup d'autres chaînes que vous devez définir par variante.
stkent
puis-je définir le facebookAppId: "anotherId ..." dans le fichier .properties où j'enregistrerais le mot de passe de mon magasin et tout. Ensuite, j'accède à ceux dans manifestplaceholders qui seraient indirectement accessibles dans AndroidManifest.xml. Puis-je faire cela?
Aman Verma
0

Vous pouvez utiliser une valeur longue comme ci-dessous

buildConfigField 'long', 'FLAVOR_LONG', '11500L'

Keyur Thumar
la source