I'm using a custom framework headers as a compile time dependencies:
Top-level build.gradle.kts:
allprojects {
gradle.projectsEvaluated {
tasks.withType(JavaCompile::class) {
options.compilerArgs.add("-Xbootclasspath/p:sdk/framework.jar")
val newFiles = options.bootstrapClasspath?.files?.toMutableList() ?: mutableListOf<File>()
newFiles.add(File("sdk/framework.jar"))
options.bootstrapClasspath = files(newFiles.toTypedArray())
}
}
}
Module's build.gradle.kts:
compileOnly(project.files("${project.rootDir.absolutePath}/sdk/framework.jar"))
Then if I use a custom class in a «regular» code, it works fine:
val viewProxyManager: ViewProxyManager = getSystemService(Context.VIEW_PROXY_SERVICE) as ViewProxyManager
But if it's used in module's Hilt module, it fails to find the class:
#Provides
#Reusable
fun provideViewProxyManager(
#ApplicationContext
context: Context
): ViewProxyManager {
return context.getSystemService(Context.VIEW_PROXY_SERVICE) as ViewProxyManager
}
ComponentProcessingStep was unable to process 'com.package.remote.agent.app.App_HiltComponents.SingletonC' because 'android.app.ViewProxyManager' could not be resolved.
How to add my framework jar to the kapt tasks classpath?
Related
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.
I'm trying to utilize Gradle versionCatalogs and put all the versions there including Android-specific compileSdkVersion, minSdkVersion, targetSdkVersion.
It's possible to access these versions with the following code:
val libs = rootProject.extensions.getByType(VersionCatalogsExtension::class.java).named("libs")
libs.findVersion("compileSdkVersion").get().toString() as Integer
But my project is multi-module and I don't want to copy-paste boilerplate code. So, I created extension functions in a separate module.
root-level settings.gradle.kts:
includeBuild("gradle-dependencies")
module-level build.gradle.kts:
plugins {
`kotlin-dsl`
`java-gradle-plugin`
}
repositories {
gradlePluginPortal()
google()
mavenCentral()
}
group = "com.foobar.androidtools.gradle"
version = "SNAPSHOT"
dependencies {
implementation(gradleApi())
}
gradlePlugin {
plugins.register("Gradle extensions") {
id = "foobar-gradle-dependencies"
implementationClass = "com.foobar.gradle_dependencies.DependenciesPlugin"
}
}
src/main/kotlin/com/foobar/gradle_dependencies/Extensions.kt:
package com.foobar.gradle_dependencies
import org.gradle.api.Project
import org.gradle.api.artifacts.VersionCatalogsExtension
import org.gradle.kotlin.dsl.getByType
fun Project.version(key: String): String = this.extensions
.getByType<VersionCatalogsExtension>()
.named("libs")
.findVersion(key)
.get()
.requiredVersion
fun Project.versionInt(key: String) = version(key).toInt()
val Project.KOTLIN_JVM_TARGET_VERSION get() = version("kotlinJvmTargetVersion")
val Project.ANDROID_COMPILE_SDK_VERSION get() = versionInt("compileSdkVersion")
val Project.ANDROID_MIN_SDK_VERSION get() = versionInt("minSdkVersion")
val Project.ANDROID_TARGET_SDK_VERSION get() = versionInt("targetSdkVersion")
Trying to build the project I see the following error:
e: /AndroidTools/gradle-dependencies/src/main/kotlin/com/foobar/gradle_dependencies/Extensions.kt: (4, 33): Unresolved reference: VersionCatalogsExtension
Why the dependency can't be resolved taking into account that import works fine?
AGP: 7.1.3
Gradle: https://services.gradle.org/distributions/gradle-7.4.2-bin.zip
So I am currently trying to add a room database to an open-source project as part of my thesis, I grabbed the most recent example I could from android itself and modified it for Kotlin DSL, I used the same DAO and database structure but both have import errors. Normally this wouldn't be a problem to fix except I am getting errors from the same library in places which is why I had to ask this question in the first place. The main import problem is to do with androidx.room. Below is the kotlin file in question and after that, is the build.gradle.kts.
Just to add, android studio suggests I use persistence.room.runtime but from what I have tried and what I could find, this does not solve my problem either.
import androidx.room.Database //works
import androidx.room.Room // unresolved reference
import androidx.room.RoomDatabase // unresolved reference
#Database(entities = [GameDatabase::class], version = 1, exportSchema = false)
abstract class Database : RoomDatabase() {
abstract val DatabaseDAO: DatabaseDAO
companion object {
#Volatile
private var INSTANCE: Database? = null
fun getInstance(): Database {
synchronized(this) {
var instance = INSTANCE
if (instance == null) {
instance = Room.databaseBuilder(
Database::class.java,
"game_database"
)
.fallbackToDestructiveMigration()
.build()
INSTANCE = instance
}
return instance
}
}
}
}
Here is the module gradle build:
plugins {
//id("kotlin")
kotlin("kapt")
//kotlin("android")
//kotlin("android-extensions")
//id("kotlin-android")
//id("kotlin-android-extensions")
//id("androidx.navigation.safeargs")
}
java {
sourceCompatibility = JavaVersion.VERSION_1_6
}
tasks {
compileJava {
options.encoding = "UTF-8"
}
compileTestJava {
options.encoding = "UTF-8"
}
}
sourceSets {
main {
java.srcDir("src/")
}
}
// added
dependencies {
val room_version = "2.2.6"
val life_version = "2.2.0"
// Room and Lifecycle dependencies
implementation("androidx.room:room-runtime:$room_version")
kapt("androidx.room:room-compiler:$room_version")
//implementation("androidx.room:room-ktx:$room_version")
implementation("androidx.legacy:legacy-support-v4:1.0.0")
implementation("androidx.lifecycle:lifecycle-extensions:$life_version")
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:$life_version")
implementation("androidx.lifecycle:lifecycle-livedata-ktx:$life_version")
implementation("androidx.lifecycle:lifecycle-common-java8:$life_version")
// adding Firebase dependencies
//implementation("android.arch.persistence.room:runtime:1.1.1")
//annotationProcessor("android.arch.persistence.room:compiler:2.2.6")
}
I am quite new to Kotlin DSL so it might be an obvious error but I also couldn't find anything like this in the area.
This is how I usually place the implementations:
//Room
implementation "androidx.room:room-runtime:2.2.6"
kapt "androidx.room:room-compiler:2.2.6"
// optional - Kotlin Extensions and Coroutines support for Room
implementation "androidx.room:room-ktx:2.2.6"
Also, have you placed the kapt plugin? if not:
plugins {
id 'kotlin-android'
id 'kotlin-kapt'//this one
}
And, try to clean and rebuild the project.
I have the following Koin module:
val exampleModule = module {
single<ExampleRepository> { RealExampleRepository() }
}
I need to apply two annotations to RealExampleRepository to supress an experimental coroutines API usage warning.
The annotations I need to apply are:
#FlowPreview
#ExperimentalCoroutinesApi
How can I do this?
I found that it can be done by converting the module to a method and applying the annotations to the method like so:
#FlowPreview
#ExperimentalCoroutinesApi
fun exampleModule() = module {
single<ExampleRepository> { RealExampleRepository() }
}
I'm trying to implement Dagger 2 in a test app to learn Clean Architecture and dependancy injection in Kotlin language.
EDIT :
I can compile thanks to #Logain, but I have always the static member problem with Dagger in my singleton (see below my TaskWorker), so I'm looking for how can I fix this error
But i got a problem, my DaggerComponent is well generated when i do a rebuild, but not when i want to run my app for testing, it fails and disappears. It fails with this error :
Error:(21, 29) Unresolved reference: DaggerInjectorComponent
Error:Execution failed for task ':app:compileDebugKotlinAfterJava'.
> Compilation error. See log for more details
While when i do a rebuild, this task is passed correctly
:app:compileDebugKotlinAfterJava
So i don't understand why it fails.
Here is my InjectorComponent :
#Singleton
#Component(modules = arrayOf(ContextDaggerModule::class, LocalStoreDaggerModule::class))
interface InjectorComponent {
fun inject(realmLocalStore: RealmLocalStore)
fun inject(taskWorker: TaskWorker)
}
ContectDaggerModule :
#Module
class ContextDaggerModule (val app: Application) {
#Provides
#Singleton
fun provideContext(): Context = app
#Provides
#Singleton
fun provideApplication(): Application = app
#Provides
#Singleton
fun provideResources(): Resources = app.resources
}
LocalStoreDaggerModule :
#Module
class LocalStoreDaggerModule {
#Provides
#Singleton
fun provideLocalStore(context: Context): LocalStore {
return RealmLocalStore(context)
}
}
I think the problem is caused because I inject dependencies in Object-declarations but all elements are static and Dagger does not appreciate it.
So, i try to hack it with a simple override getter and injecting data but nop.
Here is my "hack" :
object TaskWorker {
// #Inject lateinit var localStore: LocalStore
// Not work cause it's a static variable
var localStore: LocalStore? = null
#Inject
get() = localStore
// some cool function
}
I follow this code and this tutorial
I use these dependencies :
// Dagger2
compile 'com.google.dagger:dagger:2.11'
kapt 'com.google.dagger:dagger-compiler:2.11'
provided 'org.glassfish:javax.annotation:10.0-b28'
Make sure you are using:
kapt {
generateStubs = true
}
Due to some limitations on kapt
Or just try with:
annotationProcessor 'com.google.dagger:dagger-compiler:2.11'
You don't need this.
kapt {
generateStubs = true
}
Just apply the plugin:
apply plugin: 'kotlin-kapt'
and add the dependencies:
compile androidDependencies.dagger2
compile androidDependencies.dagger2Android
kapt androidDependencies.dagger2Kapt
sometimes the tasks fail with errors like that. Try to clean and as last resort use invalidate and restart. Most of the times it works.