138

I have set sdk.dir and ndk.dir in local.properties.

How do I read the values of sdk.dir and ndk.dir in the build.gradle file?

Mahozad
  • 18,032
  • 13
  • 118
  • 133
Vikram
  • 11,885
  • 5
  • 22
  • 16
  • 23
    the real question is: why isn't this built in to the android gradle plugin?!?!?!?! – Armand May 19 '15 at 07:41
  • @Armand: maybe because `local.properties` is in use for Android Studio's own local config, and having another file of the same name might create a little bit of confusion. See https://stackoverflow.com/a/49306091/1587329 below – serv-inc Mar 15 '18 at 17:53
  • 1
    @Armand it's a pity this was not built in 5 years ago, but later this was added: `android.getSdkDirectory()` simply works. – Alex Cohn Jan 23 '19 at 09:47
  • Related post: [Sign APK without putting keystore info in build.gradle](https://stackoverflow.com/q/20562189/8583692) – Mahozad Apr 15 '22 at 14:01
  • Does this answer your question? [Gradle - Include Properties File](https://stackoverflow.com/questions/11749384/gradle-include-properties-file) – Mahozad Apr 20 '22 at 05:29

10 Answers10

172

You can do that in this way:

Properties properties = new Properties()
properties.load(project.rootProject.file('local.properties').newDataInputStream())
def sdkDir = properties.getProperty('sdk.dir')
def ndkDir = properties.getProperty('ndk.dir')

Use project.rootProject if you are reading the properties file in a sub-project build.gradle:

.
├── app
│   ├── build.gradle <-- You are reading the local.properties in this gradle build file
│   └── src
├── build.gradle
├── gradle
├── gradlew
├── gradlew.bat
├── settings.gradle
└── local.properties

In case the properties file is in the same sub-project directory you can use just project.

rciovati
  • 27,603
  • 6
  • 82
  • 101
  • 3
    What it is "project.rootProject"? – AlexBalo Jul 28 '14 at 09:12
  • 1
    Added a brief explanation – rciovati Jul 28 '14 at 12:09
  • What do you mean with project? My ide is giving me an error. How do I get project path. – AlexBalo Jul 28 '14 at 12:12
  • Inside a `build.gradle` file `project` is a variabile which refers to the current project. If you have strange errors ask a new question. – rciovati Jul 28 '14 at 12:17
  • If I copy your code inside a utility class in app/src/main/java/my_package_name/Utils.java it cannot be resolved. How can I read local.properties from a Utility class? – AlexBalo Jul 28 '14 at 13:14
  • As I said it would be better if you ask your own question. BTW you should read the local.properties file in the `build.gradle` and generate one or more `BuildConfig` fields. http://stackoverflow.com/questions/17197636/is-it-possible-to-declare-a-variable-in-gradle-usable-in-java/17201265#17201265 – rciovati Jul 28 '14 at 13:39
  • I want to write a library that reads custom values declared in a property file by the user of the library. These values are different depending on who is using the library. It's the first time I'm facing this situation and I'm trying to figure out how to do that... – AlexBalo Jul 28 '14 at 13:43
  • What if I don't know the latest version of sdkdir build-tools, and I want gradle to handle it for me? For example, finding **sdk.ri/build-tools/24.0.0/** – IgorGanapolsky Jul 22 '16 at 19:50
55

local.properties

default.account.iccid=123

build.gradle -

def Properties properties = new Properties()
properties.load(project.rootProject.file("local.properties").newDataInputStream())

defaultConfig {

    resValue "string", "default_account_iccid", properties.getProperty("default.account.iccid", "")
}

and in code you get it as other string from Resources -

resources.getString(R.string.default_account_iccid);
Dmitrijs
  • 1,333
  • 1
  • 14
  • 20
  • 2
    This is the correct answer. How is it not selected? The chosen answer doesn't even provide a solution?? – Joshua Pinter Aug 11 '19 at 15:52
  • Cannot resolve symbol 'Properties' in my case – Aman Verma Mar 05 '21 at 04:35
  • OK, could I put `Properties` declaration in `defaultConfig`? Why do people put it outside of `defaultConfig` scope? – deadfish May 10 '21 at 07:46
  • If I try to access this variable in manifest file, it won't build (says resource not found) – Starwave Oct 23 '21 at 17:34
  • Caused by: groovy.lang.MissingMethodException: No signature of method: java.util.HashMap.load() is applicable for argument types: (DataInputStream) values: [java.io.DataInputStream@3e893459] Possible solutions: clear(), clear(), clone(), sort(), find(), find(groovy.lang.Closure) – straya Feb 14 '23 at 04:12
17

now it's more simple with the new google plugin

1- add your property

sdk_dir="sdk dir"

2- add the plugin (Groovy) this in top-level (project level)

buildscript {
 dependencies {
     classpath "com.google.android.libraries.mapsplatform.secrets-gradle-plugin:secrets-gradle-plugin:1.3.0"
 }
}

and in your app Gradle

plugins {
    id 'com.google.android.libraries.mapsplatform.secrets-gradle-plugin'
}

3- build your project 4- access it like this

BuildConfig.sdk_dir
Sattar
  • 2,453
  • 2
  • 33
  • 47
10

Although @rciovati's answer is certainly correct, there is also an alternative way of reading the values for sdk.dir and ndk.dir.

As pointed out in this blog entry by Gaku Ueda (Getting ndk directory) the BasePlugin class offers methods for getNdkFolder() and getSdkFolder():

def ndkDir = project.plugins.findPlugin('com.android.application').getNdkFolder()
def sdkDir = project.plugins.findPlugin('com.android.application').getSdkFolder()

Note: You may have to change com.android.applicationto com.android.libraryif you are building a library

This is maybe a more elegant way of reading the folder values. Although it has to be said that the answer provided by @rciovati is more flexible, as one could read any value in the properties file.

super-qua
  • 3,148
  • 1
  • 23
  • 30
  • 1
    For Gradle 1.1.0 you nee to use `plugins.getPlugin('com.android.library').sdkHandler.getNdkFolder()` as can be seen here: http://stackoverflow.com/questions/28615439/android-gradle-plugin-1-1-0-getndkfolder-not-found-anymore-any-replacement – Stephan Apr 16 '15 at 08:40
  • 1
    Broken again with the shift to "experimental" plugin :( – Alex Cohn Sep 17 '15 at 15:40
10

Adding the property

The following Gradle technique shows you how to store a property in your local.properties file so that it can be securely referenced by your app.

  1. Open the local.properties in your project level directory, and then add your property like the following example:
sdk.dir=MY_SDK_DIR
  1. In your app-level build.gradle file, add this code in the defaultConfig element. This allows Android Studio to read the sdk.dir property from the local.properties file at build time and then inject the build variable into your res/gradleResVlues.xml.
Properties properties = new Properties()
if (rootProject.file("local.properties").exists()) {
    properties.load(rootProject.file("local.properties").newDataInputStream())
}

resValue "string", "sdk_dir", properties.getProperty("sdk.dir", "")
  1. Save the files and sync your project with Gradle.
  2. Retrive your string using the following code
getString(R.string.sdk_dir);
G. Ciardini
  • 1,210
  • 1
  • 17
  • 32
  • 1
    How does this work with versioning systems? You would not want to create commits and pull requests everytime that you wanted to change a property – TheRealChx101 Dec 19 '21 at 15:19
  • In the same way you use the other method – G. Ciardini Dec 19 '21 at 22:14
  • What other method? Would this resolve the values during build without touching the source code? – TheRealChx101 Dec 19 '21 at 23:02
  • The real question is: is local.properties is included in your repository? If so, does it really have to be? If still yes, you will need to version any changes to your properties file. – G. Ciardini Dec 20 '21 at 14:07
  • No. It is not, as it should be. I saw a method (which I can't find) that loads properties from an external properties file and adds them to ```buildConfigField```, which end up in ```BuildConfig.java``` as static final fields. I thought that was quicker than dealing with XML reading etc. – TheRealChx101 Dec 20 '21 at 15:17
9

The answer that loads local.properties manually above obviously works, and the next one that requires you to know which plugin was applied should work as well.

These approaches might be a little better for some since they are more generic because they work regardless of whether you're using the Application, Test, or Library plugin. These snippets also give you full programmatic access to all of the Android plugin config (Product Flavors, Build Tools version, and much more):

If you need access in a build.gradle file that is using the Android Gradle Plugin simply access the Android DSL directly as it's now available directly:

project.android.sdkDirectory

The longer form (below) of this is handy if you're creating custom Gradle Tasks classes or Plugins or simply want to view which properties are available.

// def is preferred to prevent having to add a build dependency.
def androidPluginExtension = project.getExtensions().getByName("android");

// List available properties.
androidPluginExtension.properties.each { Object key, Object value ->
    logger.info("Extension prop: ${key} ${value}")
}
String sdkDir = androidPluginExtension.getProperties().get("sdkDirectory");
System.out.println("Using sdk dir: ${sdkDir}");

At the time of this posting there is also a handy adbExe property that is definitely worth noting.

This code has to execute AFTER the Android Gradle Plugin is configured per the Gradle livecycle. Typically this means you put it in the execute method of a Task or place it AFTER the android DSL declaration in an Android app/libraries' build.gradle file).

These snippets also come with the caveat that as you upgrade Android Gradle Plugin versions these properties can change as the plugin is developed so simply test when moving between versions of the Gradle and Android Gradle plugin as well as Android Studio (sometimes a new version of Android Studio requires a new version of the Android Gradle Plugin).

PaulR
  • 3,223
  • 1
  • 21
  • 32
8

This is for Kotlin DSL (build.gradle.kts):

import java.util.*
// ...

val properties = Properties().apply {
    load(rootProject.file("local.properties").reader())
}
val myProp = properties["propName"]

In Android projects (where you have applied the android plugin) you can also do this:

import com.android.build.gradle.internal.cxx.configure.gradleLocalProperties
// ...

val properties = gradleLocalProperties(rootDir)
val myProp = properties["propName"]
Mahozad
  • 18,032
  • 13
  • 118
  • 133
4

I think it's more elegant way.

println "${android.getSdkDirectory().getAbsolutePath()}"

it works on android gradle 1.5.0 .

Victor Choy
  • 4,006
  • 28
  • 35
0

in kotlin dsl :

build.gradle file

val properties = Properties()
properties.load(project.rootProject.file("local.properties").reader())
...
android{
   buildTypes {


    debug {
        buildConfigField("String", "SOMETHING", properties.getProperty("something"))
      }
   }
}
Majid Sadeghi
  • 180
  • 11
0

build.gradle (:app)

sourceSets {
    main {
        resources {
            srcDirs = ["src/main/resources"]
        }
    }
}

app/src/main/resources/yourfile.properties

test_feature=test-of-feature

YourClass.kt

fun getProperty(key: String): String? {
    val properties = Properties()
    val propertiesFile = Thread.currentThread().contextClassLoader.getResourceAsStream("yourfile.properties")
    properties.load(propertiesFile)
    return properties.getProperty(key)
}

getProperty("test_feature")

GL

Braian Coronel
  • 22,105
  • 4
  • 57
  • 62