I want to retreive key from local.properties file that looks like :
sdk.dir=C\:\\Users\\i30mb1\\AppData\\Local\\Android\\Sdk
key="xxx"
and save this value in my BuildConfig.java via gradle Kotlin DSL. And later get access to this field from my project.
Okay. I found solutions.
For Android Projects :
In my build.gradle.kts I create a value that retrieves my key:
import com.android.build.gradle.internal.cxx.configure.gradleLocalProperties
val key: String = gradleLocalProperties(rootDir).getProperty("key")
And in the block buildTypes I write it:
buildTypes {
getByName("debug") {
buildConfigField("String", "key", key)
}
}
And in my Activity now I can retrieve this value:
override fun onCreate() {
super.onCreate()
val key = BuildConfig.key
}
For Kotlin Projects:
We can create an extension that help us to retrieve desired key:
fun Project.getLocalProperty(key: String, file: String = "local.properties"): Any {
val properties = java.util.Properties()
val localProperties = File(file)
if (localProperties.isFile) {
java.io.InputStreamReader(java.io.FileInputStream(localProperties), Charsets.UTF_8).use { reader ->
properties.load(reader)
}
} else error("File from not found")
return properties.getProperty(key)
}
And use this extension when we would like
task("printKey") {
doLast {
val key = getLocalProperty("key")
println(key)
}
}
If you don't have access to gradleLocalProperties (it's only accessible for android projects):
val prop = Properties().apply {
load(FileInputStream(File(rootProject.rootDir, "local.properties")))
}
println("Property:" + prop.getProperty("propertyName"))
Don't forget imports:
import java.io.File
import java.io.FileInputStream
import java.util.*
put your property in
local.properties
and in build.gradle(app).kts file reference it as such:
gradleLocalProperties(rootDir).getProperty("YOUR_PROP_NAME")
Related
I created a gradle plugin to unify some settings between the various modules of the application. the summary of the error is this:
org.gradle.api.plugins.InvalidPluginException: An exception occurred applying plugin request [id: 'common.plugin']
Caused by: org.gradle.api.UnknownDomainObjectException: Extension of type 'LibraryExtension' does not exist. Currently registered extension types: [ExtraPropertiesExtension,....]
This is a summary image of the project architecture:
CommonPluginClass:
class CommonPluginClass : Plugin<Project> {
private val consumerProguardFileName = "consumer-rules.pro"
private val proguardFileName = "proguard-rules.pro"
private val sdkToCompile = 33
override fun apply(project: Project) {
println(">>> Adding sugar to gradle files!")
with(project)
{
applyPlugins(this)
androidConfig(this)
}
println(">>> Sugar added for core Module!")
}
private fun applyPlugins(project: Project) {
println(">>> apply plugins!")
project.pluginManager.run {
apply("com.android.application")
apply("kotlin-android")
apply("kotlin-kapt")
}
println(">>> end apply plugins!")
}
private fun androidConfig(project: Project) {
project.extensions.configure<LibraryExtension>{
defaultConfig.targetSdk = 33
}
}
}
the error occurs inside the androidConfig function when calling configure
I was inspired by now android, dependencies and imports are similar but not build. Can someone unlock it please.
build-logic:convention build.gradle
plugins {
alias(libs.plugins.kotlin.jvm) apply false
id "org.gradle.kotlin.kotlin-dsl" version "2.4.1"
}
dependencies {
compileOnly(libs.android.pluginGradle)
compileOnly(libs.kotlin.pluginGradle)
}
gradlePlugin {
plugins {
commonPlugin {
id = "common.plugin"
implementationClass = "CommonPluginClass"
}
}
}
LITTLE UPDATE:
I've noticed that any module I enter always identifies it to me as ApplicationExtension
I found the solution and as usual it's a stupid thing.
the application extension use plugin
apply("com.android.application")
the library or module use plugin
apply("com.android.library")
I have two multiplatform modules shared and other in a standard multiplatform template project that targets Android and iOS.
shared defines a class in commonMain source set
class SharedGreeting()
other is setup to depend on shared like this in the gradle file:
val commonMain by getting {
dependencies {
implementation(project(":shared"))
}
}
And in its androidMain sourceset it tries to reference SharedGreeting in some class, fx:
class AndroidGreeter{
val foo = SharedGreeting()
}
But no matter what I try, I get IDE errors when I try to reference the shared class, and I have to manually add an import statement.
The code compiles and deploys without problems though!
Any ideas on what I am missing or misunderstanding? Or is this a bug in KMM?
Full copy of other gradle file:
plugins {
kotlin("multiplatform")
kotlin("native.cocoapods")
id("com.android.library")
}
version = "1.0"
kotlin {
android()
iosX64()
iosArm64()
iosSimulatorArm64()
cocoapods {
summary = "Some description for the Shared Module"
homepage = "Link to the Shared Module homepage"
ios.deploymentTarget = "14.1"
framework {
baseName = "other"
}
}
sourceSets {
val commonMain by getting {
dependencies {
implementation(project(":shared"))
}
}
val commonTest by getting {
dependencies {
implementation(kotlin("test"))
}
}
val androidMain by getting
val androidTest by getting
val iosX64Main by getting
val iosArm64Main by getting
val iosSimulatorArm64Main by getting
val iosMain by creating {
dependsOn(commonMain)
iosX64Main.dependsOn(this)
iosArm64Main.dependsOn(this)
iosSimulatorArm64Main.dependsOn(this)
}
val iosX64Test by getting
val iosArm64Test by getting
val iosSimulatorArm64Test by getting
val iosTest by creating {
dependsOn(commonTest)
iosX64Test.dependsOn(this)
iosArm64Test.dependsOn(this)
iosSimulatorArm64Test.dependsOn(this)
}
}
}
android {
compileSdk = 32
sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml")
defaultConfig {
minSdk = 24
targetSdk = 32
}
}
For full project source code:
https://github.com/RabieJradi/kmm_import_error_sample
IDE suggested action for adding a dependency doesn't unfortunately do anything.
Turns out it is a bug in KMM and a fix have been implemented by the Jetbrains team here https://youtrack.jetbrains.com/issue/KTIJ-22056/KMM-Cant-reference-shared-module-commonMain-source-set-classes-from-another-modules-androidMain-source-set
You cannot do this in that way.
To make your project work you have to work with expect and actual words.
So, make these changes:
change your SharedGreeting class in shared module like that:
expect class SharedGreeting {
fun greeting(): String
}
Then your IDE wants you to make two changes, in shared module.
Add a class in both modules, iosMain and androidMain named SharedGreeting. The code is the same for both classes:
actual class SharedGreeting {
actual fun greeting(): String {
return "Hello, ${Platform().platform}!"
}
}
The work is done, now your other library has no errors. From your androidMain module inside "other" you can work only on other androidMain modules inside other MKK libraries.
Trying to use kotlin-dotnet, but this is not working, using kotlin object class, to manage singleton
Got error Could not find /asset/env on the classpath whereas the env file is in /assets folder as mentionned in the doc
object EnvVariables {
val envVar: Dotenv =
dotenv {
directory = "/assets"
filename = "env"
}
}
object RetrofitInstance {
val api: TodoService by lazy {
Retrofit.Builder()
.baseUrl(EnvVariables.envVar["BASE_URL"])
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(TodoService::class.java)
}
}
Most likely the doc is not accurate
In file DotEnvReader.java
return ClasspathHelper
.loadFileFromClasspath(location.replaceFirst("./", "/"))
.collect(Collectors.toList());
So, you can fix it by adding "."
var dotenv = dotenv {
directory = "./assets" //use ./ instead of /
filename = "env"
}
Trying to create some playground over Detekt custom rules and it just doesn't work. Doesn't even try to find the rule-set file.
The gradle goes
plugins {
id 'com.android.application'
id 'kotlin-android'
id("io.gitlab.arturbosch.detekt").version("1.17.1")
}
...
detekt {
toolVersion = "$detekt_version" // 1.17.1
input = files("src/main/java")
config = files("../detekt/detekt-config.yml")
autoCorrect = true
reports { ... }
}
dependencies {
detektPlugins "io.gitlab.arturbosch.detekt:detekt-formatting:$detekt_version"
compileOnly "io.gitlab.arturbosch.detekt:detekt-api:$detekt_version"
detekt "io.gitlab.arturbosch.detekt:detekt-cli:$detekt_version"
...
}
The rule goes
class SomeCustomRule(config: Config) : Rule(config) {
override val issue: Issue
get() = Issue("Import thingy", Severity.Minor, "I don't like this string", Debt(10))
override fun visitImportDirective(importDirective: KtImportDirective) {
val import: String = importDirective.importPath?.pathStr ?: ""
if ("appcompat" in import) {
report(CodeSmell(
issue,
Entity.from(importDirective),
"Importing $import which is an internal import"))
}
}
}
The provider is
class CustomRuleSetProvider : RuleSetProvider {
override val ruleSetId: String = "detekt-custom-rules"
override fun instance(config: Config) = RuleSet(ruleSetId, listOf(SomeCustomRule(config)))
}
And last but not least
At
src/main/resources/META-INF/services/io.gitlab.arturbosch.detekt.api.RuleSetProvider
is
com.playgrounds.detekt.customrule.CustomRuleSetProvider
Still - nothing. I tried to add gibberish at the provider - nothing, no error. I even tried to spoil the declaration at META-INF. Nothing.
Of course I tried to add the provider into my config file, or add a project line in the gradle. Error, not recognised.
What have I missed?
Thanks
I'm still new in developing Gradle Plugin. But what i want to do is to define global method to call in consumer gradle file.
So my plugin class looking something like this:
class Main : Plugin<Project> {
override fun apply(target: Project) {
// Some configuration
}
fun modulePath(moduleName: String, target: Project): Any {
val propFile = File("${target.rootDir}/local.properties")
if (!propFile.exists()) propFile.createNewFile()
val props = Properties()
props.load(propFile.inputStream())
val useAAR = props.getProperty("useAAR", "false")?.toBoolean() ?: false
val devModule = props.getProperty("modules", ":app").split(" ")
return if (useAAR && !devModule.contains(moduleName)) {
"$groupId:$moduleName:$versionId"
} else {
target.project(moduleName)
}
}
companion object {
const val groupId = "local"
const val versionId = "0.1"
}
}
I can apply the plugin just fine in the consumer. But I still don't know how to call modulePath method in consumer's gradle file. Something like this:
apply plugin: 'main'
dependencies {
implementation modulePath(':someModule')
}
When i'm calling the modulePath, i'm getting error that the method is not defined.
Thanks in advance.