Gradle'da bir değişkeni Java'da kullanılabilir olarak bildirmek mümkün müdür?


417

Gradle'da bir değişkeni Java'da kullanılabilir olarak bildirmek mümkün müdür? Temel olarak build.gradle'da bazı değişkenler bildirmek ve daha sonra (açıkçası) derleme zamanında almak istiyorum. Tıpkı C / C ++ 'da ön işlemci makroları gibi ...

Deklarasyona örnek olarak şöyle bir şey verilebilir:

android {
    debug {
        A_VAR_RETRIEVABLE_IN_JAVA = 42
    }
    release {
        A_VAR_RETRIEVABLE_IN_JAVA = 42+52
    }
}

Böyle bir şey yapmanın bir yolu var mı?

Yanıtlar:


796

Java Sabitleri Oluşturma

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

Onlara şununla erişebilirsiniz: BuildConfig.FOO

Android kaynakları oluşturma

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

Onlara her zamanki gibi @string/app_nameveyaR.string.app_name


4
Hayır, ancak kaynaklar da oluşturabilirsiniz. Cevabımı da dahil olmak üzere güncelledim.
rciovati

2
Harika, teşekkürler. Ben keşfettim bir şey iyi hata ayıklama ve sürüm yapıları için alternatif dizinler belirtebilirsiniz olmasıdır. Gelen <project>/src/dosyayı oluşturursanız, debug/res/values/strings.xmlve başka bir dosya release/res/values/strings.xml, debug için kaynak ayarlayabilirsiniz ve bırakın biraz daha temiz bir şekilde inşa de.
elimirks

6
@rciovati androideklenti olmadan aynı şeyi elde etmek mümkün mü? yani sadece kullanarak apply plugin java? Teşekkürler!
Zennichimaro

2
Farklı yapı aromaları ve yapı türleri için nasıl sabitler oluşturabilirim?
Jakob Eriksson

3
Alanlardan birini geçerli yıl olarak ayarlamak ve hangi yapı türü seçilirse seçilsin mi (sürüm, hata ayıklama, ...)?
android geliştirici

102

Android uygulamasında Api Uygulama Anahtarı kullanımına bir örnek (Java ve 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
    }
}

Java kodunda kullanım

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

BuildConfig.APP_KEY_1

XML kodunda kullanım

<data android:scheme="@string/APP_KEY_2" />

1
Ekleyebilirsem, bu değişken çalışma zamanında da iletilebilir. Farklı konfigürasyona sahip testler çalıştırırken çoğunlukla yararlıdır. Kullanım./gradlew -PAppKey="1234" testdebug
Jaswanth Manigundan

1
Her yapı türü için aynı özelliği beyan etmek için defaultConfigbloğu da kullanabilirsiniz : stackoverflow.com/a/51521146/321354
rciovati

XML bölümünün çalışan bir örneğiniz var mı? bir Github deposunda veya Gist'te. Benim için çalışmıyor, @string/APP_KEY_2
başvuramıyorum

32

Java uygulamasından okunan build.gradle içinde ayarlanan sistem özelliklerini kullanan örnek (yorumlardaki sorudan sonra):

Temel olarak, içindeki testgörevi kullanarak, build.gradletest görevi yöntemi systemPropertyçalışma zamanında geçirilen bir sistem özelliğini ayarlar:

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

Ve işte örnek kodun geri kalanı (muhtemelen çıkarımda bulunabilirsiniz, ancak yine de buraya dahil edilmiştir): MY-VAR1çalışma zamanında ayarlanması beklenen bir sistem özelliği alır VALUE-TEST:

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

Testcase: MY-VARayarlanmamışsa test başarısız olmalıdır:

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

Çalıştır (not: test geçiyor):

$ 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

Zor bölüm aslında çıktıyı sınıftan alıyor bulduk ... Yani, günlük burada yapılandırılır (slf4j + logback) ve günlük dosyası sonuçları gösterir (alternatif olarak, çalıştırın gradle --info cleanTest test; stdout olsun özellikleri de vardır konsol, ancak, nedenini biliyorsunuz):

$ 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

" systemProperty..." (Btw yalnızca bir testgörevde çalışır ) yorum yaparsanız , o zaman:

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

Tamlık için logback config ( src/test/resources/logback-test.xml):

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

