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.
Related
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?
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 run Espresso tests using MockRetrofit to test UI flows in the app. The Espresso tests rely on swapping the production Dagger ApiModule located in src/main/java/com/my/app/ApiModule
#Module(includes = [NetworkModule::class])
class ApiModule {
#Provides
#Singleton
fun restApi(
retrofit: Retrofit.Builder,
#DefaultClientBuilder clientBuilder: OkHttpClient.Builder
): RestApi {
val apiRetrofit = retrofit.client(clientBuilder.build()).build()
return apiRetrofit.create<RestApi>(RestApi::class.java)
}
}
with the fake ApiModule located in src/androidTest/java/com/my/app/ApiModule
#Module(includes = [NetworkModule::class])
class ApiModule {
#Provides
#Singleton
fun restApi(
retrofit: Retrofit.Builder,
#DefaultClientBuilder clientBuilder: OkHttpClient.Builder
): RestApi {
return MockApiModule.getApi(failureRate = FailureRate.NEVER, responseDelay = 500L)
}
}
I just upgraded to AGP 3.6 (and then to 4.0). The tests are still passing when running ./gradlew connectedDebugAndroidTest. But I also have a build configuration called debugMinified
buildTypes{
...
debugMinified {
minifyEnabled true
debuggable true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules-testing.pro'
signingConfig signingConfigs.debug
}
...
}
which I use to run Espresso tests with an obfuscated apk to catch Pro-guard related Runtime errors.
Now when I run ./gradlew connectedDebugMinifiedAndroidTest, my tests fail because AGP is not swapping the fake implementation in the androidTest src set, upon analysis of the apk. It's just using the real implementation in main. But again, this only happens for minified builds.
The above class ApiModule is one of 5 classes I swap out in this manner, when running UI tests. The other 4 have nothing to do with Dagger and are also not being swapped out, so I am relatively certain it's not just a Dagger issue.
This is currently blocking me from upgrading to AGP 4.0 so any help is greatly appreciated.
After some trial and error I was able to resolve this issue simply by adding #Keep to all fake and real implementation class signatures
#Keep
#Module(includes = [NetworkModule::class])
class ApiModule {
#Provides
#Singleton
fun restApi(
retrofit: Retrofit.Builder,
#DefaultClientBuilder clientBuilder: OkHttpClient.Builder
): RestApi {
val apiRetrofit = retrofit.client(clientBuilder.build()).build()
return apiRetrofit.create<RestApi>(RestApi::class.java)
}
}
#Keep
#Module(includes = [NetworkModule::class])
class ApiModule {
#Provides
#Singleton
fun restApi(
retrofit: Retrofit.Builder,
#DefaultClientBuilder clientBuilder: OkHttpClient.Builder
): RestApi {
return MockApiModule.getApi(failureRate = FailureRate.NEVER, responseDelay = 500L)
}
}
I'm still not sure why this works, or even why it's needed now. Just a lucky guess. Any further insight would be greatly appreciated.
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() }
}
"A long time ago in a galaxy far, far away...."
Ok, long story short - I decided to give Android Studio 3.0 Preview (Canary 2) a shot and I cannot make it work with Dagger 2 using annotationProcessor instead of android-apt.
The error message I get is a simple one to digest:
Error:(59, 24) error: cannot find symbol variable DaggerAppComponent
I've read the docs (nothing fancy there, I guess): https://developer.android.com/studio/preview/features/new-android-plugin-migration.html#annotationProcessor_config
And changed the build.gradle file to:
implementation "com.google.dagger:dagger:$rootProject.ext.daggerVersion"
annotationProcessor "com.google.dagger:dagger-android-processor:$rootProject.ext.daggerVersion"
Where daggerVersion = '2.11'
Also, I made sure that appropriate options are checked in Android Studio (were not checked by default):
File -> Other Settings -> Default Settings ->
Build, Execution, Deployment -> Compiler -> Annotation Processors ->
Enable annotation processors -> IS CHECKED
Unfortunately, it does not help.
Gradle:
distributionUrl=https\://services.gradle.org/distributions/gradle-4.0-milestone-1-all.zip
Android Plugin for Gradle:
dependencies {
classpath 'com.android.tools.build:gradle:3.0.0-alpha2'
...
}
How do I make it work with annotationProcessor instead of android-apt?
EDIT #1
I've added these "supposed-to-be-extra-ones" dependencies "just in case of"
implementation "com.google.dagger:dagger:$rootProject.ext.daggerVersion"
implementation "com.google.dagger:dagger-android:$rootProject.ext.daggerVersion"
implementation "com.google.dagger:dagger-android-support:$rootProject.ext.daggerVersion"
annotationProcessor "com.google.dagger:dagger-android-processor:$rootProject.ext.daggerVersion"
annotationProcessor "com.google.dagger:dagger-compiler:$rootProject.ext.daggerVersion"
compileOnly 'javax.annotation:jsr250-api:1.0'
And now I get an error about conflicting scopes... Oo
SomeSubComponent has conflicting scopes:
AppComponent also has #Singleton
I did upgrade Dagger from 2.6.1 to 2.11, so now I'm looking for some "breaking changes" in Release Notes: https://github.com/google/dagger/releases
Edit #2
The good news is that the first "breaking change" was introduced in 2.9 My wild guess is that this is due to "New Validation". The bad news is that, most probably, the problem was already there for ages. https://github.com/google/dagger/releases/tag/dagger-2.9
Reviewing structure of (Sub)Components and Scoped Dependencies.
Edit #3
Currently, this issue is related to this one: https://github.com/google/dagger/issues/107
Consider the following example:
#Singleton
#Component(modules = {
AppModule.class
})
public interface AppComponent {
SomeComponent plus(SomeModule someModule);
}
#Module
public class AppModule {
#Provides
#Singleton
public Integer provideInteger() {
return 1;
}
}
#Singleton
#Subcomponent(modules = {
SomeModule.class
})
public interface SomeComponent {
void inject(MainActivity activity);
}
#Module
public class SomeModule {
#Provides
#Singleton
public String provideText(Integer number) {
return number.toString();
}
}
This is no longer possible with Dagger 2.9+. The Component has to use a different Scope then the Subcomponents. Like this:
#Scope
public #interface ApplicationScope {
}
#Module
public class AppModule {
#Provides
#ApplicationScope
public Integer provideInteger() {
return -1;
}
}
#ApplicationScope
#Component(modules = {
AppModule.class
})
public interface AppComponent {
SomeComponent plus(SomeModule someModule);
}
Don't be a "smartass" and stick to what the docs say:
implementation "com.google.dagger:dagger:2.11"
annotationProcessor "com.google.dagger:dagger-compiler:2.11"
When migrating to Dagger 2.9+ use different (Custom)Scopes for Components and Subcomponents "singletons".
See the Question's description for more verbose explanation.
Also, I think that the Release Notes for 2.9 could be more explicit about this change, no? :/
https://github.com/google/dagger/releases/tag/dagger-2.9