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?
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.
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);
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
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.
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.
Open the local.properties in your project level directory, and then add your property like the following example:
sdk.dir=MY_SDK_DIR
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", "")
Save the files and sync your project with Gradle.
Retrive your string using the following code
getString(R.string.sdk_dir);
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).
I think it's more elegant way.
println "${android.getSdkDirectory().getAbsolutePath()}"
it works on android gradle 1.5.0 .
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 you can also do this:
import com.android.build.gradle.internal.cxx.configure.gradleLocalProperties
// ...
val properties = gradleLocalProperties(rootDir)
val myProp = properties["propName"]
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"))
}
}
}
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
Related
i'm using game engine (Cocos creator) and now I need migrate to Billing v4. When doing, I need support on old device that I need upgrade Gradle Plugin to version 4, then gradle need to migrate from base-feature to dynamic-feature to work, but have some problem need to resolve.
The original Gradle script:
android.featureVariants.all { variant ->
// delete previous files first
delete "${buildDir}/intermediates/merged_assets/"
variant.mergeAssets.doLast {
def sourceDir = "${buildDir}/../../../../.."
copy {
from "${sourceDir}"
include "assets/**"
include "src/**"
include "jsb-adapter/**"
into outputDir
}
copy {
from "${sourceDir}/main.js"
from "${sourceDir}/project.json"
into outputDir
}
}
}
How can I fix the error android.featureVariants properties not found
The build.gradle had migrated from base feature to dymanic feature by
Remove: apply plugin: 'com.android.feature' and change to apply plugin: 'com.android.dynamic-feature' and something at this guide: https://developer.android.com/topic/google-play-instant/feature-module-migration
I am building a Gradle Plugin that should generate both flavorDimensions and productFlavors on Android. Everything works fine when this plugin is being applied directly to the Android module. My goal however is to apply this plugin to another module within the same project as the Android module. Currently this does not work due to a AgpDslLockedException being thrown during Gradle Sync.
My plugin is implemented as follows:
class MyPlugin : Plugin<Project> {
override fun apply(project: Project) {
// Traverse whole project tree to find Android project
project.rootProject.subprojects.forEach { subproject ->
val android = subproject.extensions.findByName("android") as? AppExtension ?: return#forEach
// throws AgpDslLockedException when being applied to other module than android
android.flavorDimensions.add("dimension")
android.productFlavors.create("flavor") { it.dimension = "dimension" }
}
}
A minimal client for the Gradle Plugin could be structured as follows:
- android
- build.gradle
- other
- build.gradle
- settings.gradle
// android/build.gradle
plugins {
id 'com.android.application'
// MyPlugin would work if being applied here
}
android {
// Neither flavorDimensions nor productFlavors are declared as they should be generated by MyPlugin
}
// other/build.gradle
plugins {
// MyPlugin does not work due to AgpDslLockedException being thrown
}
// settings.gradle
include(":android")
include(":other")
The AgpDslLockedException:
It is too late to modify flavorDimensions.
It has already been read to configure this project.
Consider either moving this call to be during evaluation, or using the variant API.
Am I missing something or is there another way to generate flavorDimensions and productFlavors from a third-party build.gradle file?
So far I have tried adding the flavorDimension and creating the productFlavor on project.beforeEvaluate/afterEvaluate but to not avail. Maybe there is a lifecycle method I am missing.
Thanks in advance and have a nice day!
I have read the other threads on this but still can't get it to work.
I've added,
def nav_version = "2.3.5"
classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version"
To the Project Gradle, and:
id 'androidx.navigation.safeargs'
To the app Gradle file.
I have:
android.useAndroidX=true
android.enableJetifier=true
in the gradle.properties file
I've followed the tutorials to the letter, adding argument but still I don't get the direction or any other classes generated once I rebuild the project.
What am I missing?
Maybe you are using kotlin (as infered from your tags) and an alternative way is to use the plugin for Safe Args just in Kotlin:
build.gradle (:project):
buildscript {
ext.nav_version = "2.3.5"
dependencies {
classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version"
}
}
build.gradle (:app):
plugins {
id 'androidx.navigation.safeargs.kotlin'
}
Verify:
Kotlin >= 1.4
Android Studio >= 4.2.
Ok, the answer was found, thanks to #anshul:
The problem is not that the files are not generated, they are.
But, the IDE does not find them. As I am using Kotlin, the answer is a bit different from that for Java.
You must add to your app-level Gradle
android {
...
sourceSets {
main {
kotlin {
// srcDirs += 'build/generated/source/navigation-args/'
srcDirs += 'build/generated/source/navigation-args/debug/com/example/navanddata/ui/'
}
}
In my IDE, if you use the first (commented out) line, you get a multitude of folders that appear in your IDE sidebar. But if you go for the second, you must update it to your project name and update it for DBG / REL compilation.
In both cases, you will have to look for the files for a bit as they do not appear where you would expect, rather (in the second option) under a folder called Kotlin are “root level”.
I want to push version tags to my git repository automatically when Jenkins creates a build. But in order to do this I need the version name and version code for the created build artifact.
I'm currently using the following setup to achieve this (it works fine):
Create a Gradle task in the build.
Run a Gradle task that creates a properties file with the version name and version code in it;
Using the EnvInject plugin read/inject the properties file, so that the environment variables are available to use in the current Jenkins job;
The code to generate the version.properties file looks like this:
android.applicationVariants.all { variant ->
def taskName = "createVersionFile" + variant.flavorName.capitalize();
if (tasks.findByPath(taskName) == null) {
tasks.create(name: taskName) {
doLast {
def prop = new Properties()
def propFile = new File("$buildDir/outputs/version.properties");
prop.setProperty('versionname', variant.versionName + '-' + variant.versionCode)
propFile.createNewFile();
prop.store(propFile.newWriter(), null);
}
}
}
}
This works (as mentioned before) but it's a quite unwieldy method, I'm forced to modify the build.gradle file in order for Jenkins to do it's work.
Is there an easier method, possibly without modifying the build.gradle file? Maybe by generating a second build.gradle file which
includes the "version.properties" task?
My build philosophy is that everything should be available by gradle. No matter what automation you want to do with your project. That gives you flexibility to repeat it in any environment and easily setup any CI that just supports command line runs.
So I would add gradle git plugin to your build to manipulate with git (or do it via command line).
Take a look to gradle.properties file. You can define version code and name there. You don't need extra code to get these values in your Android gradle script and git manipulations as parameters. So you can inject them in defaultConfig.
We use a company-wide gradle configuration which is applied to all our gradle projects.
Projects using this config might apply different types of plugins (specificially the plugins java or android & android-library). In order to get the sonarRunner plugin to automatically check the android projects, additional properties have to be applied which are not available for java projects.
Now to the question: How can additional sonarRunner (or other) properties be applied only to projects applying a specific (in this case "android" or "android-library") plugin?
What I have tried so far, but does not work as the AndroidPlugin property is not know in the preparation phase:
plugins.withType(AndroidPlugin) {
sonarRunner {
sonarProperties {
property "sonar.profile", "Android"
...
}
}
}
Sounds like the code is missing an import for the AndroidPlugin class. Alternatively, plugins.withId("android") can be used for current gradle versions or afterEvaluate { if (plugins.hasPlugin("android")) { ... } } for gradle 1.12 and earlier.