Dosyalar:

  • build.gradle
  • src/main/java/example/HelloWorld.java
  • src/test/java/example/HelloWorldTest.java
  • src/test/resources/logback-test.xml

Bunun, kabul edilen yanıttaki bir yoruma doğrudan bir yanıt olduğunu unutmayın, bu nedenle orijinal sorudan biraz farklıdır.
michael

2
Bir şekilde version = '0.0.1-SNAPSHOT'Java kodu ile alabilir miyim ?
Nom1fan

SystemProperty sadece not testi görevinde kullanılabilir :(. Herkes kütüphanenin java kodunda gradle değişken değerine sahip olmanın başka bir yolunu biliyor mu?
Stoycho Andreev

systemPropertygerçekten sadece test için mantıklı, bu yüzden neden bu şekilde yaptıklarını görüyorum (bu bir gözetim değil), ama aynı zamanda amaçlanmadığı şeyler için de gradle kullanmaya çalıştım (DSL gibi bir uygulama gibi) ) tanımlayabiliyorum. Alternatif olarak, yalnızca bir özellik dosyasından (veya yapılandırma hizmetinden vb.) Özelliklerin yüklenmesini öneriyorum, çünkü "test" modunda değilse, o zaman "üretim" modudur ve uygulama mantığı gerektirir. (Bu teori zaten.)
michael

14

Derleme sırasında sistem ortamı değişkenleri üzerinden geçersiz kılınabilen derleme yapılandırma alanı oluşturabilirsiniz:

Yedekleme geliştirilirken kullanılır, ancak oluşturmayı Jenkins veya başka bir araçta çalıştırdığınızda değişkeni geçersiz kılabilirsiniz.

Uygulamanız içinde 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
        }
    } 

Değişken olarak bulunacaktır BuildConfig.SERVER_URL.


1
Bu cevap için teşekkürler! Bir ortam değişkeninin bir Android .java dosyasından görünür olmasını nasıl sağlamaya çalışıyorum ve bu harika çalıştı!
Wayne Piekarski

Boolean değişkenini tanımlamak istiyorsanız, buildConfigField "boolean", "CI_BUILD", "$ {isCi}" veya buildConfigField "boolean", "CI_BUILD", "Boolean.parseBoolean (" + '"' + isCi + ' Tiftik kontrollerinden kaçmak istiyorsanız "'+") "( stackoverflow.com/questions/29889098/… )
android_dev

5

rciovati'nin yanıtı tamamen doğru Sadece build.gradle varsayılan yapılandırma bölümünde her yapı türü için değişkenler oluşturabilirsiniz bir tane daha tidbit eklemek istedim. Bu şöyle görünecektir:

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

Bu, üzerinden erişime sahip olmanızı sağlar

BuildConfig.App_NAME

Ortak bir yapılandırma istiyorsanız bu senaryoyu da not etmek istedim.


3

Bu kodu kullanıyorum ve çok iyi çalışıyorum.

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

}


Neyi değiştirdiğinizi ve bunun ne gibi bir etkisi olduğunu belirtirseniz, çalışma çözümünüzle sonuçlanırsınız.
Badgy

2

Fonksiyonun String sonucunu buildConfigField içine nasıl ekleyebilirsiniz?

İnsan tarafından okunabilir biçim kümesinde derleme tarihi örneği:

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

def buildDate = getDate()

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

1

kullanıyorum

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

Bu, Dennis'in cevabına dayanıyor ama bir çevre değişkeninden alıyor.


0

Yukarıdaki cevapların hiçbiri bana herhangi bir yönerge vermedi, bu yüzden Groovy Metodlarını öğrenmek için iki saat harcamak zorunda kaldım.

Bir prodüksiyon, sanal alan ve yerel ortama karşı çıkmak istedim. Tembel olduğum için, URL'yi yalnızca bir yerde değiştirmek istedim. İşte ben geldim:

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

Alternatif sözdizimi, çünkü ${variable}Groovy Yöntemlerinde yalnızca çift ​​tırnaklarla kullanabilirsiniz .

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

Benim için zor olan şey, dizelerin tırnaklarla çevrili dizeler olarak beyan edilmesi gerektiğiydi. Bu kısıtlama nedeniyle, referansı API_HOSTdoğrudan kullanamadım , bu ilk etapta yapmak istediğim şeydi.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.