0

First of all, and just in case, I've read plenty of posts (like this) with no luck so don't mark this as duplicate please.

I'm new to Hilt, and trying to implement it in my multi-module app, but for the moment cannot even get my app to start.

I have a class called AppSettings in a module called "Common" -which is accesible from all modules- which holds (as the name says) all app configuration.

I'm following the Hilt documentation and the first I've done is to add dependencies (done it in all project modules).

Project build.gradle:

buildscript {
    ext.kotlin_version = '1.7.10'
    repositories {
        jcenter()
        google()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:7.2.1'
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
        classpath("com.google.dagger:hilt-android-gradle-plugin:2.38.1")
    }
    ext.java_version = JavaVersion.VERSION_1_8
}

allprojects {
    repositories {
        jcenter()
        mavenCentral()
        maven { url "https://jitpack.io" }
        maven { url 'https://repository-achartengine.forge.cloudbees.com/snapshot/' }
        maven { url 'def androidHome = System.getenv("ANDROID_HOME")' }
        maven { url "/Home/MrDeveloper/Android/Sdk/extras/android/m2repository/" }
        google()
    }
}

app build.gradle:

plugins {
    id 'dagger.hilt.android.plugin'
    id 'com.android.application'
    id 'kotlin-android'
    id 'kotlin-kapt'
}

android {
    compileSdkVersion 32
    def code
    Properties versionProps = new Properties()
    def versionPropsFile = file('version.properties')
    if (versionPropsFile.exists())
        versionProps.load(new FileInputStream(versionPropsFile))
    code = (versionProps['VERSION_CODE'] ?: "0").toInteger() + 1
    versionProps['VERSION_CODE'] = code.toString()
    versionProps.store(versionPropsFile.newWriter(), null)
    packagingOptions {
        resources {
            pickFirsts += ['META-INF/LICENSE.txt']
            excludes += ['META-INF/NOTICE.md', 'META-INF/LICENSE.md', 'META-INF/INDEX.LIST', 'META-INF/DEPENDENCIES', 'META-INF/io.netty.versions.properties']
        }
    }
    defaultConfig {
        minSdkVersion 23
        targetSdkVersion 32
        versionCode code
        versionName "2.0." + code
        // next ndk abifilters have to be disabled if spli apk is enabled.
        // ndk.abiFilters 'armeabi', 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'//testing
        multiDexEnabled true
        compileOptions {
            sourceCompatibility java_version
            targetCompatibility java_version
        }
    }
    compileOptions {
        sourceCompatibility java_version
        targetCompatibility java_version
    }
    splits {
        // Configures multiple APKs based on ABI.
        abi {
            // Enables building multiple APKs per ABI.
            enable true
            // By default all ABIs are included, so use reset() and include to specify that we only
            // want APKs for x86 and x86_64.
            // Resets the list of ABIs that Gradle should create APKs for to none.
            reset()
            // Specifies a list of ABIs that Gradle should create APKs for.
            include "armeabi-v7a"
            include "arm64-v8a"
            include "x86"
            include "x86_64"
        }
    }
    buildTypes {
        release {
            /*signingConfig signingConfigs.release*/
            minifyEnabled false
            shrinkResources false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            // This next piece of code is used by apk Split
            applicationVariants.all { variant ->
                variant.outputs.all { output ->
                    project.ext { appName = 'artandwords' }
                    def newName = 'artandwords_' + output.getFilter(com.android.build.OutputFile.ABI) + '.apk'
                    outputFileName = new File("./", newName)
                }
                // assign different version code for each output
                variant.outputs.each { output ->
                    output.versionCodeOverride =
                            //project.ext.versionCodes.get(output.getFilter(OutputFile.ABI)) * 1000 + android.defaultConfig.versionCode
                            project.ext.versionCodes.get(output.getFilter(com.android.build.OutputFile.ABI)) * 1000 + code - 1000
                }
            }
        }
        debug {
        }
    }
    allprojects {
        repositories {
            jcenter()
            mavenCentral()
            def androidHome = System.getenv("ANDROID_HOME")
            maven {
                url "$androidHome/extras/android/m2repository/"
            }
            maven {
                url "https://maven.java.net/content/groups/public/"
            }
        }
    }
    productFlavors {
    }
    androidResources {
        ignoreAssetsPattern '!*ffprobe'
    }
    lint {
        abortOnError false
        checkReleaseBuilds false
    }
    dataBinding{
        enabled = true
    }
}

// This next piece of code is used by apk Split
// map for the version code that gives each ABI a value. make sure to list all ABIs mentioned in splits block, an keep the order.
ext.versionCodes = ['armeabi-v7a': 1, 'arm64-v8a': 2, 'x86': 3, 'x86_64': 4]

