it-swarm.com.de

Ist es möglich, eine in Java verwendbare Variable in Gradle zu deklarieren?

Ist es möglich, eine Variable in Gradle als in Java verwendbar zu deklarieren? Grundsätzlich möchte ich einige Variablen in build.gradle deklarieren und diese dann (offensichtlich) zur Buildzeit abrufen. Genau wie ein Pre-Prozessor-Makro in C/C++ ...

Ein Beispiel für eine Deklaration wäre so etwas ...:

Android {
    debug {
        A_VAR_RETRIEVABLE_IN_Java = 42
    }
    release {
        A_VAR_RETRIEVABLE_IN_Java = 42+52
    }
}

Gibt es eine Möglichkeit, so etwas zu tun?

361
klefevre

Java-Konstanten generieren

Android {
    buildTypes {
        debug {
            buildConfigField "int", "FOO", "42"
            buildConfigField "String", "FOO_STRING", "\"foo\""
            buildConfigField "boolean", "LOG", "true"
        }

        release {
            buildConfigField "int", "FOO", "52"
            buildConfigField "String", "FOO_STRING", "\"bar\""
            buildConfigField "boolean", "LOG", "false"
        }
    }
}

Sie können mit BuildConfig.FOO darauf zugreifen.

Android-Ressourcen generieren

Android {
    buildTypes {
        debug{
            resValue "string", "app_name", "My App Name Debug"
        }
        release {
            resValue "string", "app_name", "My App Name"
        }
    }
}

Sie können auf die übliche Weise mit @string/app_name oder R.string.app_name darauf zugreifen.

719
rciovati

Ein Beispiel für die Verwendung eines Api App Key in einer Android-Anwendung (Java und XML)

gradle.properties

AppKey="XXXX-XXXX"

build.gradle

buildTypes {
//...
    buildTypes.each {
        it.buildConfigField 'String', 'APP_KEY_1', AppKey
        it.resValue 'string', 'APP_KEY_2', AppKey
    }
}

Verwendung in Java-Code

Log.d("UserActivity", "onCreate, APP_KEY: " + getString(R.string.APP_KEY_2));

BuildConfig.APP_KEY_1

Verwendung in XML-Code

<data Android:scheme="@string/APP_KEY_2" />
82
Denis

Beispiel für die Verwendung von Systemeigenschaften (in build.gradle), das aus der Java-Anwendung gelesen wird (Fortsetzung der Frage in den Kommentaren):

Grundsätzlich kann mit der Task test in build.gradle die Testaufgabenmethode systemProperty eine zur Laufzeit übergebene Systemeigenschaft festlegen:

apply plugin: 'Java'
group = 'example'
version = '0.0.1-SNAPSHOT'

repositories {
    mavenCentral()
    // mavenLocal()
    // maven { url 'http://localhost/nexus/content/groups/public'; }
}

dependencies {
    testCompile 'junit:junit:4.8.2'
    compile 'ch.qos.logback:logback-classic:1.1.2'
}

test {
  logger.info '==test=='
  systemProperty 'MY-VAR1', 'VALUE-TEST'
}

Und hier ist der Rest des Beispielcodes (den Sie wahrscheinlich schließen können, der hier jedoch ohnehin enthalten ist): Er erhält die Systemeigenschaft MY-VAR1, die zur Laufzeit voraussichtlich auf VALUE-TEST gesetzt ist:

package example;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class HelloWorld {
  static final Logger log=LoggerFactory.getLogger(HelloWorld.class);
  public static void main(String args[]) {
    log.info("entering main...");
    final String val = System.getProperty("MY-VAR1", "UNSET (MAIN)");
    System.out.println("(main.out) hello, world: " + val);
    log.info("main.log) MY-VAR1=" + val);
  }
}

Testfall: Wenn MY-VAR nicht gesetzt ist, sollte der Test fehlschlagen:

package example;
...
public class HelloWorldTest {
    static final Logger log=LoggerFactory.getLogger(HelloWorldTest.class);
    @Test public void testEnv() {
        HelloWorld.main(new String[]{});
        final String val = System.getProperty("MY-VAR1", "UNSET (TEST)");
        System.out.println("(test.out) var1=" + val);
        log.info("(test.log) MY-VAR1=" + val);
        assertEquals("env MY-VAR1 set.", "VALUE-TEST", val);
    }
}

Run (Anmerkung: Test ist bestanden):

$ gradle cleanTest test
:cleanTest
:compileJava UP-TO-DATE
:processResources UP-TO-DATE
:classes UP-TO-DATE
:compileTestJava UP-TO-DATE
:processTestResources UP-TO-DATE
:testClasses UP-TO-DATE
:test

BUILD SUCCESSFUL

Ich habe festgestellt, dass der schwierige Teil tatsächlich die Ausgabe von gradle abruft ... Hier wird die Protokollierung konfiguriert (slf4j + logback), und die Protokolldatei zeigt die Ergebnisse (alternativ führen Sie gradle --info cleanTest test aus; es gibt auch Eigenschaften, die stdout abrufen zur Konsole, aber wissen Sie warum):

$ cat app.log
INFO Test worker example.HelloWorld - entering main...
INFO Test worker example.HelloWorld - main.log) MY-VAR1=VALUE-TEST
INFO Test worker example.HelloWorldTest - (test.log) MY-VAR1=VALUE-TEST

Wenn Sie "systemProperty..." auskommentieren (was übrigens nur in einer test-Task funktioniert), dann:

example.HelloWorldTest > testEnv FAILED
    org.junit.ComparisonFailure at HelloWorldTest.Java:14

Der Vollständigkeit halber sei hier die Logback-Konfiguration (src/test/resources/logback-test.xml) angegeben:

