I have an error when trying to use Kotlin DSL for my gradle files.
In build.gradle(app) I have a function to retrieve an api key stored in an
file keys.properties, the function in Groovy is the following:
// Retrieve key api
def getApiKey() {
def keysFile = file("keys.properties")
def keysProperties = new Properties()
keysProperties.load(new FileInputStream(keysFile))
def apiKey = keysProperties['API_KEY']
return apiKey
}
When switching to Kotlin DSL I naively changed the function as follow:
// Retrieve key for TMDB api
fun getApiKey() {
val keysFile = file("keys.properties")
val keysProperties = Properties()
keysProperties.load(FileInputStream(keysFile))
val apiKey = keysProperties["API_KEY"]
return apiKey
}
The build then returns the following error:
.../app/build.gradle.kts:13:26: Unresolved reference: Properties
Does anyone know how to fix that?
Edit
as suggested by #bam bam, adding an import import java.util.Properties solved the problems.. But other problems came, see this question
did you import class? add import java.util.Properties on top of your build.gradle.kts
Related
After upgrading the lifecycle dependency from 2.6.0-alpha04 to 2.6.0-beta01 I got Unresolved reference: Transformations and it can't import androidx.lifecycle.Transformations class.
import androidx.lifecycle.Transformations
...
var myList: LiveData<List<Bookmark>> = Transformations.switchMap(
bookMarkType
) { input: Int? ->
when (input) {
ARTICLE_BOOKMARK -> return#switchMap repository.articleBookmarks
WEBSITE_BOOKMARK -> return#switchMap repository.websiteBookmarks
LINK_BOOKMARK -> return#switchMap repository.linkBookmarks
}
repository.websiteBookmarks
}
As of 2.6.0-alpha05 version:
Transformations is now written in Kotlin. This is a source incompatible change for those classes written in Kotlin that were directly using syntax such as Transformations.map - Kotlin code must now use the Kotlin extension method syntax that was previously only available when using lifecycle-livedata-ktx. When using the Java programming language, the versions of these methods that take an androidx.arch.core.util.Function method are deprecated and replaced with the versions that take a Kotlin Function1.
So, instead of using Transformations, you need to use the extension function directly myLiveData.switchMap or myLiveData.map
So, to fix this use:
var myList: LiveData<List<Bookmark>> = bookMarkType.switchMap { input: Int? ->
when (input) {
ARTICLE_BOOKMARK -> return#switchMap repository.articleBookmarks
WEBSITE_BOOKMARK -> return#switchMap repository.websiteBookmarks
LINK_BOOKMARK -> return#switchMap repository.linkBookmarks
}
repository.websiteBookmarks
}
Traditionally, in Groovy, it was possible to define flavor-specific variables in the ext
{} block, but switching to Kotlin DSL it seems that the extra map has the project scope.
It looks like it is possible to force a flavor scope for extras by using:
productFlavors {
register("flavor1") {
require(this is ExtensionAware)
...
}
register("flavor2") {
require(this is ExtensionAware)
...
}
}
(source: https://github.com/gradle/kotlin-dsl-samples/issues/1254)
But if it needs to be used later, for example to tweak the variables based on buildType like this:
variants.forEach { variant ->
val flavor = variant.productFlavors[0]
val size = ?? // extra??
variant.buildConfigField("String", "SIZE", size)
}
how would these flavor-scoped references to extra be used?
Currently, only one working method to access ext properties on ProductFlavor is this way
variant.productFlavors.forEach { flavor ->
require(flavor is ReadOnlyProductFlavor)
val properties = (flavor.getProperty("ext") as DefaultExtraPropertiesExtension).properties
}
Or maybe more clear
val flavor = variant.productFlavors[0] as ReadOnlyProductFlavor
val extra = flavor.getProperty("ext") as DefaultExtraPropertiesExtension
extra.get("myPropertyName")
It just does the same thing what Groovy does when you call the non-existing property ext
I created a feature request for making it easier
https://issuetracker.google.com/issues/161115878
I am trying to switch my gradle files to Kotlin DSL. My project is making call
to an API.
In build.gradle(app) I had a function to retrieve an api key stored in an other
file keys.properties.
After some problem (for example) I rewrote the function to get the
key. I wrote the following function in build.gradle.kts:
import import java.io.File
fun readFileLineByLineUsingForEachLine2(fileName: String): HashMap<String, String>{
val items = HashMap<String, String>()
File(fileName).forEachLine {
items[it.split("=")[0]] = it.split("=")[1]
}
return items
}
Then I set a variable to hold the value of a particular key:
buildConfigField(String!, "API_KEY", returnMapOfKeys()["API_KEY"])
After fixing some errors I am stuck with the following one:
app/build.gradle.kts:49:36: Expecting ')'
which point on the line above with buildConfigField.
Does someone know where is this error ?
Or does someone know how to retrieve keys from files with Kotlin DSL ?
I solved my problem (it seems so.. check the edit!!). I ended up with the following function:
// Retrieve key for api
fun getApiKey(): String {
val items = HashMap<String, String>()
val f = File("keys.properties")
f.forEachLine {
items[it.split("=")[0]] = it.split("=")[1]
}
return items["API_KEY"]!!
}
And then I call buildConfigField as follow:
buildConfigField("String", "API_KEY", getApiKey())
There are no errors anymore on this part.
Edit
Once I have fixed all errors in the build.gradle.kts, the build of my project return that the file keys.properties could not be found: I had to fix my function getApiKey. Finally I could build and run my project with the following implementation:
// Return value of api key stored in `app/keys.properties`
fun getApiKey(): String {
val items = HashMap<String, String>()
val fl = rootProject.file("app/keys.properties")
(fl.exists())?.let {
fl.forEachLine {
items[it.split("=")[0]] = it.split("=")[1]
}
}
return items["API_KEY"]!!
}
This function is far to be good with all its hardcoded stuff but it allows to build my project.
Alternative
import com.android.build.gradle.internal.cxx.configure.gradleLocalProperties
val apiKey = gradleLocalProperties(rootDir).getProperty("key.properties")
..
buildConfigField("String", "API_KEY", "\"$apiKey\"")
In your kts file, first import
import java.io.FileInputStream
import java.io.FileNotFoundException
import java.util.Properties
then you can do this:
fun getApiKey(): String {
val fl = rootProject.file("gradle.properties") <- the path for the file where your key is.
if (fl.exists()) {
val properties = Properties()
properties.load(FileInputStream(fl))
return properties.getProperty("API_KEY") <- the name your give to it
} else {
throw FileNotFoundException()
}
}
Now you call use it: buildConfigField("String", "API_KEY", getApiKey())
I'm trying to create a helper class that will handle reading and writing internal files in my android app using Kotlin.
Here are the links I followed in order:
https://developer.android.com/guide/topics/data/data-storage
https://developer.android.com/training/data-storage/files.html#WriteInternalStorage
https://developer.android.com/training/data-storage/files/internal
https://developer.android.com/topic/security/data
Here's my code:
package com.example.testapp
// Added
import android.content.Context
import java.io.File
// External
import androidx.security.crypto.EncryptedFile
import androidx.security.crypto.MasterKeys
#Suppress("unused")
class SystemMain {
fun writeFile(context: Context) {
// Although you can define your own key generation parameter specification, it's recommended that you use the value specified here.
val keyGenParameterSpec = MasterKeys.AES256_GCM_SPEC
val masterKeyAlias = MasterKeys.getOrCreate(keyGenParameterSpec)
// Creates a file with this name, or replaces an existing file that has the same name. Note that the file name cannot contain path separators.
val fileToWrite = "my_sensitive_data.txt"
val encryptedFile = EncryptedFile.Builder(File(fileToWrite), context, masterKeyAlias, EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB).build()
encryptedFile.bufferedWriter().use { writer ->
writer.write("MY SUPER-SECRET INFORMATION")
}
}
}
Here's my build.gradle:
...
implementation "androidx.lifecycle:lifecycle-extensions:2.1.0"
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.1.0"
implementation "androidx.security:security-crypto:1.0.0-alpha02"
...
The error I'm getting is here: encryptedFile.bufferedWriter()
Unresolved reference. None of the following candidates is applicable
because of receiver type mismatch:
#InlineOnly public inline fun File.bufferedWriter(charset: Charset = ..., bufferSize: Int = ...): Buffered Writer defined in kotlin.io
#InlineOnly public inline fun OutputStream.bufferedWriter(charset: Charset = ...): BufferedWriter defined in kotlin.io
Am I missing a reference somewhere? Am I using the incorrect references? Has the code changed and the documentation on the links are outdated?
I'm very new at this. Any advice / help will be appreciated.
After looking at definitions and declarations; I've found this:
encryptedFile.openFileOutput().bufferedWriter().use {writer ->
writer.write("MY SUPER-SECRET INFORMATION")
}
Not sure how well this will work, but there's no error.
Hope this helps someone else.
I am doing an react native project. When I open the project on Android Studio. The following error is shown.
Error:Cannot get property 'args' on null object
I have checked setting gradle. It is just like bellow:
rootProject.name = 'my_app_name'
include ':app'
I also wonder what is 'args' in this statement.
I've had this error.My solution is find 'your project root path'/node_modules/react-native-config/android/dotenv.gradle
enter image description here
def getCurrentFlavor() {
Gradle gradle = getGradle()
String tskReqStr = gradle.getStartParameter().getTaskRequests().toString()
Pattern pattern = Pattern.compile("(assemble|generate|install)(.*?)(Debug|Release)")
Matcher matcher = pattern.matcher(tskReqStr)
if( matcher.find() ) {
String variant = matcher.group(2) + matcher.group(3)
return variant.toLowerCase()
} else {
return "";
}
}
enter image description here
I hope it help you!