dependencies {
    //ffmpeg
    implementation 'com.arthenica:mobile-ffmpeg-min-gpl:4.2.2.LTS'
    //implementation 'com.arthenica:mobile-ffmpeg-full:4.3.1'
    //Google Guava
    api 'com.google.guava:guava:31.1-jre'
    //volley
    api 'com.android.volley:volley:1.2.1'
    //spotify
    api 'com.github.kaaes:spotify-web-api-android:0.4.1'
    //apache commons lang
    implementation group: 'org.apache.commons', name: 'commons-text', version: '1.9'
    //Font Selector List Preference
    api 'com.vanniktech:vntfontlistpreference:1.0.0'
    //Rate my app
    api 'com.github.hotchemi:android-rate:1.0.1'
    //Support
    api 'androidx.appcompat:appcompat:1.4.2'
    api 'androidx.legacy:legacy-support-v4:1.0.0'
    //AlertDialog
    implementation 'com.github.d-max:spots-dialog:1.1@aar'
    //glide animated gifs
    implementation 'com.github.bumptech.glide:glide:4.13.2'
    implementation 'androidx.viewpager2:viewpager2:1.0.0'
    annotationProcessor 'com.github.bumptech.glide:compiler:4.13.2'
    implementation 'androidx.recyclerview:recyclerview:1.2.1'
    //preference
    implementation 'androidx.preference:preference-ktx:1.2.0'
    //
    api 'com.rockerhieu:rv-adapter-endless:1.2'
    implementation 'com.squareup.picasso:picasso:2.71828'
    //flat-dialog
    implementation 'com.github.mejdi14:Flat-Dialog-Android:1.0.5'
    //Hilt
    implementation('com.google.dagger:hilt-android:2.42')
    annotationProcessor('com.google.dagger:hilt-android-compiler:2.42')

    //implementation 'com.google.dagger:hilt-android:2.42'
    //implementation 'androidx.navigation:navigation-fragment-ktx:2.5.0'
    //implementation 'androidx.hilt:hilt-lifecycle-viewmodel:1.0.0-alpha03'
    //annotationProcessor 'androidx.hilt:hilt-compiler:1.0.0'
    //annotationProcessor 'com.google.dagger:hilt-android-compiler:2.42'

    implementation project(':Common')
    implementation project(':DTO')
    implementation project(':Core')
}

I've added the same Hilt dependencies in all project modules and everything builds fine.

Then, in my AppSettings activity I've added the required directive so I can then inject it anywhere I need it:

@HiltAndroidApp
class AppSettings : MultiDexApplication() {

    val infoAlertBkgColor1 = "#60a69e"

    ...

    override fun onCreate() {
        super.onCreate()

    }
}

In my MainActivity:

@AndroidEntryPoint
class MainActivity : FragmentActivity(), IActionListeners, IImageListeners,
    OnListFragmentInteractionListener {
    @Inject lateinit var app: AppSettings

    ...
    whatever
}

And after launching the app:

