Apakah mungkin untuk mendeklarasikan variabel dalam Gradle yang dapat digunakan di Jawa?

417

Apakah mungkin untuk mendeklarasikan variabel dalam Gradle yang dapat digunakan di Jawa? Pada dasarnya saya ingin mendeklarasikan beberapa vars di build.gradle dan kemudian mendapatkannya (jelas) pada waktu build. Sama seperti makro pra-prosesor di C / C ++ ...

Contoh deklarasi akan seperti itu ...:

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

Apakah ada cara untuk melakukan hal seperti itu?

klefevre
sumber

Jawaban:

796

Hasilkan Konstanta Jawa

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

Anda dapat mengaksesnya dengan BuildConfig.FOO

Hasilkan sumber daya Android

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

Anda dapat mengaksesnya dengan cara biasa dengan @string/app_nameatauR.string.app_name

rciovati
sumber
4
Tidak, tetapi Anda dapat menghasilkan sumber daya juga. Saya telah memperbarui jawaban saya termasuk itu.
rciovati
2
Keren terima kasih. Sesuatu yang saya temukan dengan baik adalah Anda dapat menentukan direktori alternatif untuk debug dan rilis build. Di <project>/src/, jika Anda membuat file debug/res/values/strings.xmldan file lain release/res/values/strings.xml, Anda bisa mengatur sumber daya untuk debug dan rilis build dengan cara yang sedikit lebih bersih juga.
elimirks
6
@rciovati apakah mungkin untuk mencapai hal yang sama tanpa androidplugin? yaitu hanya menggunakan apply plugin java? Terima kasih!
Zennichimaro
2
Bagaimana saya bisa membuat konstanta untuk citarasa cita rasa berbeda dan tipe pembangun?
Jakob Eriksson
3
Apakah mungkin untuk menetapkan salah satu bidang, sebagai tahun saat ini, dan juga mencapainya tidak peduli apa pun tipe bangunan yang dipilih (rilis, debug, ...)?
pengembang android
102

Contoh penggunaan Kunci Aplikasi Api di aplikasi Android (Java dan XML)

properti

AppKey="XXXX-XXXX"

build.gradle

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

Penggunaan dalam kode java

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

BuildConfig.APP_KEY_1

Penggunaan dalam kode xml

<data android:scheme="@string/APP_KEY_2" />
Denis
sumber
1
Jika saya dapat menambahkan, variabel ini dapat dikirimkan pada saat runtime juga. Paling berguna saat menjalankan tes dengan konfigurasi berbeda. Gunakan./gradlew -PAppKey="1234" testdebug
Jaswanth Manigundan
1
Untuk mendeklarasikan properti yang sama untuk setiap tipe build, Anda dapat menggunakan defaultConfigblok juga: stackoverflow.com/a/51521146/321354
rciovati
Apakah Anda memiliki contoh kerja bagian XML? dalam repositori atau Gist Github. Ini tidak berfungsi untuk saya, saya tidak bisa referensi@string/APP_KEY_2
voghDev
32

Contoh menggunakan properti sistem, ditetapkan dalam build.gradle, baca dari aplikasi Java (menindaklanjuti pertanyaan di komentar):

Pada dasarnya, menggunakan testtugas dalam build.gradle, dengan metode tugas uji systemPropertymenetapkan properti sistem yang dilewati saat runtime:

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

Dan inilah sisa kode sampel (yang mungkin dapat Anda simpulkan, tetapi sudah termasuk di sini): kode ini mendapatkan properti sistem MY-VAR1, yang diharapkan pada saat run-time diatur ke 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: jika MY-VARtidak disetel, tes harus gagal:

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

Jalankan (catatan: tes lulus):

$ 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

Saya telah menemukan bahwa bagian yang rumit sebenarnya mendapatkan output dari gradle ... Jadi, logging dikonfigurasi di sini (slf4j + logback), dan file log menunjukkan hasilnya (sebagai alternatif, jalankan gradle --info cleanTest test; ada juga properti yang mendapatkan stdout untuk konsol, tetapi, Anda tahu, mengapa):

$ 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

Jika Anda berkomentar " systemProperty..." (yang, btw, hanya berfungsi dalam testtugas), maka:

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

