Có thể khai báo một biến trong Gradle có thể sử dụng được trong Java không?


417

Có thể khai báo một biến trong Gradle có thể sử dụng được trong Java không? Về cơ bản tôi muốn khai báo một số vars trong build.gradle và sau đó lấy nó (rõ ràng) tại thời điểm xây dựng. Giống như các macro tiền xử lý trong C / C ++ ...

Một ví dụ về khai báo sẽ là một cái gì đó như thế ...:

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

Có cách nào để làm một cái gì đó như vậy?

Câu trả lời:


796

Tạo các hằng Java

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

Bạn có thể truy cập chúng với BuildConfig.FOO

Tạo tài nguyên Android

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

Bạn có thể truy cập chúng theo cách thông thường với @string/app_namehoặcR.string.app_name


4
Không, nhưng bạn cũng có thể tạo tài nguyên. Tôi đã cập nhật câu trả lời của mình bao gồm cả điều đó.
rciovati

2
Thật sự cảm ơn. Một cái gì đó mà tôi đã phát hiện ra là bạn có thể chỉ định các thư mục thay thế cho các bản dựng gỡ lỗi và phát hành. Trong <project>/src/, nếu bạn tạo tệp debug/res/values/strings.xmlvà tệp khác release/res/values/strings.xml, bạn có thể đặt tài nguyên cho gỡ lỗi và phát hành bản dựng theo cách sạch hơn một chút.
bỏ

6
@rciovati có thể đạt được điều tương tự mà không cần androidplugin không? tức là chỉ dùng apply plugin java? cảm ơn!
Zennichimaro

2
Làm cách nào tôi có thể tạo các hằng số cho các hương vị xây dựng khác nhau và các kiểu xây dựng?
Jakob Eriksson

3
Có thể đặt một trong các trường, như năm hiện tại và cũng có thể tiếp cận nó bất kể loại xây dựng nào được chọn (phát hành, gỡ lỗi, ...) không?
nhà phát triển Android

102

Một ví dụ về việc sử dụng Khóa ứng dụng Api trong ứng dụng Android (Java và XML)

gradle.properies

AppKey="XXXX-XXXX"

xây dựng. nâng cấp

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

Sử dụng trong mã java

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

BuildConfig.APP_KEY_1

Sử dụng trong mã xml

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

1
Nếu tôi có thể thêm, biến này cũng có thể được truyền vào thời gian chạy. Chủ yếu là hữu ích khi chạy thử nghiệm với cấu hình khác nhau. Sử dụng./gradlew -PAppKey="1234" testdebug
Jaswanth Manigundan

1
Để khai báo cùng một thuộc tính cho từng loại bản dựng, bạn cũng có thể sử dụng defaultConfigkhối: stackoverflow.com/a/51521146/321354
rciovati

Bạn có một ví dụ hoạt động của phần XML không? trong kho Github hoặc Gist. Nó không hoạt động với tôi, tôi không thể tham khảo@string/APP_KEY_2
voghDev

32

Ví dụ sử dụng các thuộc tính hệ thống, được đặt trong build.gradle, đọc từ ứng dụng Java (theo dõi từ câu hỏi trong các bình luận):

Về cơ bản, sử dụng testtác vụ trong build.gradle, với phương thức tác vụ thử nghiệm systemPropertythiết lập một thuộc tính hệ thống được truyền trong thời gian chạy:

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

Và đây là phần còn lại của mã mẫu (mà bạn có thể suy ra, nhưng dù sao cũng được bao gồm ở đây): nó có một thuộc tính hệ thống MY-VAR1, dự kiến ​​vào thời gian chạy được đặt thành 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: nếu MY-VARkhông được đặt, kiểm tra sẽ thất bại:

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

Chạy (lưu ý: kiểm tra đang qua):

$ 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

Tôi đã thấy rằng phần khó khăn thực sự nhận được đầu ra từ cấp độ ... Vì vậy, ghi nhật ký được định cấu hình ở đây (slf4j + logback) và tệp nhật ký hiển thị kết quả (cách khác, chạy gradle --info cleanTest test; cũng có các thuộc tính được xuất ra Bảng điều khiển, nhưng, bạn biết, tại sao):

$ 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

Nếu bạn nhận xét " systemProperty..." (mà, btw, chỉ hoạt động trong một testnhiệm vụ), thì:

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

Để hoàn thiện, đây là cấu hình 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> 

Các tập tin:

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