<configuration>
    <appender name="FILE" class="ch.qos.logback.core.FileAppender">
        <file>app.log</file>
        <layout class="ch.qos.logback.classic.PatternLayout">
            <pattern>%d %p %t %c - %m%n</pattern>
        </layout>
 </appender>
 <root level="info">
     <appender-ref ref="FILE"/>
</root>
</configuration> 

Dateien:

  • build.gradle
  • src/main/Java/example/HelloWorld.Java
  • src/test/Java/example/HelloWorldTest.Java
  • src/test/resources/logback-test.xml
27
michael

Sie können Build-Konfigurationsfelder erstellen, die während des Builds über Systemumgebungsvariablen überschrieben werden können:

Beim Entwickeln wird Fallback verwendet. Sie können die Variable jedoch überschreiben, wenn Sie den Build mit Jenkins oder einem anderen Tool ausführen.

In Ihrer App build.gradle :

buildTypes {
        def serverUrl =  '\"' + (System.getenv("SERVER_URL")?: "http://default.fallback.url.com")+'\"'
        debug{
            buildConfigField "String", "SERVER_URL", serverUrl
        }
        release {
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-Android.txt'), 'proguard-rules.pro'
            buildConfigField "String", "SERVER_URL", serverUrl
        }
    } 

Die Variable wird als BuildConfig.SERVER_URL verfügbar sein.

12
Boris Treukhov

die Antwort von rciovati ist völlig korrekt. Ich wollte nur ein weiteres Wort hinzufügen, das Sie auch für jeden Build-Typ innerhalb des Standard-Konfigurationsabschnitts Ihres Build.gradle-Objekts erstellen können. Das würde so aussehen:

Android {
    defaultConfig {
        buildConfigField "String", "APP_NAME", "\"APP_NAME\""
    }
}

Dadurch haben Sie Zugriff auf durch

BuildConfig.App_NAME

Ich wollte nur dieses Szenario notieren, wenn Sie eine gemeinsame Konfiguration wünschen.

3
s.pike

Ich verwende diesen Code und arbeite sehr gut.

def baseUrl = '\"http://patelwala.com/myapi/"'
def googleServerKey = '\"87171841097-opu71rk2ps35ibv96ud57g3ktto6ioio.apps.googleusercontent.com"'
Android {
  buildTypes {
  release {
        minifyEnabled true
        proguardFiles getDefaultProguardFile('proguard-Android.txt'), 'proguard-rules.pro'
        buildConfigField 'String', 'BASE_URL', baseUrl
        buildConfigField 'String', 'web_client_id', googleServerKey
    }
    releasedebug {
        initWith debug
        buildConfigField 'String', 'BASE_URL', baseUrl
        buildConfigField 'String', 'web_client_id' ,googleServerKey
    }
    debug {

        buildConfigField 'String', 'BASE_URL', baseUrl
        buildConfigField 'String', 'web_client_id', googleServerKey
    }
 }
}

}

1
Hits sapra

Wie können Sie das String-Ergebnis der Funktion in buildConfigField einfügen

Hier ein Beispiel für das Erstellungsdatum in einem für Menschen lesbaren Format:

def getDate() {
    return new SimpleDateFormat("dd MMMM yyyy", new Locale("ru")).format(new Date())
}

def buildDate = getDate()

defaultConfig {
    buildConfigField "String", "BUILD_DATE", "\"$buildDate\""
}
0
anil

Keine der obigen Antworten gab mir Richtlinien, so dass ich mich zwei Stunden lang mit Groovy-Methoden auseinandersetzen musste.

Ich wollte in der Lage sein, gegen eine Produktion, einen Sandkasten und ein lokales Umfeld vorzugehen. Da ich faul bin, wollte ich die URL nur an einer Stelle ändern. Folgendes habe ich mir ausgedacht:

 flavorDimensions 'environment'
    productFlavors {
        production {
            def SERVER_Host = "evil-company.com"
            buildConfigField 'String', 'API_Host', "\"${SERVER_Host}\""
            buildConfigField 'String', 'API_URL', "\"https://${SERVER_Host}/api/v1/\""
            buildConfigField 'String', 'WEB_URL', "\"https://${SERVER_Host}/\""
            dimension 'environment'
        }
        rickard {
            def LOCAL_Host = "192.168.1.107"
            buildConfigField 'String', 'API_Host', "\"${LOCAL_Host}\""
            buildConfigField 'String', 'API_URL', "\"https://${LOCAL_Host}/api/v1/\""
            buildConfigField 'String', 'WEB_URL', "\"https://${LOCAL_Host}/\""
            applicationIdSuffix ".dev"
        }
    }

Alternative Syntax, da Sie in Groovy-Methoden nur ${variable} mit doppelten Anführungszeichen verwenden können.

    rickard {
        def LOCAL_Host = "192.168.1.107"
        buildConfigField 'String', 'API_Host', '"' + LOCAL_Host + '"'
        buildConfigField 'String', 'API_URL', '"https://' + LOCAL_Host + '/api/v1/"'
        buildConfigField 'String', 'WEB_URL', '"https://' + LOCAL_Host + '"'
        applicationIdSuffix ".dev"
    }

Was für mich schwer zu verstehen war, war, dass Strings als von Anführungszeichen umgebene Strings deklariert werden müssen. Aufgrund dieser Einschränkung konnte ich die Referenz API_Host nicht direkt verwenden, was ich eigentlich wollte.

0

Ich benutze

buildTypes.each {
    it.buildConfigField 'String', 'GoogleMapsApiKey', "\"$System.env.GoogleMapsApiKey\""
}

Es basiert auf Dennis 'Antwort bezieht sich jedoch auf eine Umgebungsvariable.

0
Marc