Untuk kelengkapan, berikut adalah konfigurasi logback ( 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> 

File:

  • build.gradle
  • src/main/java/example/HelloWorld.java
  • src/test/java/example/HelloWorldTest.java
  • src/test/resources/logback-test.xml
michael
sumber
Perhatikan bahwa ini adalah respons langsung terhadap komentar dalam jawaban yang diterima, sehingga sedikit menyimpang dari pertanyaan awal.
michael
2
Bisakah saya mendapatkan version = '0.0.1-SNAPSHOT'melalui kode Java?
Nom1fan
SystemProperty hanya tersedia dalam tugas tes gradle :(. Adakah yang tahu cara lain untuk memiliki nilai variabel gradle dalam kode java perpustakaan?
Stoycho Andreev
systemPropertybenar-benar hanya masuk akal untuk pengujian, jadi saya melihat mengapa mereka melakukannya dengan cara ini (ini bukan pengawasan), tetapi pada saat yang sama, saya juga mencoba menggunakan gradle untuk hal-hal yang tidak dimaksudkan untuknya (seperti aplikasi DSL ) jadi saya bisa mengidentifikasi. Sebagai alternatif, saya sarankan hanya memuat properti dari file properti (atau layanan konfigurasi, dll), karena jika tidak dalam mode "test", maka itu mode "produksi" & memerlukan logika aplikasi. (Begitulah teorinya.)
michael
14

Anda dapat membuat bidang konfigurasi build yang dapat ditimpa melalui variabel lingkungan sistem selama proses:

Fallback digunakan saat mengembangkan, tetapi Anda bisa mengganti variabel ketika Anda menjalankan build di Jenkins atau alat lain.

Di build.gradle aplikasi Anda :

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

Variabel akan tersedia sebagai BuildConfig.SERVER_URL.

Boris Treukhov
sumber
1
Terima kasih atas jawaban ini! Saya telah mencoba mencari cara untuk mendapatkan variabel lingkungan agar terlihat dari dalam file .java Android, dan ini berhasil!
Wayne Piekarski
Jika Anda ingin mendefinisikan variabel boolean, Anda harus menggunakan buildConfigField "boolean", "CI_BUILD", "$ {isCi}" atau buildConfigField "boolean", "CI_BUILD", "Boolean.parseBoolean (" + '"' + isCi + ' "'+") "jika Anda ingin lolos dari pemeriksaan serat ( stackoverflow.com/questions/29889098/… )
android_dev
5

Jawaban rciovati sepenuhnya benar. Saya hanya ingin menambahkan satu berita menarik bahwa Anda juga dapat membuat variabel untuk setiap tipe build di dalam bagian konfigurasi default build.gradle Anda. Ini akan terlihat seperti ini:

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

Ini akan memungkinkan Anda untuk memiliki akses melalui

BuildConfig.App_NAME

Hanya ingin mencatat skenario ini juga jika Anda menginginkan konfigurasi umum.

paku
sumber
3

Saya menggunakan kode ini dan bekerja dengan sangat baik.

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

}

Hitesh sapra
sumber
Akan lebih baik jika Anda menentukan apa yang Anda modifikasi dan apa dampaknya, menghasilkan solusi kerja Anda.
Badgy
2

Bagaimana Anda bisa menyisipkan hasil String fungsi ke buildConfigField

Berikut adalah contoh tanggal pembuatan dalam rangkaian format yang dapat dibaca manusia:

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

def buildDate = getDate()

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

saya menggunakan

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

Ini didasarkan pada jawaban Dennis tetapi mengambilnya dari variabel lingkungan.

Marc
sumber
0

Tidak satu pun dari jawaban di atas yang memberi saya pedoman, jadi saya harus menghabiskan dua jam belajar tentang Metode Groovy.

Saya ingin dapat menentang produksi, kotak pasir, dan lingkungan setempat. Karena saya malas, saya hanya ingin mengubah URL di satu tempat. Inilah yang saya pikirkan:

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

Sintaks alternatif, karena Anda hanya dapat menggunakan ${variable}dengan tanda kutip ganda dalam Metode Groovy.

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

Yang sulit saya pahami adalah bahwa string harus dinyatakan sebagai string yang dikelilingi oleh tanda kutip. Karena pembatasan itu, saya tidak dapat menggunakan referensi API_HOSTsecara langsung, yang ingin saya lakukan sejak awal.

Rickard Elimää
sumber