Lưu ý rằng đây là câu trả lời trực tiếp cho một nhận xét trong câu trả lời được chấp nhận, vì vậy nó sai lệch một chút so với câu hỏi ban đầu.
michael

2
Tôi có thể bằng cách nào đó có được version = '0.0.1-SNAPSHOT'thông qua mã Java?
Nom1fan

SystemProperty chỉ khả dụng trong nhiệm vụ kiểm tra lớp :(. Mọi người có biết cách nào khác để có giá trị biến cấp trong mã java của thư viện không?
Stoycho Andreev

systemPropertythực sự chỉ có ý nghĩa cho việc thử nghiệm, vì vậy tôi hiểu tại sao họ lại làm theo cách này (nó không phải là một sự giám sát), nhưng đồng thời, tôi cũng đã thử sử dụng lớp cho những thứ mà nó không dành cho (như DSL ứng dụng ) để tôi có thể xác định. Cách khác, tôi khuyên bạn chỉ nên tải các thuộc tính từ tệp thuộc tính (hoặc dịch vụ cấu hình, v.v.), vì nếu không ở chế độ "kiểm tra" thì chế độ "sản xuất" & yêu cầu logic ứng dụng. (Dù sao đó cũng là lý thuyết.)
michael

14

Bạn có thể tạo trường cấu hình xây dựng có thể ghi đè thông qua các biến môi trường hệ thống trong quá trình xây dựng:

Dự phòng được sử dụng trong khi phát triển, nhưng bạn có thể ghi đè biến khi bạn chạy bản dựng trên Jenkins hoặc công cụ khác.

Trong ứng dụng build.gradle của bạn :

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

Biến sẽ có sẵn như là BuildConfig.SERVER_URL .


1
Cảm ơn bạn cho câu trả lời này! Tôi đã cố gắng tìm ra cách để có thể nhìn thấy một biến môi trường từ trong tệp .java của Android và điều này đã hoạt động rất tốt!
Wayne Piekarski

Nếu bạn muốn xác định biến boolean, bạn nên sử dụng buildConfigField "boolean", "CI_BUILD", "$ {isCi}" hoặc buildConfigField "boolean", "CI_BUILD", "Boolean.parseBoolean (" + '+' "'+") "nếu bạn muốn thoát khỏi kiểm tra lint ( stackoverflow.com/questions/29889098/ mẹo )
android_dev

5

Câu trả lời của rciovati hoàn toàn chính xác Tôi chỉ muốn thêm một mẩu tin nữa mà bạn cũng có thể tạo các biến cho mọi loại bản dựng trong phần cấu hình mặc định của build.gradle của bạn. Điều này sẽ trông như thế này:

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

Điều này sẽ cho phép bạn có quyền truy cập thông qua

BuildConfig.App_NAME

Chỉ muốn ghi chú lại kịch bản này nếu bạn muốn một cấu hình chung.


3

Tôi đang sử dụng mã này và làm việc rất tốt.

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

}


Sẽ thật tuyệt nếu bạn chỉ định những gì bạn đã sửa đổi và tác động của nó, dẫn đến giải pháp làm việc của bạn.
Badgy

2

Làm thế nào bạn có thể chèn kết quả Chuỗi của hàm vào buildConfigField

Dưới đây là ví dụ về ngày xây dựng trong bộ định dạng có thể đọc được của con ngườ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

Tôi đang sử dụng

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

Nó dựa trên câu trả lời của Dennis nhưng lấy nó từ một biến môi trường.


0

Không có câu trả lời nào ở trên đưa ra cho tôi bất kỳ hướng dẫn nào nên tôi phải dành hai giờ để tìm hiểu về Phương pháp Groovy.

Tôi muốn có thể đi ngược lại với môi trường sản xuất, hộp cát và môi trường địa phương. Vì tôi lười biếng, tôi chỉ muốn thay đổi URL ở một nơi. Đây là những gì tôi đã đưa ra:

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

Cú pháp thay thế, bởi vì bạn chỉ có thể sử dụng ${variable}với dấu ngoặc kép trong Phương thức 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"
    }

Điều khó khăn đối với tôi là các chuỗi cần phải được khai báo là các chuỗi được bao quanh bởi các dấu ngoặc kép. Do hạn chế đó, tôi không thể sử dụng tài liệu tham khảo API_HOSTtrực tiếp, đó là điều tôi muốn làm ngay từ đầu.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.