Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ClassNotFoundException with product flavors and Kotlin

I have a project written mostly in Kotlin, but with some java classes. Project is well advanced now, and I wanted to add the possibility of switching between different environments, for which I used flavors:

 productFlavors {
        prod {
            dimension "default"
            buildConfigField 'boolean', 'FABRIC', 'true'
            applicationId = "com.myapp"
        }

        beta {
            dimension "default"
            buildConfigField 'boolean', 'FABRIC', 'true'
            applicationId = "com.myapp.beta"
        }

        dev {
            dimension "default"
            buildConfigField 'boolean', 'FABRIC', 'false'
            applicationId = "com.myapp.dev"
        }

    }

However when I run in a flavor that isn't production (which does not change applicationId) I get a ClassDefNotFoundException for a java class:

Caused by: java.lang.ClassNotFoundException: Didn't find class "com.myapp.beta.ui.view.ScrollBehavior" on path: DexPathList[[zip file "/data/app/com.myapp.beta-1/base.apk"],nativeLibraryDirectories=[/data/app/com.myapp.beta-1/lib/arm64, /system/lib64, /vendor/lib64]]
   at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56)
   at java.lang.ClassLoader.loadClass(ClassLoader.java:380)
   at java.lang.ClassLoader.loadClass(ClassLoader.java:312)
    ... 33 more

I am using Android Studio 3.0 beta 4 with Kotlin plugin version 1.1.3-2.

Build file:

apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt' // Use experimental kapt implementation

repositories {
    mavenCentral()
    maven {
        url "http://dl.bintray.com/ttymsd/maven"
    }
    maven { url 'https://jitpack.io' }
}
android {
    compileSdkVersion rootProject.ext.compileSdkVersion
    buildToolsVersion rootProject.ext.buildToolsVersion

    defaultConfig {
        applicationId "com.myapp"

        minSdkVersion rootProject.ext.minSdkVersion
        targetSdkVersion rootProject.ext.targetSdkVersion

        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        vectorDrawables.useSupportLibrary = true
    }

    sourceSets {
        main.java.srcDirs += 'src/main/java'
    }


    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

    flavorDimensions "default"
    productFlavors {
        prod {
            dimension "default"
            buildConfigField 'boolean', 'FABRIC', 'true'
            applicationId = "com.myapp"
        }

        beta {
            dimension "default"
            buildConfigField 'boolean', 'FABRIC', 'true'
            applicationId = "com.myapp.beta"
        }

        dev {
            dimension "default"
            buildConfigField 'boolean', 'FABRIC', 'false'
            applicationId = "com.myapp.dev"
        }

    }


    dataBinding {
        enabled = true
    }

    dependencies {
        (...)
    }
}

Manifest:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.myapp">

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


    <application
        android:name=".MyApp"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/MyTheme">


        <activity
            android:name=".ui.dashboard.DashboardListActivity"
            android:launchMode="singleTop"
            android:configChanges="orientation|keyboardHidden|screenSize">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>

                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>


    </application>

</manifest>

Relevant part in the code:

<android.support.design.widget.AppBarLayout
            android:id="@+id/appbar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@color/colorPrimary"
            app:layout_behavior=".ui.view.ScrollBehavior">
like image 391
Gabriel Sanmartin Avatar asked Sep 06 '17 07:09

Gabriel Sanmartin


1 Answers

You're defining your behavior as

app:layout_behavior=".ui.view.ScrollBehavior"

which is a relative definition. In this case relative to the app package.

So the name actually used is context.getPackageName() + name and thus the application id you defined is used as prefix.

To load the correct behavior you have to define it as a fully qualified name

app:layout_behavior="com.myapp.ui.view.ScrollBehavior"

Also you could use string resources here.

like image 108
tynn Avatar answered Nov 11 '22 06:11

tynn