2022-07-17 15:51:27.268 8574-8574/com.myapp.myapp E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.myapp.myapp, PID: 8574
    java.lang.RuntimeException: Unable to instantiate application app.AppSettings: java.lang.ClassNotFoundException: Didn't find class "app.AppSettings" on path: DexPathList[[zip file "/data/app/~~umETXnca3-spQEy4jvBm2Q==/com.myapp.myapp-QfTlJr20Dw0ZWFvJSqfnvg==/base.apk"],nativeLibraryDirectories=[/data/app/~~umETXnca3-spQEy4jvBm2Q==/com.myapp.myapp-QfTlJr20Dw0ZWFvJSqfnvg==/lib/arm64, /data/app/~~umETXnca3-spQEy4jvBm2Q==/com.myapp.myapp-QfTlJr20Dw0ZWFvJSqfnvg==/base.apk!/lib/arm64-v8a, /system/lib64, /system_ext/lib64]]
        at android.app.LoadedApk.makeApplication(LoadedApk.java:1244)
        at android.app.ActivityThread.handleBindApplication(ActivityThread.java:6683)
        at android.app.ActivityThread.access$1300(ActivityThread.java:237)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1913)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loop(Looper.java:223)
        at android.app.ActivityThread.main(ActivityThread.java:7656)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
     Caused by: java.lang.ClassNotFoundException: Didn't find class "app.AppSettings" on path: DexPathList[[zip file "/data/app/~~umETXnca3-spQEy4jvBm2Q==/com.myapp.myapp-QfTlJr20Dw0ZWFvJSqfnvg==/base.apk"],nativeLibraryDirectories=[/data/app/~~umETXnca3-spQEy4jvBm2Q==/com.myapp.myapp-QfTlJr20Dw0ZWFvJSqfnvg==/lib/arm64, /data/app/~~umETXnca3-spQEy4jvBm2Q==/com.myapp.myapp-QfTlJr20Dw0ZWFvJSqfnvg==/base.apk!/lib/arm64-v8a, /system/lib64, /system_ext/lib64]]
        at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:207)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:379)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:312)
        at android.app.AppComponentFactory.instantiateApplication(AppComponentFactory.java:76)
        at androidx.core.app.CoreComponentFactory.instantiateApplication(CoreComponentFactory.java:52)
        at android.app.Instrumentation.newApplication(Instrumentation.java:1158)
        at android.app.LoadedApk.makeApplication(LoadedApk.java:1236)
        at android.app.ActivityThread.handleBindApplication(ActivityThread.java:6683) 
        at android.app.ActivityThread.access$1300(ActivityThread.java:237) 
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1913) 
        at android.os.Handler.dispatchMessage(Handler.java:106) 
        at android.os.Looper.loop(Looper.java:223) 
        at android.app.ActivityThread.main(ActivityThread.java:7656) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947) 
        Suppressed: java.lang.NoClassDefFoundError: Failed resolution of: Lapp/Hilt_AppSettings;
        at java.lang.VMClassLoader.findLoadedClass(Native Method)
        at java.lang.ClassLoader.findLoadedClass(ClassLoader.java:738)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:363)
                ... 14 more
     Caused by: java.lang.ClassNotFoundException: Didn't find class "app.Hilt_AppSettings" on path: DexPathList[[zip file "/data/app/~~umETXnca3-spQEy4jvBm2Q==/com.myapp.myapp-QfTlJr20Dw0ZWFvJSqfnvg==/base.apk"],nativeLibraryDirectories=[/data/app/~~umETXnca3-spQEy4jvBm2Q==/com.myapp.myapp-QfTlJr20Dw0ZWFvJSqfnvg==/lib/arm64, /data/app/~~umETXnca3-spQEy4jvBm2Q==/com.myapp.myapp-QfTlJr20Dw0ZWFvJSqfnvg==/base.apk!/lib/arm64-v8a, /system/lib64, /system_ext/lib64]]
        at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:207)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:379)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:312)
                ... 17 more

AndroidManifest:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>

    <supports-screens
        android:smallScreens="true"
        android:normalScreens="true"
        android:largeScreens="true"
        android:xlargeScreens="true"
        android:anyDensity="true"
        android:resizeable="true"/>

    <application
        android:name="app.AppSettings"
        android:enabled="true"
        android:allowBackup="true"
        android:fullBackupContent="true"
        android:hardwareAccelerated="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:largeHeap="true"
        tools:replace="android:theme"
        android:theme="@style/Theme.myTheme.TitleBar">
        <uses-library
            android:name="org.apache.http.legacy"
            android:required="false" />

        ...activities...

        <receiver android:name=".helpers.notification.receiver.AlarmReceiver"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.NOTIFY" />
            </intent-filter>
        </receiver>
        <receiver android:name=".helpers.notification.receiver.BootReceiver"
            android:permission="android.permission.RECEIVE_BOOT_COMPLETED"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED"/>
            </intent-filter>
        </receiver>
        <service
            android:name=".helpers.notification.service.AlarmService"
            android:enabled="true"/>
        <service
            android:name=".helpers.audio.PlayMp3Service"
            android:enabled="true"/>
        <provider
            android:name=".helpers.GenericFileProvider"
            android:authorities="${applicationId}.helpers.GenericFileProvider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/provider_paths"/>
        </provider>

    </application>

</manifest>

Any help to get rid of this? (tried disabling Multidex with no luck, but anyway I need it)

Edit 1:

If I move the application class (the one using @HiltAndroidApp directive) to the application itself (and not in a module) the error changes, now it complains about MainActivity (the main activity using @AndroidEntryPoint directivity) not existing.

Diego Perez
  • 2,188
  • 2
  • 30
  • 58
  • Is your `AppSettings` in the `app` package only or is there something more to the package declaration like `com.app.AppSettings`? – Darshan Jul 17 '22 at 14:12
  • Thanks for your reply @DarShan. As in AppSettings I hold the whole app configuration (and my app is multi-module) I have AppSettings in a module called "Common" which is accessible by every module. I have only one AppSettings class, but I suspect that the class location may have something to do. I tried to put the application class in the application itself (and not in another module), and in that case the error changes (anyway continues and it's related) and it complains about the same (class not found) but in this case about MainActivity (which uses AndroidEntryPoint directive). – Diego Perez Jul 17 '22 at 18:58

0 Answers0